d3.js化工管条形图

Posted

技术标签:

【中文标题】d3.js化工管条形图【英文标题】:d3.js chemical tube bar chart 【发布时间】:2017-09-10 23:23:54 【问题描述】:

我对创建这种液体条形图很感兴趣。如图所示,指针/虚线标记拉到一边。

4 月 22 日 - 处理动态数据的最新代码 http://jsfiddle.net/NYEaX/1855/


最新条形图代码 http://jsfiddle.net/NYEaX/1827/

最新清理的水波代码 http://jsfiddle.net/Qh9X5/10331/


//我想去掉这个水波代码 http://jsfiddle.net/Qh9X5/10091/

//进度图 http://jsfiddle.net/NYEaX/1740/


此条形图的最新基本代码。 http://jsfiddle.net/NYEaX/1822/

var $this = $("#checmicalbars");


var data = [
  "label": "Rendering",
  "value": 90,      
  "startcolor": "#c3da54",
  "endcolor": "#c1e500"
,

  "label": "Character Design",
  "value": 95,      
  "startcolor": "#e94adc",
  "endcolor": "#aae3dd"
,

  "label": "Sketching",
  "value": 80,      
  "startcolor": "#c3da54",
  "endcolor": "#fa5283"
,

  "label": "Story Boarding",
  "value": 90,      
  "startcolor": "#e94adc",
  "endcolor": "#f83b03"
,

  "label": "Drawing",
  "value": 82,      
  "startcolor": "#c3da54",
  "endcolor": "#f88504"
,

  "label": "Painting",
  "value": 90,      
  "startcolor": "#e94adc",
  "endcolor": "#f7d200"
];


var h = 150;
var w = 300;

    var options = 
  minlimit: 0,
  maxlimit: 100



// setup scales
var x = d3.scale.ordinal()
  .rangeRoundBands([0, w], .1);

var y = d3.scale.linear()
  .range([h, 0]);

var xAxis = d3.svg.axis()
  .scale(this.x)
  .orient("bottom");

var yAxis = d3.svg.axis()
  .scale(this.y)
  .orient("left");
// setup scales


// chart container
var progresschart = d3.select($this[0]).append("svg")
  .attr("width", w)
  .attr("height", h)
  .append("g")
  .attr("transform", "translate(0,5)");

var barrectsholder = progresschart.append("g")
  .attr("class", "chart")
  .attr("transform", "translate(15,0)");
// chart container


y.domain([options["minlimit"], options["maxlimit"]]);


//__ bars
var bar = barrectsholder.selectAll("rect")
  .data(data);

//__ enter
bar.enter()
  .append("rect")
  .attr("class", "bar")
  .attr("y", h);

//__ update   
bar
  .attr("y", h)
  .attr("height", 0)
  .style("fill", function(d)
    return d.startcolor;
  )
  .transition()
  .duration(2500)
  .style("fill", function(d)
    return d.endcolor;
  )
  .attr("width", 20)
  .attr("x", function(d, i) 
    return 30 * i;
  )
  .attr("y", function(d) 
    return y(d.value);
  )
  .attr("height", function(d) 
    return h - y(d.value);
  )

//__ exit
bar.exit()
  .transition()
  .duration(250)
  .attr("y", 0)
  .attr("height", 0)
  .remove();
//__ bars

【问题讨论】:

我已经添加了标签 - jsfiddle.net/NYEaX/1825 --添加了虚线-但努力使垂直线匹配--jsfiddle.net/NYEaX/1826 设法解决了第二行 - 热衷于合并水效果 - 一种简化算法以实现集成的方法? jsfiddle.net/NYEaX/1827——水代码——jsfiddle.net/Qh9X5/10091 --我已经开始剥离这个波形代码了--jsfiddle.net/Qh9X5/10290 老兄,说真的,所有这些小提琴都没有帮助!您需要将所有这些外部信息浓缩到您的问题中,并明确说明您在问什么。 【参考方案1】:

我已将这两个图表合并在一起 - 但如果水代码是单独的 svg 则正确翻译 - 最好清理/审查此代码。还要确保指针/标签调整/适应更多/更少的数据集。

最新的jsfiddle http://jsfiddle.net/NYEaX/1843/

    var $this = $("#checmicalbars");


    var data = [
      "label": "Rendering",
      "value": 90,      
      "startcolor": "#c3da54",
      "endcolor": "#c1e500"
    ,
    
      "label": "Character Design",
      "value": 95,      
      "startcolor": "#e94adc",
      "endcolor": "#aae3dd"
    ,
    
      "label": "Sketching",
      "value": 80,      
      "startcolor": "#c3da54",
      "endcolor": "#fa5283"
    ,
    
      "label": "Story Boarding",
      "value": 90,      
      "startcolor": "#e94adc",
      "endcolor": "#f83b03"
    ,
    
      "label": "Drawing",
      "value": 82,      
      "startcolor": "#c3da54",
      "endcolor": "#f88504"
    ,
    
      "label": "Painting",
      "value": 90,      
      "startcolor": "#e94adc",
      "endcolor": "#f7d200"
    ];


    var h = 450;
    var w = 400;

    var barHeight = 150;
    var barWidth = 180;

        var options = 
      minlimit: 0,
      maxlimit: 100
    


    // setup scales
    var x = d3.scale.ordinal()
      .rangeRoundBands([0, barWidth], .1);

    var y = d3.scale.linear()
      .range([barHeight, 0]);

    var xAxis = d3.svg.axis()
      .scale(this.x)
      .orient("bottom");

    var yAxis = d3.svg.axis()
      .scale(this.y)
      .orient("left");
    // setup scales


    // chart container
    var progresschart = d3.select($this[0]).append("svg")
      .attr("width", w)
      .attr("height", h)
      .append("g")
      .attr("transform", "translate(0,5)");

    var barrectsholder = progresschart.append("g")
      .attr("class", "barrectsholder")
      .attr("transform", "translate(15,0)");

        var labelsholder = progresschart.append("g")
      .attr("class", "labelsholder")
      .attr("transform", "translate(10,"+(barHeight+ 20)+")");      

      var lineholder = progresschart.append("g")
      .attr("class", "lineholder")
      .attr("transform", "translate(25,"+(barHeight+ 15)+")");
    // chart container


    y.domain([options["minlimit"], options["maxlimit"]]);





/*
  var gauge = barrectsholder
    .append("g")
    .attr("width", config.w)
    .attr("height", config.h)
    .append("g");

  liquidBar(gauge, config);
*/

var bar = barrectsholder.selectAll("svg")
      .data(data);

 bar.enter()
       .append("svg")
       .attr("class", function(d, i) 
        return "bar"+i;
         )
      .attr("width", 20)
      .attr("x", function(d, i) 
        return 30 * i;
      )
      .attr("y", function(d) 
        return y(d.value);
      )
      .attr("height", function(d) 
        return barHeight - y(d.value);
      )


$.each(data, function( index, value ) 
  //alert( index + ": " + value );


  var config = 
    w: 20,
    h: barHeight,
    value: value.value,
    amplitude: 0.02, // The wave height as a percentage of the radius of the wave circle.
    countPerWidth: 1, // The number of full waves per width of the wave circle.
    riseTime: 1000, // The amount of time in milliseconds for the wave to rise from 0 to it's final height.
    animateTime: 1000, // The amount of time in milliseconds for a full wave to enter the wave circle.
    rise: true, // Control if the wave should rise from 0 to it's full height, or start at it's full height. 
    colorTransition: 1000,
    colorBefore: value.startcolor, // The color before of the fill wave.
    colorAfter: value.endcolor, // The color after of the fill wave.
    offset: 0 // The amount to initially offset the wave. 0 = no offset. 1 = offset of one full wave.
  ;

  var gauge = barrectsholder.selectAll("svg.bar"+index)
   liquidBar(gauge, config);

);      


