D3-Rect

  • 一段时间没有记录博客了,四月份和五月份都很忙,四月份主要忙weex,五月份主要忙wexx+d3.v3.js,这里先稳下如何用d3实现负柱形图,供以后参考。

    基础元素

  • 创建底盘svg

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var width = window.innerWidth;
    var height = width/2;
    var svg = d3.selectAll('body')
    .append('svg')
    .attr({
    width: width,
    height: height
    })
    .style({
    background: "black"
    })
  • 声明元数据,比例尺,坐标轴

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var dataSet = [10,20,30,40,60]
    var xScale = d3.scale.ordinal()
    .domain(dataSet)
    .rangeRoundBands([0,width-margin.right-margin.left])
    var yScale = d3.scale.ordinal()
    .domain(dataSet)
    .rangeRoundBands([height-margin.bottom-margin.top,0])
    var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient('bottom')
    var yAxis = d3.svg.axis()
    .scale(yScale)
    .orient('left')
  • 生成坐标轴

    1
    2
    3
    4
    svg.append('g')
    .call(xAxis)
    svg.append('g')
    .call(yAxis)
  • 因为没有设置合理的位置,Y轴在可见区域之外了,X轴在最顶上了,这都是不是我们期望的,下面做一些改动。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    // 这里额外定义了偏值
    var margin = {
    'top':20,
    'right': 50,
    'bottom': 50,
    'left': 50
    };
    var width = window.innerWidth;
    var height = width/2;
    var svg = d3.selectAll('body')
    .append('svg')
    .attr({
    width: width,
    height: height
    })
    .style({
    background: "#FFF"
    })
    var dataSet = [1,2,3,4,5]
    var xScale = d3.scale.ordinal()
    .domain(dataSet)
    .rangeRoundBands([0,width-margin.right-margin.left])
    var yScale = d3.scale.ordinal()
    .domain(dataSet)
    .rangeRoundBands([height-margin.bottom-margin.top,0])
    var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient('bottom')
    .tickSize(-100,0)
    var yAxis = d3.svg.axis()
    .scale(yScale)
    .orient('left')
    .tickSize(-100,-(width-margin.right-margin.left))

    svg.append('g')
    .attr('transform', 'translate('+(margin.left)+','+(height-margin.bottom)+')')
    .call(xAxis)
    svg.append('g')
    .attr('transform', 'translate('+margin.left+','+margin.top+')')
    .call(yAxis)
  • 以上,我们最简单的打底内容就搞定了,下面尝试添加柱形元素。

    正向柱形

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    svg.selectAll('rect').data(dataSet).enter()
    .append('rect')
    .attr({
    'class': 'rect',
    'x': function(d, i){
    return xScale(d)+margin.left
    },
    'y': function(d, i){
    return yScale(d) + margin.top
    },
    'width': function(d, i){
    return xScale.rangeBand()
    },
    'height': function(d, i){
    return height - margin.top - margin.bottom - yScale(d)
    },
    'fill': function(d){
    return 'red'
    }
    })
  • 这样我们就能渲染正常的柱形图

    负向柱形

  • 负向的要点主要有两点
    • 负刻度以0为基准线
    • 负刻度的高度也要以0对应的值为基准值,最后求绝对值
  • 代码稍做改动就能达到如期效果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    var dataSet = [1,2,-3,4,5]
    var xScale = d3.scale.ordinal()
    .domain(dataSet)
    .rangeRoundBands([0,width-margin.right-margin.left])
    var yScale = d3.scale.linear()
    .domain([d3.min(dataSet,d3.max(dataSet)])
    .range([height-margin.bottom-margin.top,0])
    svg.selectAll('rect').data(dataSet).enter()
    .append('rect')
    .attr({
    'class': 'rect',
    'x': function(d, i){
    return xScale(d)+margin.left
    },
    'y': function(d, i){
    // 要点一,注意这里
    var basePoint = d > -1 ? yScale(d) : yScale(0)
    return basePoint + margin.top
    },
    'width': function(d, i){
    return xScale.rangeBand()
    },
    'height': function(d, i){
    // 要点二,注意这里
    var baseHeight = yScale(0) - yScale(d)
    return d > -1 ? baseHeight : Math.abs(baseHeight)
    },
    'fill': function(d){
    return 'red'
    }
    })
  • 暂时写到这里,后续补充:分组柱形图