【问题标题】:Different color between line and area graph折线图和面积图的颜色不同
【发布时间】:2018-05-08 04:20:29
【问题描述】:

edit image 我正在使用 d3 v4。我在其中创建了面积图和折线图。数据形成是。 图表 => [1,4,5,2.4,6] 线 => [3,3,3,3,3]

现在我的要求是折线图下方,面积图应该有不同的颜色。

如果有任何其他库可以做到这一点,那么也建议。 这是我绘制折线图和面积图的函数。 那么如果 dailyConsValue> targetConsValue 呢? '无颜色' : '显示颜色' dailydate 是年份 [Jan 2017 - dec 2017] => 这是动态的。

下面是我的代码:

function drawGraph(drawData, highlightedData, first, last) {
let margin, width, height, parseDate, xScale, yScale, area, 
dailyConsumption, targetConsumption, svg;
margin = {
  top: 10,
  right: 60,
  bottom: 10,
  left: 60
},
width = document.querySelector('#graph').clientWidth - margin.left - margin.right,
height = document.querySelector('#graph').clientHeight - margin.top - margin.bottom;

parseDate = d3.timeParse('%b %Y');
// x axis
xScale = d3.scaleTime().domain([parseDate(first), parseDate(last)]).range([0, width]);
// y axis
yScale = d3.scaleLinear().domain([-1, 2 + Math.max.apply(this, drawData.map(function(o){return o.dailyConsValue; }))])
.range([height, 0]);

area = d3.area()
.x(function(d) { return xScale(d['dailyDate']); })
.y0(function(d) { return yScale(d['targetConsValue']); })
.y1(function(d) { return yScale(d['dailyConsValue']); });
// define the line
dailyConsumption = d3.line().x(function(d) {return xScale(d['dailyDate']); })
 .y(function(d) {return yScale(d['dailyConsValue']); });

targetConsumption = d3.line().x(function(d) {return xScale(d['dailyDate']); })
    .y(function(d) {return yScale(d['targetConsValue']); });

svg = d3.select('#graph').append('svg')
    .attr('width', width + margin.left + margin.right)
    .attr('height', height + margin.top + margin.bottom)
  .append('g')
    .attr('transform',
          'translate(' + margin.left + ',' + margin.top + ')');

 // add axis
 svg.append('g')
 .attr('transform', 'translate(0,0)').attr('class', 'Xaxis')
 .call(d3.axisTop(xScale).ticks(drawData.length).tickSize(-innerHeight).tickFormat(d3.timeFormat('%b %Y')));
 svg.append('g').attr('class', 'Yaxis')
 .call(d3.axisLeft(yScale).tickSize(0));

 // Prepare data
 drawData.forEach(function( d ) {
   d['dailyDate'] = parseDate( d['dailyDate'] );
   d['targetConsValue'] = d['targetConsValue'];
   d['dailyConsValue'] = d['dailyConsValue'];
 } );

 highlightedData.forEach(function( d ) {
   d['dailyDate'] = parseDate( d['dailyDate'] );
   d['dailyConsValue'] = d['dailyConsValue'];
   d['active'] = d['active'];
 } );

 // add the area
 svg.append('path').data([drawData]).attr('class', 'area')
 .attr('d', area)
  .transition().duration(2500).attrTween( 'd', this.tween( drawData, area ) );

 // add data for first line
 svg.append('path')
 .data([drawData])
 .attr('class', 'daily').attr('d', targetConsumption).transition()
 .duration(2500).delay(1500 / 2).attrTween( 'd', this.tween( drawData, targetConsumption ) );

// add data for futureConsumption
 svg.append('path')
 .data([drawData])
 .attr('class', 'target').attr('data-legend', 'CST')
 .attr('d', dailyConsumption);

 createLengends(drawData);
 drawCircle(drawData, '10', '#037DA6');
 drawCircle(drawData, '5', '#003A54');


/**
 * legends start
 * @param datalegendsData
 */
function createLengends(datalegendsData) {
  let legend;
  legend = svg.selectAll('.legend').data([datalegendsData])
    .enter().append('g').attr('class', 'legend')
    .attr('transform', function(d, i) { return 'translate(0,' + i * 20 + ')'; });
  // making a line for legend
  legend.append('line')
      .attr('x1', width - 335).attr('x2', width - 305).attr('y1', height - 1)
      .attr('y2', height - 1).style('stroke', '5,5').style('stroke', '#4682B4');

  legend.append('text').attr('x', width - 300).attr('y', height - 1)
      .attr('dy', '.35em').style('text-anchor', 'start').text('IST Verbrauch WOB')
      .style('fill', '#666').style('font-weight', 'normal');

  legend.append('line').attr('x1', width - 130).attr('x2', width - 100)
      .attr('y1', height - 1).attr('y2', height - 1).style('stroke-dasharray', '5,5')
      .style('stroke', '#003A54');

  legend.append('text').attr('x', width - 96).attr('y', height - 1).attr('dy', '.35em')
      .style('text-anchor', 'start').text('CST Sollwert').style('fill', '#666')
      .style('font-weight', 'normal');
}
// legends end

/**
 * highlighted data points start
 * @param data
 * @param r
 * @param color
 */
function drawCircle(data, r, color) {
  let tooltip;
  tooltip = d3.select('#graph').append('div')
  .attr('class', 'tooltip').style('display', 'none');
  svg.selectAll('.dot').data(data).enter().append('circle') // Uses the enter().append() method
  .attr('class', 'circle_' + r).attr('cx', function(d) { return xScale(d['dailyDate']); })
  .attr('cy', function(d) {return yScale(d['dailyConsValue']); }).attr('r', r).attr('fill', color)
    .on( 'mouseover', function( d) {
      let arr, date;
      d3.select( this ).classed('circle circle__highlighted', true);
      d['active'] = true;
      tooltip.transition().duration(200).style('display', 'block');
      arr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
      date = arr[d['dailyDate'].getMonth()] + ', ' + d['dailyDate'].getFullYear();
      tooltip.html('Month ' + date + '<br/> Consumption- ' + d['dailyConsValue'] + ' unit')
      .style('left', (parseInt(this.getAttribute('cx'), 10) + 70) + 'px').style('top', (this.getAttribute('cy')) + 'px');
      /*tooltip.html('Month ' + date + '<br/> Consumption- ' + d['dailyConsValue'] + ' unit')
        .style('left', (d3.event.offsetX + 20) + 'px').style('top', (d3.event.offsetY - 28) + 'px');*/
  } ).on( 'mouseout', function( d ) {
        d3.selectAll('.circle').classed('circle', true).classed('circle__highlighted', false);
        d['active'] = false;
        tooltip.transition().duration(500).style('display', 'none');
  } );
}
// highlighted data points end
}