/*
    //__ bars
    var bar = barrectsholder.selectAll("rect")
      .data(data);

    //__ enter
    bar.enter()
      .append("rect")
      .attr("class", "bar")
      .attr("y", barHeight);

    //__ update   
    bar
      .attr("y", barHeight)
      .attr("height", 0)
      .style("fill", function(d)
        return d.startcolor;
      )
      .transition()
      .duration(2500)
      .style("fill", function(d)
        return d.endcolor;
      )
      .attr("width", 20)
      .attr("x", function(d, i) 
        return 30 * i;
      )
      .attr("y", function(d) 
        return y(d.value);
      )
      .attr("height", function(d) 
        return barHeight - y(d.value);
      )

    //__ exit
    bar.exit()
      .transition()
      .duration(250)
      .attr("y", 0)
      .attr("height", 0)
      .remove();
    //__ bars

*/


    //__ labels
    var labels = labelsholder.selectAll("text")
      .data(data);

    labels.enter()
      .append("text")
      .attr("class", "barlabels")
      .attr("x", 200)
      .attr("y", function(d, i) 
        return 20 * i;
      )  
      .text(function(d) 
        return d.label; 
      )


 var lines = lineholder.selectAll("text")
      .data(data);

  lines.enter()
    .append("line")// attach a line
    .style("stroke-dasharray", ("3, 3"))    
    .style("stroke", "black")// colour the line
    .attr("x1", function(d, i) 
      return barWidth-(30 * (i+1));
    )//x pos of the 1st end of the line
    .attr("y1", function(d, i) 
      return 20 * i;
    )//y pos of the 1st end of the line
    .attr("x2", function(d, i) 
      return barWidth;
    )//x pos of the 2nd end of the line
    .attr("y2", function(d, i) 
      return 20 * i;
    );//y pos of the 2nd end of the line


    var lineHeights = 100;

  lines.enter()
    .append("line")// attach a line
    .style("stroke-dasharray", ("3, 3"))    
    .style("stroke", "black")// colour the line
    .attr("x1", function(d, i) 
      return 30 * i;
    )//x pos of the 1st end of the line
    .attr("y1", function(d, i) 
      return lineHeights - (20 * i);
    )//y pos of the 1st end of the line
    .attr("x2", function(d, i) 
      return 30 * i;
    )//x pos of the 2nd end of the line
    .attr("y2", function(d, i) 
      return -15;
    );//y pos of the 2nd end of the line









  function liquidBar(gauge, config) 

    var fillPercent = Math.max(0, Math.min(100, config.value)) / 100;

    var waveHeightScale = d3.scale.linear()
      .range([0, config.amplitude, 0])
      .domain([0, 50, 100]);

    var waveHeight = (config.h / 2) * waveHeightScale(fillPercent * 100);
    var waveLength = config.w / config.countPerWidth;
    var waveClipCount = 1 + config.countPerWidth;
    var waveClipWidth = waveLength * waveClipCount;

    // Data for building the clip wave area.
    var data = [];
    for (var i = 0; i <= 40 * waveClipCount; i++) 
      data.push(
        x: i / (40 * waveClipCount),
        y: (i / (40))
      );
    


    // Scales for controlling the size of the clipping path.
    var waveScaleX = d3.scale.linear().range([0, waveClipWidth]).domain([0, 1]);
    var waveScaleY = d3.scale.linear().range([0, waveHeight]).domain([0, 1]);

    // Scales for controlling the position of the clipping path.
    var waveRiseScale = d3.scale.linear()
      // The clipping area size is the height of the fill circle + the wave height, so we position the clip wave
      // such that the it will overlap the fill circle at all when at 0%, and will totally cover the fill
      // circle at 100%.
      .range([(config.h + waveHeight), (waveHeight)])
      .domain([0, 1]);
    var waveAnimateScale = d3.scale.linear()
      .range([0, waveClipWidth - config.w]) // Push the clip area one full wave then snap back.
      .domain([0, 1]);


    // Center the gauge within the parent SVG.
    var gaugeGroup = gauge.append("g")
      .attr("class", "gaugeGroup")
      .attr("transform", "translate(0,0)");


    var randomId = Math.floor(Math.random() * 26) + Date.now();

    // The clipping wave area.
    var clipArea = d3.svg.area()
      .x(function(d) 
        return waveScaleX(d.x);
      )
      .y0(function(d) 
        return waveScaleY(Math.sin(Math.PI * 2 * config.offset * -1 + Math.PI * 2 * (1 - config.countPerWidth) + d.y * 2 * Math.PI));
      )
      .y1(function(d) 
        return (config.h + waveHeight);
      );

    var waveGroup = gaugeGroup.append("defs")
      .append("clipPath")
      .attr("id", "clipWave" + randomId);

    var wave = waveGroup.append("path")
      .datum(data)
      .attr("d", clipArea)
      .attr("T", 0);

    // The inner circle with the clipping wave attached.
    var fillGroup = gaugeGroup.append("g")
      .attr("clip-path", "url(#clipWave" + randomId + ")");

    fillGroup.append("rect")
      .attr("x", 0)
      .attr("y", 0)
      .attr("width", config.w)
      .attr("height", config.h)
      .style("fill", config.colorBefore)
      .transition()
      .duration(config.colorTransition)
      .style("fill", config.colorAfter);


    // Make the wave rise. wave and waveGroup are separate so that horizontal and vertical movement can be controlled independently.
    var waveGroupXPosition = config.w - waveClipWidth;
    if (config.rise) 
      waveGroup.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(0) + ')')
        .transition()
        .duration(config.riseTime)
        .attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(fillPercent) + ')')
        .each("start", function() 
          wave.attr('transform', 'translate(1,0)');
        ); // This transform is necessary to get the clip wave positioned correctly when waveRise=true and waveAnimate=false. The wave will not position correctly without this, but it's not clear why this is actually necessary.
     else 
      waveGroup.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(fillPercent) + ')');
    


        animateWave();

    function animateWave() 
      wave.attr('transform', 'translate(' + waveAnimateScale(wave.attr('T')) + ',0)');
      wave.transition()
        .duration(config.animateTime * (1 - wave.attr('T')))
        .ease('linear')
        .attr('transform', 'translate(' + waveAnimateScale(1) + ',0)')
        .attr('T', 1)
        .each('end', function() 
          wave.attr('T', 0);
          animateWave(config.animateTime);
        );
    

  

【讨论】:

我已经尝试整理图表并提供上面的值标签 - 热衷于清理此图表 - 使其更多地用于处理动态/不同的数据集 - 这也是最好的方法为每个条创建背景 -- jsfiddle.net/NYEaX/1842 jsfiddle.net/NYEaX/1855 - 动态修复标签,使其贴紧到底部 这是一个与此图表相关的问题——***.com/questions/43507667/…

以上是关于d3.js化工管条形图的主要内容,如果未能解决你的问题,请参考以下文章

无需使用d3.js重新渲染数据的无限滚动条形图[关闭]

html D3byEX 4.10:带边距和轴的条形图(适用于D3.js v4)

D3.js:条形图中的条形,刻度未正确建模数据

使用 D3.js 将误差线添加到分组条形图中

结合d3.js和backbone.js

在 D3.js 中创建带有序数刻度的文本标记 x 轴