繁体   English   中英

带有双向图表的 D3 v4 图表

[英]D3 v4 chart with Bi directional chart

在此处输入图片说明

如何使用 D3 创建此图表? 任何帮助都将有助于对高图表进行全面尝试,但不能完全帮助更多点击事件在添加此向下钻取事件时不起作用,但在单击条形或 y 轴标签时不起作用。

const data = [
  { "name": 'IT', "value": 20, "negativeValue": -80 },
  { "name": 'Capital Invest', "value": 30, "negativeValue": -70 },
  { "name": 'Infrastructure', "value": 40, "negativeValue": -60 }
];
Highcharts.setOptions({
    lang: {
        drillUpText: `◁ Back to {series.description}`,
    },
});

Highcharts.chart({
  chart: {
    type: 'bar',
    renderTo: 'alignmentChart',
    height: 530,
    marginRight: 20,
    backgroundColor: 'transparent',
    events: {
      drilldown(e: any) {
        if (e.seriesOptions.fits) {
          linesPositive = e.seriesOptions.line;
        } else {
          lineNegative = e.seriesOptions.line;
        }
        labels = !!e.seriesOptions && e.seriesOptions.data.map(a => a.name);
      },
      drillup(e: any) {
        if (e.seriesOptions.fits) {
          linesPositive = e.seriesOptions.line;
        } else {
          lineNegative = e.seriesOptions.line;
        }
        labels = !!e.seriesOptions && e.seriesOptions.data.map(a => a.name);
      },
    },
  },
  title: {
    text: '',
  },
  colors: ['#f7a704', '#458dde'],
  // tooltip: this.getTooltip(this),
  xAxis: {
    reversed: false,
    tickPositions: Array.from(Array(this.multi.positive.length).keys()),
    labels: {
      useHTML: true,
      formatter() {
        return `<span title="${labels[this.value]}">${labels[this.value]}</span>`;
      },
      style: {
        color: '#000000',
      },
      step: 1,
    },
    lineWidth: 0,
    tickWidth: 0,
  },
  yAxis: {
    title: {
      text: null,
    },
    max: 100,
    min: -100,
    plotLines: [{
      color: '#e5e5e5',
      value: 0,
      width: 1,
      zIndex: 20,
    }],
    lineWidth: 1,
    gridLineWidth: 0,
    tickWidth: 1,
    // offset: 100,
    labels: {
      y: 30,
      align: 'center',
    },
  },

  plotOptions: {
    bar: {
      pointWidth: 12,
    },
    series: {
      stacking: 'normal',
      dataLabels: {
        enabled: true,
        color: '#6b6b6b',
        style: {
          fontSize: '12px',
          fontFamily: 'Proxima Nova'
        },
        formatter() {
          return '';
        },
        inside: false,
      },
    },
  },

  series: [{
    name: 'Fits Role',
    description: 'Subfunctions',
    data: this.multi.positive,
    type: undefined
  }, {
    name: 'Not Fit Role',
    description: 'Subfunctions',
    data: this.multi.negative,
    type: undefined
  }],
  drilldown: {
    allowPointDrilldown: false,
    activeAxisLabelStyle: {
      fontSize: '12px',
      fontWeight: 'bold',
      color: '#007bc7',
      textDecoration: 'none',
    },
    series: this.multi.drilldowns,
  },
  credits: {
    enabled: false,
  },
  legend: {
    enabled: false,
  },
  exporting: {
    enabled: false,
  },
});

我分享的答案相比,我只需要进行很少的更改。 正如我在评论中所说,我为每个项目创建一个g节点,并为每个项目绘制两个rect

