d3.js 化工管柱状图 [英] d3.js chemical tube bar chart

查看:28
本文介绍了d3.js 化工管柱状图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

4 月 22 日 - 处理动态数据的最新代码

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

 var $this = $("#checmicalbars");变量数据 = [{"label": "渲染",价值":90,"startcolor": "#c3da54",结束颜色":#c1e500"},{"label": "角色设计",价值":95,"startcolor": "#e94adc","endcolor": "#aae3dd"},{"label": "草图",价值":80,"startcolor": "#c3da54",结束颜色":#fa5283"},{"label": "故事板",价值":90,"startcolor": "#e94adc",结束颜色":#f83b03"},{"label": "绘图",价值":82,"startcolor": "#c3da54",结束颜色":#f88504"},{"label": "绘画",价值":90,"startcolor": "#e94adc",结束颜色":#f7d200"}];无功h = 450;无功 w = 400;var barHeight = 150;var barWidth = 180;变量选项 = {最小限制:0,最大限制:100}//设置比例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("底部");var yAxis = d3.svg.axis().scale(this.y).orient("左");//设置比例//图表容器var progresschart = d3.select($this[0]).append("svg").attr("宽度", w).attr("高度", h).append("g").attr("transform", "translate(0,5)");var barrectsholder = progresschart.append("g").attr("class", "barrectsholder").attr("transform", "translate(15,0)");var labelholder = 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)+")");//图表容器y.domain([options["minlimit"], options["maxlimit"]]);/*无功量规 = barrectsholder.append("g").attr("宽度", config.w).attr("高度", config.h).append("g");液体条(仪表,配置);*/var bar = barrectsholder.selectAll("svg").数据(数据);栏输入().append("svg").attr("class", function(d, i) {返回 "bar"+i;}).attr("宽度", 20).attr("x", function(d, i) {返回 30 * i;}).attr(y",函数(d){返回 y(d.value);}).attr(高度",函数(d){返回 barHeight - y(d.value);})$.each(data, function( index, value ) {//警报(索引+:"+值);变量配置 = {w: 20,h:条形高度,价值:价值.价值,振幅: 0.02,//波高占波圈半径的百分比.countPerWidth: 1,//波圈每宽度的全波数.riseTime: 1000,//波浪从 0 上升到最终高度的时间量(以毫秒为单位).animateTime: 1000,//全波进入波圈的时间量,以毫秒为单位.rise: true,//控制波浪是从 0 升到它的全高,还是从它的全高开始.颜色过渡:1000,colorBefore: value.startcolor,//填充波之前的颜色.colorAfter: value.endcolor,//填充波形之后的颜色.offset: 0//初始偏移波浪的量.0 = 无偏移.1 = 一个全波的偏移.};var Gauge = barrectsholder.selectAll("svg.bar"+index)液体条(仪表,配置);});/*//__ 条var bar = barrectsholder.selectAll("rect").数据(数据);//__ 进入栏输入().append("rect").attr("class", "bar").attr("y", barHeight);//__ 更新酒吧.attr("y", barHeight).attr("高度", 0).style("填充", 函数(d){返回 d.startcolor;}).过渡().duration(2500).style("填充", 函数(d){返回 d.endcolor;}).attr("宽度", 20).attr("x", function(d, i) {返回 30 * i;}).attr(y",函数(d){返回 y(d.value);}).attr(高度",函数(d){返回 barHeight - y(d.value);})//__ 出口bar.exit().过渡().duration(250).attr("y", 0).attr("高度", 0).消除();//__ 条*///__ 标签var labels = labelsholder.selectAll("text").数据(数据);标签.输入().append("文本").attr("class", "barlabels").attr("x", 200).attr("y", function(d, i) {返回 20 * i;}).text(function(d) {返回 d.label;})var lines = lineholder.selectAll("text").数据(数据);行.输入().append("line")//附加一行.style("stroke-dasharray", ("3, 3")).style("stroke", "black")//给线条上色.attr("x1", function(d, i) {返回 barWidth-(30 * (i+1));})//行首尾的x​​ pos.attr("y1", function(d, i) {返回 20 * i;})//行首尾的y位置.attr("x2", function(d, i) {返回条宽;})//第二行的x pos.attr("y2", function(d, i) {返回 20 * i;});//第二行的y posvar lineHeights = 100;行.输入().append("line")//附加一行.style("stroke-dasharray", ("3, 3")).style("stroke", "black")//给线条上色.attr("x1", function(d, i) {返回 30 * i;})//行首尾的x​​ pos.attr("y1", function(d, i) {返回 lineHeights - (20 * i);})//行首尾的y位置.attr("x2", function(d, i) {返回 30 * i;})//第二行的x pos.attr("y2", function(d, i) {返回-15;});//第二行的y pos功能liquidBar(仪表,配置){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;//用于构建剪切波区域的数据.var 数据 = [];for (var i = 0; i <= 40 * waveClipCount; i++) {数据推送({x: i/(40 * waveClipCount),y: (i/(40))});}//缩放以控制剪切路径的大小.var waveScaleX = d3.scale.linear().range([0, waveClipWidth]).domain([0, 1]);var waveScaleY = d3.scale.linear().range([0, waveHeight]).domain([0, 1]);//缩放以控制剪切路径的位置.var waveRiseScale = d3.scale.linear()//裁剪区域大小是填充圆的高度+波浪高度,所以我们定位裁剪波浪//这样它会在 0% 时与填充圆完全重叠,并将完全覆盖填充//在 100% 处循环..range([(config.h + waveHeight), (waveHeight)]).domain([0, 1]);var waveAnimateScale = d3.scale.linear().range([0, waveClipWidth - config.w])//将剪辑区域推一整波然后弹回..domain([0, 1]);//将仪表置于父 SVG 中.var GaugeGroup = Gauge.append("g").attr("class", "gaugeGroup").attr("transform", "translate(0,0)");var randomId = Math.floor(Math.random() * 26) + Date.now();//剪切波区域.var clipArea = d3.svg.area().x(函数(d){返回 waveScaleX(d.x);}).y0(函数(d){return waveScaleY(Math.sin(Math.PI * 2 * config.offset * -1 + Math.PI * 2 * (1 - config.countPerWidth) + d.y * 2 * Math.PI));}).y1(函数(d){返回(config.h + waveHeight);});var waveGroup = GaugeGroup.append("defs").append("clipPath").attr("id", "clipWave" + randomId);var wave = waveGroup.append("path").数据(数据).attr("d", 剪辑区域).attr("T", 0);//带有剪切波的内圆.var fillGroup = GaugeGroup.append("g").attr("clip-path", "url(#clipWave" + randomId + ")");fillGroup.append("rect").attr("x", 0).attr("y", 0).attr("宽度", config.w).attr("高度", config.h).style("填充", config.colorBefore).过渡().duration(config.colorTransition).style("fill", config.colorAfter);//使波浪上升.wave 和 waveGroup 是分开的,因此可以独立控制水平和垂直移动.var waveGroupXPosition = config.w - waveClipWidth;如果(配置.上升){waveGroup.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(0) + ')').过渡().duration(config.riseTime).attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(fillPercent) + ')').each("开始", function() {wave.attr('transform', 'translate(1,0)');});//当waveRise=true 和waveAnimate=false 时,为了使剪辑波形正确定位,此变换是必要的.没有这个,波浪就不会正确定位,但不清楚为什么这实际上是必要的.} 别的 {waveGroup.attr('transform', 'translate(' + waveGroupXPosition + ',' + waveRiseScale(fillPercent) + ')');}动画波();函数 animateWave() {wave.attr('transform', 'translate(' + waveAnimateScale(wave.attr('T')) + ',0)');wave.transition().duration(config.animateTime * (1 - wave.attr('T'))).ease('线性').attr('transform', 'translate(' + waveAnimateScale(1) + ',0)').attr('T', 1).each('end', function() {wave.attr('T', 0);animateWave(config.animateTime);});}}

I am interested in creating this liquid bar chart of sorts. With the pointers/dotted markers pulling off to the side like shown.

22 April - latest code to work with dynamic data http://jsfiddle.net/NYEaX/1855/


latest bar chart code http://jsfiddle.net/NYEaX/1827/

latest cleaned up water wave code http://jsfiddle.net/Qh9X5/10331/


//I want to strip down this waterwave code http://jsfiddle.net/Qh9X5/10091/

//progress chart http://jsfiddle.net/NYEaX/1740/


latest base code for this bar chart. 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

解决方案

I've merged the two charts together - but the watercode is translated correctly if its a separate svg - be good to get this code cleaned up/reviewed. Also ensuring the pointers/labels adjust/adapt with more/less data sets.

latest 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);
        });
    }

  }

这篇关于d3.js 化工管柱状图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