有兴趣在折线图中渲染垂直和水平工具提示线。使用dc.js,d3.js ver 4.2.8,React。在原始版本中,它运作良好 Tootltip lines are being displayed ,但不是在React版本中: Tooltip lines are not being displayed 。代码:
//////Line.js
import React, { PropTypes } from 'react';
import ReactDOM from "react-dom";
import * as d3 from 'd3';
import dc from "dc";
import * as crossfilter from 'crossfilter';
import {Jumbotron } from 'react-bootstrap';
import functionDCHelper from './functionDCHelper';
import {scaleTime, scaleLinear} from 'd3-scale';
import { axisLeft, axisBottom } from 'd3-axis';
import TableChart from "../components/TableChart.js";
class LineChart extends React.Component {
componentDidMount() {
var bitrateLineChart = dc.compositeChart(this.refs.lineChart);
var { min15, minDate, maxDate, bitrateWeekMinIntervalGroupMove, maxbit } = functionDCHelper.generateValues(this.props.data);
bitrateLineChart
.xUnits(min15.range)
.x(d3.scaleTime().domain([new Date(minDate), new Date(maxDate)]))
.yAxisPadding('5%')
.elasticY(true)
.width(990)
.height(200)
.transitionDuration(500)
.margins({ top: 30, right: 50, bottom: 25, left: 50, padding: 1 })
.mouseZoomable(true)
.brushOn(false)
.renderHorizontalGridLines(true)
.legend(dc.legend().x(800).y(10).itemHeight(13).gap(5))
//Render max bitrate horizontal line copied from bar-extra-line.html
.yAxisLabel("Total Bitrate per 15 minutes")
.on('renderlet', function (chart) {
chart.svg().selectAll('.chart-body').attr('clip-path', null)
var left_y = 10, right_y = 70; // use real statistics here!
var extra_data = [{ x: chart.x().range()[0], y: chart.y()(left_y) }, { x: chart.x().range()[1], y: chart.y()(right_y) }];
var line = d3.line()
.x(function (d) { return d.x; })
.y(function (d) { return maxbit; })
.curve(d3.curveLinear); //.interpolate('linear');
var chartBody = chart.select('g.chart-body');
var path = chartBody.selectAll('path.extra').data([extra_data]);
path.enter().append('path').attr({
class: 'extra',
stroke: 'red',
id: 'extra-line',
});
path.attr('d', line);
// Label the max line
var text = chartBody.selectAll('text.extra-label').data([0]);
text.enter().append('text')
.attr('text-anchor', 'middle')
.append('textPath').attr({
class: 'extra-label',
'xlink:href': '#extra-line',
startOffset: '50%'
})
.text('Total Bitrate Max Value');
})
// Title can be called by any stack layer.
.title(function (d) {
var value = d.value.total ? d.value.total : d.value;
if (isNaN(value)) {
value = 0;
}
return functionDCHelper.dateFormat(d.key) + ' \n Total Bit:' + functionDCHelper.numberFormat(value)
})
//Creating dynamic Y axis with min max ticks' values depending on min max of data - copied from http://jsfiddle.net/gordonwoodhull/7anae5c5/1/
.compose([
functionDCHelper.nonzero_min(dc.lineChart(bitrateLineChart)
.dimension(min15)
.colors('green')
.group(bitrateWeekMinIntervalGroupMove, 'Bitrate Total')
.valueAccessor(function (d) {
return d.value.total;
})
// .dashStyle([2,2])
.interpolate('d3.curveStepAfter')
.renderArea(false)
.brushOn(false)
.renderDataPoints(false)
.clipPadding(10)),
])
bitrateLineChart.render();
}
render() {
return(
<div ref="lineChart">
</div>
);
}
}
export default LineChart;
//////functionDCHelper.js
import crossfilter from 'crossfilter';
import * as d3 from 'd3';
import dc from 'dc';
var minDate,min15,bitrateWeekMinIntervalGroupMove,maxDate,minIntervalWeekBitrateGroup,dateDimension,dateFormat,numberFormat,maxbit;
function nonzero_min(chart) {
dc.override(chart, 'yAxisMin', function () {
var min = d3.min(chart.data(), function (layer) {
return d3.min(layer.values, function (p) {
return p.y + p.y0;
});
});
return dc.utils.subtract(min, chart.yAxisPadding());
});
return chart;
}
// 15 Min Interval - copied from https://github.com/mbostock/d3/blob/master/src/time/interval.js
var d3_date = Date;
function d3_time_interval(local, step, number) {
function round(date) {
var d0 = local(date), d1 = offset(d0, 1);
return date - d0 < d1 - date ? d0 : d1;
}
function ceil(date) {
step(date = local(new d3_date(date - 1)), 1);
return date;
}
function offset(date, k) {
step(date = new d3_date(+date), k);
return date;
}
function range(t0, t1, dt) {
var time = ceil(t0), times = [];
if (dt > 1) {
while (time < t1) {
if (!(number(time) % dt)) times.push(new Date(+time));
step(time, 1);
}
} else {
while (time < t1) times.push(new Date(+time)), step(time, 1);
}
return times;
}
function range_utc(t0, t1, dt) {
try {
d3_date = d3_date_utc;
var utc = new d3_date_utc();
utc._ = t0;
return range(utc, t1, dt);
} finally {
d3_date = Date;
}
}
local.floor = local;
local.round = round;
local.ceil = ceil;
local.offset = offset;
local.range = range;
var utc = local.utc = d3_time_interval_utc(local);
utc.floor = utc;
utc.round = d3_time_interval_utc(round);
utc.ceil = d3_time_interval_utc(ceil);
utc.offset = d3_time_interval_utc(offset);
utc.range = range_utc;
return local;
}
function d3_time_interval_utc(method) {
return function (date, k) {
try {
d3_date = d3_date_utc;
var utc = new d3_date_utc();
utc._ = date;
return method(utc, k)._;
} finally {
d3_date = Date;
}
};
}
// generalization of d3.time.minute copied from- https://github.com/mbostock/d3/blob/master/src/time/minute.js
function n_minutes_interval(nmins) {
var denom = 6e4 * nmins;
return d3_time_interval(function (date) {
return new d3_date(Math.floor(date / denom) * denom);
}, function (date, offset) {
date.setTime(date.getTime() + Math.floor(offset) * denom); // DST breaks setMinutes
}, function (date) {
return date.getMinutes();
});
}
min15 = n_minutes_interval(15);
dateFormat = d3.timeFormat('%Y/%m/%d/%H:%M');
numberFormat = d3.format('d');
//### Crossfilter Dimensions
function generateValues(data) {
data.forEach(function (d) {
d.bitdate = new Date(d.DATETIME); //d.DATETIME = dateFormat.parse(d.DATETIME);
// d.month = d3.time.month(d.bitdate);
// d.week = d3.time.week(d.bitdate);
d.BITRATE = +d.BITRATE.match(/\d+/); //d.BITRATE = +d.BITRATE;
});
var crossFilteredData = crossfilter(data);
var all = crossFilteredData.groupAll();
// Dimension by full date
dateDimension = crossFilteredData.dimension(function (d) {
return d.bitdate;
});
maxbit = d3.max(data, function (d) { return +d["BITRATE"]; }); //alert(maxbit);
//Group bitrate per week, 15 minInterval - maintain running tallies
bitrateWeekMinIntervalGroupMove = dateDimension.group(min15).reduce(
/* callback for when data is added to the current filter results */
function (p, v) {
++p.count;
p.BITRATE = +v.BITRATE;
p.total += +v.BITRATE;
p.avg = p.count ? Math.round(p.total / p.count) : 0;
return p;
},
/* callback for when data is removed from the current filter results */
function (p, v) {
--p.count;
p.BITRATE = +v.BITRATE;
p.total -= +v.BITRATE;
p.avg = p.count ? Math.round(p.total / p.count) : 0;
return p;
},
/* initialize p */
function () {
return {
count: 0,
bitrate: 0,
total: 0,
avg: 0
};
}
);
try {
minDate = dateDimension.bottom(1)[0].DATETIME;
} catch(err) {
minDate = new Date("2016-06-14 0:00");
}
try {
maxDate = dateDimension.top(1)[0].DATETIME;
} catch(err) {
maxDate = new Date("2016-06-18 23:55");
}
return {
min15, minDate, maxDate, bitrateWeekMinIntervalGroupMove,minIntervalWeekBitrateGroup,dateDimension,maxbit
};
}
export default {
generateValues,
nonzero_min,
dateFormat,
numberFormat
};
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
path.line {
fill: none;
stroke: green;
stroke-width: 1.5px;
}
.y.axis line,
.y.axis path {
fill: none;
stroke: black;
}
.x.axis line,
.x.axis path {
fill: none;
stroke: black;
}
</style>
<title>Line Chart DC.js,React</title>
</head>
<body>
<div id="App"></div>
<script src="/bundle.js"></script>
</body>
</html>
任何帮助将不胜感激
答案 0 :(得分:1)
目前的解决方案是在index.html中放置以下样式:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
path.yRef{
storke-width:2;
stroke:red;
dislplay:inline;
}
path.xRef{
storke-width:2;
stroke:red;
dislplay:inline;
}
</style>
<title>Line Chart DC.js,React</title>
</head>
<body>
<div id="App"></div>
<script src="/bundle.js"></script>
</body>
</html>
宁愿在图表的js(Line.js)或css类中处理它,任何建议都会受到欢迎。显示: