基于D3.js的趋势线图表定制:添加轴线、标记点及告警图标
折线图功能增强需求
需求概述
我现有一个折线图表,希望完成以下改造:
- 样式调整
- 创建趋势线
- 添加展示当前时间的轴线及趋势线/圆形标记点
- 在图表顶部生成与图表刻度对齐的图标/告警,并与图表集成
参考示例图



现有实现资源
当前React+D3.js实现代码
import React from 'react' import * as d3 from 'd3' import './LineChart.scss' class LineChart extends React.Component { constructor(props) { super(props) this.myRef = React.createRef() this.state = { data: this.props.data ? this.props.data : [], theme: this.props.theme ? this.props.theme : ['#bde0fe', '#2698f9', '#71bcfd', '#f1f8fe'], } } componentWillReceiveProps(nextProps) { // You don't have to do this check first, but it can help prevent an unneeded render if (nextProps.data !== this.state.data) { //console.log("PROPS HAVE CHANGED FOR CHART"); this.setState({data: nextProps.data}) this.buildChart() } } componentDidMount() { this.buildChart() } buildChart() { var $this = this.myRef.current d3.select($this).selectAll('svg').remove() var data = this.state.data //console.log("DATA", data) var hasLabels = false data.forEach((item, index) => { if (item.id.length > 0) { hasLabels = true } }) var yAxisLabel = this.props.yAxisLabel //console.log("hasLabels", hasLabels) var width = parseInt(this.props.width, 10), height = parseInt(this.props.height, 10) var color = d3.scaleOrdinal().range(this.state.theme) var parseTime = d3.timeParse('%Y%m%d') var margin = { top: 20, right: hasLabels ? 95 : 25, bottom: 30, left: 45, }, w = width - margin.left - margin.right, h = height - margin.top - margin.bottom var x = d3.scaleTime().range([0, w]) var y = d3.scaleLinear().range([h, 0]) var valueline = d3 .line() .curve(d3.curveBasis) .x(function (d) { return x(new Date(d.date)) }) .y(function (d) { return y(d.value) }) //valueline.curve(d3.curveBasis) x.domain([ d3.min(data, function (c) { return d3.min(c.values, function (d) { return new Date(d.date) }) }), d3.max(data, function (c) { return d3.max(c.values, function (d) { return new Date(d.date) }) }), ]) y.domain([ d3.min(data, function (c) { return d3.min(c.values, function (d) { return d.value }) }), d3.max(data, function (c) { return d3.max(c.values, function (d) { return d.value }) }), ]) var svg = d3 .select($this) .append('svg') .attr('width', w + margin.left + margin.right) .attr('height', h + margin.top + margin.bottom) .append('g') .attr('class', 'linechart') .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') var lines = svg.append('g').attr('class', 'lines') var line = lines .selectAll('.line') .data(data) .enter() .append('g') .attr('class', 'line') line .append('path') .attr('d', function (d) { return valueline(d.values) }) .attr('stroke', function (d, i) { return color(i) }) line .append('text') .datum(function (d) { return { id: d.id, value: d.values[d.values.length - 1], } }) .attr('transform', function (d) { return ( 'translate(' + x(new Date(d.value.date)) + ',' + y(d.value.value) + ')' ) }) .attr('x', 3) .attr('dy', '0.35em') .text(function (d) { return d.id }) ////return c.date; var minDate = d3.min(data, function (c) { return d3.min(c.values, function (d) { return d.date }) }) var maxDate = d3.max(data, function (c) { return d3.max(c.values, function (d) { return d.date }) }) //console.log("minDate", minDate); //console.log("maxDate", maxDate); var difference = dateDiffInDays( new Date(minDate.toString()), new Date(maxDate.toString()), ) //console.log(difference + ' days') let tick = d3.timeDay.every(1) if (difference < 1) { tick = d3.timeHour.every(2) } if (difference > 1 && difference < 7) { tick = d3.timeDay.every(1) } if (difference > 7 && difference < 30) { tick = d3.timeWeek.every(1) } if (difference >= 30 && difference < 90) { //console.log("jackpot") tick = d3.timeMonth.every(1) } lines .append('g') .attr('transform', 'translate(0,' + h + ')') .call(d3.axisBottom(x).ticks(tick)) lines .append('g') .call(d3.axisLeft(y)) .append('text') .attr('class', 'ylabel') .attr('transform', 'rotate(-90)') .attr('y', 6) .attr('dy', '0.71em') .text(yAxisLabel) function dateDiffInDays(a, b) { const _MS_PER_DAY = 1000 * 60 * 60 * 24 // Discard the time and time-zone information. const utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate()) const utc2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate()) return Math.floor((utc2 - utc1) / _MS_PER_DAY) } } render() { return <div ref={this.myRef} className="LineChart" /> } } export default LineChart
内容的提问来源于stack exchange,提问作者The Old County
相关产品推荐
相关产品推荐

