如何使用D3 js创建分组的条形可刷图表

时间:2018-08-26 16:48:01

标签: javascript d3.js

我正在创建一个可刷写的条形图,在Y轴上,我需要将具有可刷写内容的图表分组,每当我移动画笔时,该图就不会刷新。 使用以下代码创建附加栏,

 var bar2 = bar.enter().append("rect")
      .attr("class", "bar2")
      .attr("id","lesser")
      .style("fill", "#ff7f0e")
      .attr("y", function(d,i) { return main_yScale(d.country); })
      .attr("height", main_yScale.rangeBand()/2)
      .attr("x", 0)
      .transition().duration(50)
      .attr("width", function(d) { return main_xScale(d.result); });

我在http://jsfiddle.net/mouneshp777/7xp10awb/1/中尝试过 我无法解决该问题。

预先感谢

1 个答案:

答案 0 :(得分:1)

主要问题是您使用联接模式(selectAll("abc").data(mylist).enter())的方式。再次阅读文档以查看详细信息。

  • 为什么不使用变焦时创建变焦。我已将其从示例中删除
  • 有关工具提示的所有内容均已评论
  • 不要在每次笔刷移动时为X计算一个新的域,它会给人留下这样的印象,因为条形会改变大小,因此值会改变。
  • 请勿使用相同的idgreater / lesser)定义多个元素。使用课程。
  • 使用属性{strong>或使用fill定义style,但不能同时使用两者,并且使用不同的颜色会使确定您想要/将要使用的颜色更加困难。
  • 为什么要设置宽度动画-50ms太短了,没人会注意到
  • scroll()的用途是什么?
  • 也许是将图表移植到d3v5的想法

var data = [], svg, defs,gBrush, brush, main_xScale, mini_xScale, main_yScale,
      mini_yScale,main_yZoom, main_xAxis, main_yAxis, mini_width, textScale;

init();

function init() {

    for (var i = 1; i < 30; i++) {
      var my_object = {};
      my_object.key = i;
      my_object.country = "Label"+i;
      my_object.gtLabel = "greater";
      my_object.value   = Math.floor(Math.random() * 600);
      my_object.ltLabel = "Lesser";
      my_object.result  = Math.floor(Math.random() * 300);
      data.push(my_object);
    }

    // var zoomer = d3.behavior.zoom()
    //     .on("zoom", null);

    var main_margin = {top: 10, right: 10, bottom: 30, left: 100},
        main_width = 450 - main_margin.left - main_margin.right,
        main_height = 250 - main_margin.top - main_margin.bottom;

    var mini_margin = {top: 10, right: 10, bottom: 30, left: 10},
        mini_height = 250 - mini_margin.top - mini_margin.bottom;
    mini_width = 100 - mini_margin.left - mini_margin.right;

    svg = d3.select("body").append("svg")
        .attr("class", "svgWrapper")
        .attr("width", main_width + main_margin.left + main_margin.right + mini_width + mini_margin.left + mini_margin.right)
        .attr("height", main_height + main_margin.top + main_margin.bottom);

        // .call(zoomer)
        // .on("wheel.zoom", scroll)
        // .on("mousedown.zoom", null)
        // .on("touchstart.zoom", null)
        // .on("touchmove.zoom", null)
        // .on("touchend.zoom", null);

    var mainGroup = svg.append("g")
        .attr("class","mainGroupWrapper")
        .attr("transform","translate(180,10)")
        .append("g")
        .attr("clip-path", "url(#clip)")
        .style("clip-path", "url(#clip)")
        .attr("class","mainGroup");

    var miniGroup = svg.append("g")
        .attr("class","miniGroup")
        .attr("transform","translate(135,10)");

    var brushGroup = svg.append("g")
        .attr("class","brushGroup")
        .attr("transform","translate(135,10)");

    main_xScale = d3.scale.linear().range([0, main_width]);
    mini_xScale = d3.scale.linear().range([0, mini_width]);

    main_yScale = d3.scale.ordinal().rangeBands([0, main_height], 0.4, 0);
    mini_yScale = d3.scale.ordinal().rangeBands([0, mini_height], 0.4, 0);

    main_yZoom = d3.scale.linear()
        .range([0, main_height])
        .domain([0, main_height]);

    main_xAxis = d3.svg.axis()
      .scale(main_xScale)
      .orient("bottom")
      .tickFormat(d3.format(".2s"));

    d3.select(".mainGroupWrapper")
        .append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(" + 0 + "," + (main_height + 5) + ")");

    svg.append("text") 
        .attr("transform", "translate(" + (main_width / 2) + " ," + (main_height + (main_margin.bottom -60) ) +")")
        .attr("dy", ".71em")
        .attr("class", "x axis")
        .attr("stroke-width",1)
        .style("font-size","15px")
        .text("");

    main_yAxis = d3.svg.axis()
      .scale(main_yScale)
      .orient("left").tickSize(5);

    mainGroup.append("g")
        .attr("class", "y axis")
        .attr("transform", "translate(-48,0)");

    main_xScale.domain([0, d3.max(data, function(d) { return d.value; })]);
    mini_xScale.domain([0, d3.max(data, function(d) { return d.value; })]);
    main_yScale.domain(data.map(function(d) { return d.country; }));
    mini_yScale.domain(data.map(function(d) { return d.country; }));

    d3.select(".mainGroup").select(".y.axis").call(main_yAxis);

    textScale = d3.scale.linear()
      .domain([25,50])
      .range([12,6])
      .clamp(true);

    var brushExtent = 15;// Math.max( 1, Math.min( 20, Math.round(data.length*0.2)));

    brush = d3.svg.brush()
        .y(mini_yScale)
        .extent([mini_yScale(data[0].country), mini_yScale(data[brushExtent].country)])
        .on("brush", brushmove);

    gBrush = d3.select(".brushGroup").append("g")
      .attr("class", "brush")
      .call(brush);
    
    gBrush.selectAll(".resize")
      .append("line")
      .attr("x2", 40);

    gBrush.selectAll("rect")
      .attr("width", 40);

    gBrush.select(".background")
      .on("mousedown.brush", brushcenter)
      .on("touchstart.brush", brushcenter);

    defs = svg.append("defs")

    defs.append("clipPath")
      .attr("id", "clip")
      .append("rect")
      .attr("x", -main_margin.left)
      .attr("width", main_width + main_margin.left)
      .attr("height", main_height);

    var mini_bar = d3.select(".miniGroup").selectAll(".bar")
      .data(data, function(d) { return d.key; });

    mini_bar
      .attr("width", function(d) { return (mini_xScale(d.value)/2.2); })
      .attr("y", function(d,i) { return mini_yScale(d.country); })
      .attr("height", mini_yScale.rangeBand());

    mini_bar.enter().append("rect")
      .attr("class", "bar")
      .attr("x", 0)
      .attr("width", function(d) { return mini_xScale(d.value/2.2); })
      .attr("y", function(d,i) { return mini_yScale(d.country); })
      .attr("height", mini_yScale.rangeBand())
      .style("fill", "url(#gradient-rainbow-mini)");

    mini_bar.exit()
      .remove();

    gBrush.call(brush.event);
}

function update() {

    // var divTooltip = svg.append("div").attr("class", "toolTip");

    if (d3.select(".mainGroup").select(".bar2.greater").empty()) {
        var bar = d3.select(".mainGroup").selectAll(null)
          .data(data, function(d) { return d.key; });
        bar.enter().append("rect")
           .attr("class", "bar2 greater")
           .attr("fill", "#1f77b4")
           .attr("x", 0);

        bar.enter().append("rect")
           .attr("class", "bar2 lesser")
           .attr("fill", "#ff7f0e")
           .attr("x", 0);
    }

    d3.selectAll(".bar2.greater")
      .attr("y", function(d) { return main_yScale(d.country) + main_yScale.rangeBand()/2; })
      .attr("width", function(d) { return main_xScale(d.value); })
      .attr("height", main_yScale.rangeBand()/2);

    d3.selectAll(".bar2.lesser")
      .attr("y", function(d,i) { return main_yScale(d.country); })
      .attr("width", function(d) { return main_xScale(d.result); })
      .attr("height", main_yScale.rangeBand()/2);


    // bar
    //   .attr("y", function(d,i) { return main_yScale(d.country); })
    //   .attr("height", main_yScale.rangeBand())
    //   .attr("x", 0)
    //   .transition().duration(50)
    //   .attr("width", function(d) { return main_xScale(d.value); });

    // var bar1= bar.enter().append("rect")
    //   .attr("class", "bar2")
    // //   .attr("id","greater")
    // //   .style("fill", "#1f77b4")
    // //   .attr("fill", function(d,i) { return "#000" })
    //   .attr("fill", "#1f77b4")
    //   .attr("y", function(d,i) { return main_yScale(d.country) + main_yScale.rangeBand()/2; })
    //   .attr("height", main_yScale.rangeBand()/2)
    //   .attr("x", 0)
    //   .transition().duration(50)
    //   .attr("width", function(d) { return main_xScale(d.value); });

    // // console.log(bar1);
    // var bar2 = bar.enter().append("rect")
    //   .attr("class", "bar2")
    // //   .attr("id","lesser")
    // //   .style("fill", "#ff7f0e")
    //   .attr("fill", "#ff7f0e")
    //   .attr("y", function(d,i) { return main_yScale(d.country); })
    //   .attr("height", main_yScale.rangeBand()/2)
    //   .attr("x", 0)
    //   .transition().duration(50)
    //   .attr("width", function(d) { return main_xScale(d.result); });

    // console.log(bar2);

    // var dwellTimeSecsEntered = $("#dwellTimeSecs").val();

    // var lessValue = "value";
    // var greaterValues = "result";
    // var tip = d3.tip()
    //   .attr('class', 'd3-tip')
    //   .offset([10, 75])
    //   .html(function(d) {
    //     return "<strong>"+d.country+ " </strong><br>" +
    //       ""+lessValue+" :<span style='color:black'>" + d.result + "</span><br>"+greaterValues+": <span style='color:black'>" + d.value + "</span><br>";
    //     });

    // bar.on('mouseover', tip.show)
    //    .on('mouseout', tip.hide);

    // svg.call(tip);

    // bar.exit()
    //    .remove();
}

function brushmove() {

    var extent = brush.extent();

    var selected = mini_yScale.domain()
      .filter(function(d) { return (extent[0] - mini_yScale.rangeBand() + 1e-2 <= mini_yScale(d)) && (mini_yScale(d) <= extent[1] - 1e-2); }); 

    d3.select(".miniGroup").selectAll(".bar")
      .style("fill", "lightGrey");

    d3.selectAll(".y.axis text")
      .style("font-size", textScale(selected.length));
    var originalRange = main_yZoom.range();
    main_yZoom.domain( extent );

    main_yScale.domain(data.map(function(d) { return d.country; }));
    main_yScale.rangeBands( [ main_yZoom(originalRange[0]), main_yZoom(originalRange[1]) ], 0.4, 0);

    d3.select(".mainGroup")
      .select(".y.axis")
      .call(main_yAxis);

    // keep x-axis at the same scale independet of selected brush range
    // var newMaxXScale = d3.max(data, function(d) { return selected.indexOf(d.country) > -1 ? d.value : 0; });
    // main_xScale.domain([0, newMaxXScale]);

    // can be moved to the init() call
    d3.select(".mainGroupWrapper")
      .select(".x.axis")
      .transition().duration(50)
      .call(main_xAxis);

    update();
}

function brushcenter() {
    var target = d3.event.target,
        extent = brush.extent(),
        size = extent[1] - extent[0],
        range = mini_yScale.range(),
        y0 = d3.min(range) + size / 2,
        y1 = d3.max(range) + mini_yScale.rangeBand() - size / 2,
        center = Math.max( y0, Math.min( y1, d3.mouse(target)[1] ) );

    d3.event.stopPropagation();

    gBrush
        .call(brush.extent([center - size / 2, center + size / 2]))
        .call(brush.event);
}

function scroll() {

    var extent = brush.extent(),
      size = extent[1] - extent[0],
      range = mini_yScale.range(),
      y0 = d3.min(range),
      y1 = d3.max(range) + mini_yScale.rangeBand(),
      dy = d3.event.deltaY,
      topSection;

    if ( extent[0] - dy < y0 ) { topSection = y0; } 
    else if ( extent[1] - dy > y1 ) { topSection = y1 - size; } 
    else { topSection = extent[0] - dy; }

    d3.event.stopPropagation();
    d3.event.preventDefault();

    gBrush
        .call(brush.extent([ topSection, topSection + size ]))
        .call(brush.event);
}
.axis path,
.axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
}
.x.axis path {
    display: block;
}
body {
    font-size: 10px;
    font-family: 'Open Sans', sans-serif;
    font-weight: 400;
    text-align: center;
}
#title {
    font-size: 20px;
    padding-bottom: 10px;
    padding-top: 20px;
    font-weight: 300;
}
#explanation {
    font-size: 12px;
    max-width: 620px;
    margin: 0 auto;
    padding-top: 10px;
    color: #ababab;
    font-weight: 300;
}
.brush .extent {
    fill-opacity: .125;
    shape-rendering: crispEdges;
}
.resize {
    display: inline !important; /* show when empty */
    fill: #7A7A7A;
    fill-opacity: 1;
    stroke: #7A7A7A;
    stroke-width: 2px;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<body>
</body>