然后我更新rect s 以具有相同的数据形状( { name: string, value: number } ),无论它是正数还是负数。 这使我可以对两种类型做完全相同的事情。

 // Now, the data can also be negative const data = [{ "name": 'IT', "value": 20, "negativeValue": -80 }, { "name": 'Capital Invest', "value": 30, "negativeValue": -70 }, { "name": 'Infrastructure', "value": 40, "negativeValue": -60 }]; const width = 600, height = 300, margin = { top: 20, left: 100, right: 40, bottom: 40 }; // Now, we don't use 0 as a minimum, but get it from the data using d3.extent const x = d3.scaleLinear() .domain([-100, 100]) .range([0, width]); const y = d3.scaleBand() .domain(data.map(d => d.name)) .range([height, 0]) .padding(0.1); const svg = d3.select('svg') .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom); const g = svg .append('g') .attr('transform', `translate(${margin.left} ${margin.right})`); // One group per data entry, each holding two bars const barGroups = g .selectAll('.barGroup') .data(data); barGroups.exit().remove(); const newBarGroups = barGroups.enter() .append('g') .attr('class', 'barGroup'); // Append one bar for the positive value, and one for the negative one newBarGroups .append('rect') .attr('class', 'positive') .attr('fill', 'darkgreen'); newBarGroups .append('rect') .attr('class', 'negative') .attr('fill', 'darkred'); const positiveBars = newBarGroups .merge(barGroups) .select('.positive') .datum(d => ({ name: d.name, value: d.value })); const negativeBars = newBarGroups .merge(barGroups) .select('.negative') .datum(d => ({ name: d.name, value: d.negativeValue })); newBarGroups.selectAll('rect') // If a bar is positive it starts at x = 0, and has positive width // If a bar is negative it starts at x < 0 and ends at x = 0 .attr('x', d => d.value > 0 ? x(0) : x(d.value)) .attr('y', d => y(d.name)) // If the bar is positive it ends at x = v, but that means it's x(v) - x(0) wide // If the bar is negative it ends at x = 0, but that means it's x(0) - x(v) wide .attr('width', d => d.value > 0 ? x(d.value) - x(0) : x(0) - x(d.value)) .attr('height', y.bandwidth()) // Let's color the bar based on whether the value is positive or negative g.append('g') .classed('x-axis', true) .attr('transform', `translate(0, ${height})`) .call(d3.axisBottom(x)) g.append('g') .classed('y-axis', true) .attr('transform', `translate(${x(0)}, 0)`) .call(d3.axisLeft(y))
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script> <svg></svg>


或者,您可以在不合并选择的情况下执行此操作,如下所示:

 // Now, the data can also be negative const data = [{ "name": 'IT', "value": 20, "negativeValue": -80 }, { "name": 'Capital Invest', "value": 30, "negativeValue": -70 }, { "name": 'Infrastructure', "value": 40, "negativeValue": -60 }]; const width = 600, height = 300, margin = { top: 20, left: 100, right: 40, bottom: 40 }; // Now, we don't use 0 as a minimum, but get it from the data using d3.extent const x = d3.scaleLinear() .domain([-100, 100]) .range([0, width]); const y = d3.scaleBand() .domain(data.map(d => d.name)) .range([height, 0]) .padding(0.1); const svg = d3.select('svg') .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom); const g = svg .append('g') .attr('transform', `translate(${margin.left} ${margin.right})`); // One group per data entry, each holding two bars const positiveBars = g .selectAll('.positive') .data(data); positiveBars.exit().remove(); positiveBars.enter() .append('rect') .attr('class', 'positive') .attr('fill', 'darkgreen') .merge(positiveBars) .attr('x', x(0)) .attr('y', d => y(d.name)) // The bar is positive. It ends at x = v, but that means it's x(v) - x(0) wide .attr('width', d => x(d.value) - x(0)) .attr('height', y.bandwidth()); const negativeBars = g .selectAll('.negative') .data(data); negativeBars.exit().remove(); negativeBars.enter() .append('rect') .attr('class', 'negative') .attr('fill', 'darkred') .merge(negativeBars) .attr('x', d => x(d.negativeValue)) .attr('y', d => y(d.name)) // The bar is negative. It ends at x = 0, but that means it's x(0) - x(v) wide .attr('width', d => x(0) - x(d.negativeValue)) .attr('height', y.bandwidth()); g.append('g') .classed('x-axis', true) .attr('transform', `translate(0, ${height})`) .call(d3.axisBottom(x)) g.append('g') .classed('y-axis', true) .attr('transform', `translate(${x(0)}, 0)`) .call(d3.axisLeft(y))
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script> <svg></svg>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM