我想创建折线图,当我移动鼠标时,它会显示点和此点数据。这是我的代码。但我发现点位不正确。我不知道。谢谢你的帮助。
这是我的代码。我用的是d3 v4。
(function lineChart() {
elementId = 'real_monitor_platform_getBetAmount';
xMax = 1528170430000;
yMax = 8;
xMin = 1528170360000;
yMin = 0;
x = 'unixtime';
y = 'betAmount';
dataset = [{unixtime:1528170360000,betAmount:0},
{unixtime:1528170370000,betAmount:1},
{unixtime:1528170380000,betAmount:2},
{unixtime:1528170390000,betAmount:3},
{unixtime:1528170400000,betAmount:5},
{unixtime:1528170410000,betAmount:6},
{unixtime:1528170420000,betAmount:7},
{unixtime:1528170430000,betAmount:8}];
dataset.sort((a, b) => a[x] - b[x]);
const margin = {
top: 30, right: 40, bottom: 120, left: 60,
};
const w = 700;
const h = 300;
const width = w + margin.left + margin.right;
const height = h + margin.top + margin.bottom;
const formatTime = d3.timeFormat('%Y-%m-%d %H:%M:%S');
const svg = d3.select(`#${elementId}`).append('svg')
.attr('width', width)
.attr('height', height),
areaWidth = width - margin.left - margin.right,
areaHeight = svg.attr('height') - margin.top - margin.bottom,
g = svg.append('g')
.attr('id', 'group')
.attr('transform', `translate(${margin.left},${margin.top})`)
.attr('width', areaWidth)
.attr('height', areaHeight);
const xScale = d3.scaleTime()
.domain([xMin, xMax])
.range([0, areaWidth]);
const yScale = d3.scaleLinear().domain([yMin, yMax]).range([areaHeight, 0]);
// create axis objects
const xAxis = d3.axisBottom(xScale).ticks(width / 100);
const yAxis = d3.axisLeft(yScale);
const line = d3.line()
.x(d =>
xScale(d[x]),
).y(d =>
yScale(d[y]),
);
const t = d3.transition()
.duration(500)
.ease(d3.easeLinear);
const xGrooup = g.append('g')
.attr('transform', `translate(0,${areaHeight})`)
.call(xAxis.tickFormat(formatTime).ticks(3));
const yGroup = g.append('g')
.attr('transform', 'translate(0,0)')
.call(yAxis);
g.append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('width', areaWidth)
.attr('height', areaHeight);
const bisectDate = d3.bisector(d => d.unixtime).left;
const focus = g.append('g')
.attr('class', 'focus')
.style('display', 'none');
const circle = focus.append('circle')
.attr('r', 4)
.style('fill', '#F1F3F3')
.style('stroke', '#6F257F')
.style('stroke-width', '1px');
const updateLine = g.append('g')
.attr('class', 'chart')
.selectAll('line')
.data([dataset]);
const enterLine = updateLine.enter();
const exitLine = updateLine.exit();
const path = enterLine.append('path')
.attr('clip-path', 'url(#clip)')
.attr('class', 'line')
.attr('d', line)
.attr('fill', 'none')
.attr('stroke', 0)
.transition(t)
.attr('stroke-width', 1)
.attr('stroke', 'DodgerBlue');
exitLine.remove();
const zoom = d3.zoom()
.scaleExtent([1, 80])
.translateExtent([[0, 0], [areaWidth, areaHeight]])
.on('zoom', zoomed);
const zoomRect = svg.append('rect')
.attr('width', width)
.attr('height', height)
.attr('transform', 'translate(0,0)')
.style('fill', 'transparent')
.attr('fill', 'none')
.attr('pointer-events', 'all')
.call(zoom)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function zoomed() {
const new_xScale = d3.event.transform.rescaleX(xScale);
xGrooup.call(xAxis.scale(new_xScale));
d3.select(`#${elementId}`).select('svg').select('#group').select('.chart')
.select('path.line')
.attr('d', line.x(d => new_xScale(d.unixtime)));
}
function mousemove() {
var transform = d3.zoomTransform(this);
var xt = transform.rescaleX(xScale);
var yt = transform.rescaleY(yScale);
let g = d3.select("#group")._groups[0][0]
var mouse = d3.mouse(g);
var x0 = xt.invert(mouse[0]);
var i = bisectDate(dataset, x0, 1);
var d0 = dataset[i - 1];
var d1 = dataset[i];
var d = x0 - d0[x] > d1[x] - x0 ? d1 : d0;
circle.attr("transform", `translate(${transform.applyX(xScale(d[x]))},${transform.applyY(yScale(d[y]))})`);
}
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<div id="real_monitor_platform_getBetAmount"></div>
修改
这对我有用。
(function lineChart() {
elementId = 'real_monitor_platform_getBetAmount';
xMax = 1528170430000;
yMax = 8;
xMin = 1528170360000;
yMin = 0;
x = 'unixtime';
y = 'betAmount';
dataset = [{unixtime:1528170360000,betAmount:0},
{unixtime:1528170370000,betAmount:1},
{unixtime:1528170380000,betAmount:2},
{unixtime:1528170390000,betAmount:3},
{unixtime:1528170400000,betAmount:5},
{unixtime:1528170410000,betAmount:6},
{unixtime:1528170420000,betAmount:7},
{unixtime:1528170430000,betAmount:8}];
dataset.sort((a, b) => a[x] - b[x]);
const margin = {
top: 30, right: 40, bottom: 120, left: 60,
};
const w = 700;
const h = 300;
const width = w + margin.left + margin.right;
const height = h + margin.top + margin.bottom;
const formatTime = d3.timeFormat('%Y-%m-%d %H:%M:%S');
const svg = d3.select(`#${elementId}`).append('svg')
.attr('width', width)
.attr('height', height),
areaWidth = width - margin.left - margin.right,
areaHeight = svg.attr('height') - margin.top - margin.bottom,
g = svg.append('g')
.attr('id', 'group')
.attr('transform', `translate(${margin.left},${margin.top})`)
.attr('width', areaWidth)
.attr('height', areaHeight);
const xScale = d3.scaleTime()
.domain([xMin, xMax])
.range([0, areaWidth]);
const yScale = d3.scaleLinear().domain([yMin, yMax]).range([areaHeight, 0]);
// create axis objects
const xAxis = d3.axisBottom(xScale).ticks(width / 100);
const yAxis = d3.axisLeft(yScale);
const line = d3.line()
.x(d =>
xScale(d[x]),
).y(d =>
yScale(d[y]),
);
const t = d3.transition()
.duration(500)
.ease(d3.easeLinear);
const xGrooup = g.append('g')
.attr('transform', `translate(0,${areaHeight})`)
.call(xAxis.tickFormat(formatTime).ticks(3));
const yGroup = g.append('g')
.attr('transform', 'translate(0,0)')
.call(yAxis);
g.append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('width', areaWidth)
.attr('height', areaHeight);
const bisectDate = d3.bisector(d => d.unixtime).left;
const focus = g.append('g')
.attr('class', 'focus')
.style('display', 'none');
const circle = focus.append('circle')
.attr('r', 4)
.style('fill', '#F1F3F3')
.style('stroke', '#6F257F')
.style('stroke-width', '1px');
const updateLine = g.append('g')
.attr('class', 'chart')
.selectAll('line')
.data([dataset]);
const enterLine = updateLine.enter();
const exitLine = updateLine.exit();
const path = enterLine.append('path')
.attr('clip-path', 'url(#clip)')
.attr('class', 'line')
.attr('d', line)
.attr('fill', 'none')
.attr('stroke', 0)
.transition(t)
.attr('stroke-width', 1)
.attr('stroke', 'DodgerBlue');
exitLine.remove();
const zoom = d3.zoom()
.scaleExtent([1, 80])
.translateExtent([[0, 0], [areaWidth, areaHeight]])
.on('zoom', zoomed);
const zoomRect = svg.append('rect')
.attr('width', width)
.attr('height', height)
.attr('transform', 'translate(0,0)')
.style('fill', 'transparent')
.attr('fill', 'none')
.attr('pointer-events', 'all')
.call(zoom)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function zoomed() {
const new_xScale = d3.event.transform.rescaleX(xScale);
xGrooup.call(xAxis.scale(new_xScale));
d3.select(`#${elementId}`).select('svg').select('#group').select('.chart')
.select('path.line')
.attr('d', line.x(d => new_xScale(d.unixtime)));
}
function mouseDate(scale) {
var g = d3.select("#group")._groups[0][0]
var x0 = scale.invert(d3.mouse(g)[0]),
i = bisectDate(dataset, x0, 1),
d0 = dataset[i - 1],
d1 = dataset[i],
d = x0 - d0[x] > d1[x] - x0 ? d1 : d0;
return d;
}
function mousemove() {
var transform = d3.zoomTransform(this);
var xt = transform.rescaleX(xScale);
var yt = transform.rescaleY(yScale);
d = mouseDate(xt);
console.log(transform.applyX(xScale(d[x])));
console.log(transform.applyY(yScale(d[y])));
circle.attr("transform", `translate(${transform.applyX(xScale(d[x]))},${(yScale(d[y]))})`);
}
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<div id="real_monitor_platform_getBetAmount"></div>
答案 0 :(得分:2)
您必须考虑边距。
所以,而不是......
const focus = svg.append('g')
......应该是:
const focus = g.append('g')
以下是具有该更改的代码:
(function lineChart() {
elementId = 'real_monitor_platform_getBetAmount';
xMax = 1528170430000;
yMax = 8;
xMin = 1528170360000;
yMin = 0;
x = 'unixtime';
y = 'betAmount';
dataset = [{unixtime:1528170360000,betAmount:0},
{unixtime:1528170370000,betAmount:1},
{unixtime:1528170380000,betAmount:2},
{unixtime:1528170390000,betAmount:3},
{unixtime:1528170400000,betAmount:5},
{unixtime:1528170410000,betAmount:6},
{unixtime:1528170420000,betAmount:7},
{unixtime:1528170430000,betAmount:8}];
dataset.sort((a, b) => a[x] - b[x]);
const margin = {
top: 30, right: 40, bottom: 120, left: 60,
};
const w = 700;
const h = 300;
const width = w + margin.left + margin.right;
const height = h + margin.top + margin.bottom;
const formatTime = d3.timeFormat('%Y-%m-%d %H:%M:%S');
const svg = d3.select(`#${elementId}`).append('svg')
.attr('width', width)
.attr('height', height),
areaWidth = width - margin.left - margin.right,
areaHeight = svg.attr('height') - margin.top - margin.bottom,
g = svg.append('g')
.attr('id', 'group')
.attr('transform', `translate(${margin.left},${margin.top})`)
.attr('width', areaWidth)
.attr('height', areaHeight);
const xScale = d3.scaleTime()
.domain([xMin, xMax])
.range([0, areaWidth]);
const yScale = d3.scaleLinear().domain([yMin, yMax]).range([areaHeight, 0]);
// create axis objects
const xAxis = d3.axisBottom(xScale).ticks(width / 100);
const yAxis = d3.axisLeft(yScale);
const line = d3.line()
.x(d =>
xScale(d[x]),
).y(d =>
yScale(d[y]),
);
const t = d3.transition()
.duration(500)
.ease(d3.easeLinear);
const xGrooup = g.append('g')
.attr('transform', `translate(0,${areaHeight})`)
.call(xAxis.tickFormat(formatTime).ticks(3));
const yGroup = g.append('g')
.attr('transform', 'translate(0,0)')
.call(yAxis);
g.append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('width', areaWidth)
.attr('height', areaHeight);
const bisectDate = d3.bisector(d => d.unixtime).left;
const focus = g.append('g')
.attr('class', 'focus')
.style('display', 'none');
const circle = focus.append('circle')
.attr('r', 4)
.style('fill', '#F1F3F3')
.style('stroke', '#6F257F')
.style('stroke-width', '1px');
const updateLine = g.append('g')
.attr('class', 'chart')
.selectAll('line')
.data([dataset]);
const enterLine = updateLine.enter();
const exitLine = updateLine.exit();
const path = enterLine.append('path')
.attr('clip-path', 'url(#clip)')
.attr('class', 'line')
.attr('d', line)
.attr('fill', 'none')
.attr('stroke', 0)
.transition(t)
.attr('stroke-width', 1)
.attr('stroke', 'DodgerBlue');
exitLine.remove();
const zoom = d3.zoom()
.scaleExtent([1, 80])
.translateExtent([[0, 0], [areaWidth, areaHeight]])
.on('zoom', zoomed);
const zoomRect = svg.append('rect')
.attr('width', width)
.attr('height', height)
.attr('transform', 'translate(0,0)')
.style('fill', 'transparent')
.attr('fill', 'none')
.attr('pointer-events', 'all')
.call(zoom)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function zoomed() {
const new_xScale = d3.event.transform.rescaleX(xScale);
xGrooup.call(xAxis.scale(new_xScale));
d3.select(`#${elementId}`).select('svg').select('#group').select('.chart')
.select('path.line')
.attr('d', line.x(d => new_xScale(d.unixtime)));
}
function mousemove() {
var mouse = d3.mouse(this);
var x0 = xScale.invert(mouse[0]);
var i = bisectDate(dataset, x0);
var d0 = dataset[i - 1];
var d1 = dataset[i];
var d = x0 - d0[x] > d1[x] - x0 ? d1 : d0;
circle.attr("transform", `translate(${xScale(d[x])},${(yScale(d[y]))})`);
}
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<div id="real_monitor_platform_getBetAmount"></div>
顺便说一句,这不适用于缩放...但是,那是另一个问题。