提前致谢。

【问题讨论】:

  • 你能发布更多代码吗?颜色变化绝对是可能的。
  • 为线条和区域分配一个 ID 或类,并使用 css 或使用“.style('fill','#cc0000')”使用“stroke”或“fill”
  • 我给了它,但它填满了整个区域图。这是我不想要的。
  • 那你想怎么给你的面积图上色呢?
  • 当我填写数据时,我必须检查是否我的 dailyConsValue

标签: d3.js


【解决方案1】:

在您的style fill 中,只需创建一个函数并比较两个值并根据条件返回颜色,如下所示:

svg.append('path')
   .data([drawData]).attr('class', 'area')
   .attr('d', area)
   .style('fill', function(d){
      for (i in d) {
        if (d[i]['dailyConsValue'] < d[i]['targetConsValue']) {
           return "green"
        } else {
           return "blue"
        }
   }
   })
   .transition().duration(2500)
   .attrTween( 'd', this.tween( drawData, area ) );

这将仅基于数据的最后一个值。如果您想根据您的情况在图表的每个点使用不同的颜色,据我所知,您必须创建一个带有多个颜色停止(动态)的linearGradient

现在要创建一个linearGradient,我使用 d3 创建了一个线性刻度来计算色标的偏移量并根据您的条件分配颜色。要动态创建linearGradient,请参阅此fiddle

https://jsfiddle.net/aditya_kk29/gsy5dt8h/

【讨论】:

  • 它不起作用,因为 d 将是 [{dailyConsValue: 2,targetConsValue:3 }, {dailyConsValue: 4,targetConsValue:3} , {dailyConsValue: 2.5,targetConsValue:3}] 并返回数组颜色
  • @Himani 我无法理解您想要实现的目标。你能张贴一张你想要你的面积图是什么样子的照片吗?
  • 嘿 Aditya,这是链接,我还附上了图片。 i.stack.imgur.com/JsGc1.png
  • @Himani 这实际上是一个渐变,但带有硬色标;意思是渐变中没有颜色的渐变。您可以使用一种纯色或动态生成色标(对于初学者来说并不容易),因为您的面积图只是一个路径元素。我建议您阅读一些有关线性渐变的内容。
  • @Himani 请看一下上面的小提琴并尝试弄清楚它是如何工作的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-01
相关资源
最近更新 更多