d.label 在 D3 折线图上读取未定义
d.label is reading undefined on D3 Line chart
我是 d3 的新手,从 Urvashi 女士那里找到了这个教程 Link Here
我现在可以看到绘制的折线图,但是鼠标工具提示会导致未定义的错误。它是未定义的,无法找到根本原因,因为数据是完全随机生成的,即使 console.log() 显示未定义。
所以这是错误:
TypeError: Cannot read properties of undefined (reading 'label')
SVGRectElement.mousemove
http://localhost:3000/static/js/main.chunk.js:269:54
266 | const x0 = bisect(data, xScale.invert(xPos));
267 | const d0 = data[x0];
268 | console.log(data[x0]);
> 269 | focus.attr('transform', `translate(${xScale(d0.label)},${yScale(d0.value)})`);
| ^ 270 | tooltip.transition().duration(300).style('opacity', 0.9);
271 | tooltip.html(d0.tooltipContent || d0.label).style('transform', `translate(${xScale(d0.label) + 30}px,${yScale(d0.value) - 30}px)`);
272 | } // d3.select('#container')
我一直在试图弄清楚为什么参数 d 及其属性未定义,但是图形呈现,除非将鼠标悬停在图形上。
原始代码如下:
import React, { useEffect } from 'react';
import './Linechart.scss';
import * as d3 from 'd3';
const Linechart = (props) => {
const { data, width, height } = props;
useEffect(() => {
drawChart();
}, [data])
const drawChart = () => {
//clears previous chart render
d3.select('#container')
.select('svg')
.remove();
d3.select('#container')
.select('.tooltip')
.remove();
const margin = { top: 50, right: 50, bottom: 50, left: 50 };
const yMinValue = d3.min(data, d => d.value);
const yMaxValue = d3.max(data, d => d.value);
const xMinValue = d3.min(data, d => d.label);
const xMaxValue = d3.max(data, d => d.label);
const svg = d3
.select('#container')
.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})`);
const xScale = d3 //x-axis
.scaleLinear()
.domain([xMinValue, xMaxValue])
.range([0, width]);
const yScale = d3 //y-axis
.scaleLinear()
.range([height, 0])
.domain([0, yMaxValue]);
const line = d3
.line()
.x(d => xScale(d.label))
.y(d => yScale(d.value))
.curve(d3.curveMonotoneX);
svg
.append('g')
.attr('class', 'grid')
.attr('transform', `translate(0,${height})`)
.call(
d3.axisBottom(xScale)
.tickSize(-height)
.tickFormat(''),
);
svg
.append('g')
.attr('class', 'grid')
.call(
d3.axisLeft(yScale)
.tickSize(-width)
.tickFormat(''),
);
svg
.append('g')
.attr('class', 'x-axis')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom().scale(xScale).tickSize(15));
svg
.append('g')
.attr('class', 'y-axis')
.call(d3.axisLeft(yScale));
svg
.append('path')
.datum(data)
.attr('fill', 'none')
.attr('stroke', '#f6c3d0')
.attr('stroke-width', 4)
.attr('class', 'line')
.attr('d', line);
const focus = svg
.append('g')
.attr('class', 'focus')
.style('display', 'none');
focus.append('circle').attr('r', 5).attr('class', 'circle');
const tooltip = d3
.select('#container')
.append('div')
.attr('class', 'tooltip')
.style('opacity', 0);
svg
.append('rect')
.attr('class', 'overlay')
.attr('width', width)
.attr('height', height)
.style('opacity', 0)
.on('mouseover', () => {
focus.style('display', null);
})
.on('mouseout', () => {
tooltip
.transition()
.duration(300)
.style('opacity', 0);
})
.on('mousemove', mousemove);
function mousemove(event) {
const bisect = d3.bisector(d => d.label).left;
const xPos = d3.pointer(this)[0];
const x0 = bisect(data, xScale.invert(xPos));
const d0 = data[x0];
console.log(data[x0]);
focus.attr(
'transform',
`translate(${xScale(d0.label)},${yScale(d0.value)})`,
);
tooltip
.transition()
.duration(300)
.style('opacity', 0.9);
tooltip
.html(d0.tooltipContent || d0.label)
.style(
'transform',
`translate(${xScale(d0.label) + 30}px,${yScale(d0.value) - 30}px)`,
);
}
}
return(
<div id="container"></div>
)
}
export default Linechart;
并且数据是通过这个函数生成的:
const [data, setData] = useState([]);
const regenerateData = () => {
var chartData = [];
for (let index = 0; index < 20; index++) {
var value = Math.floor(Math.random() * index + 3);
var dataObject = {
label: index,
value,
tooltipContent:
`<b>x: </b> ${index} <br />
<b>y: </b> ${value}`,
}
chartData.push(dataObject);
}
setData(chartData);
}
如果只是一个参数,为什么还要定义呢?我对此很困惑,我学得有点慢,所以如果我不得不问一些问题,我很抱歉。
找到了,经过无数次console.log()终于搞明白了
const xPos = d3.pointer(this)[0];
const x0 = bisect(data, xScale.invert(xPos));
似乎这是一种旧方法,我只是碰巧用指针替换了鼠标以进行迁移,但是当我 console.log(xPos) 时,它只是抛出 undefined ,为什么?基本上就是这样。
const xPos = d3.pointer(event);
const x0 = bisect(data, xScale.invert(xPos[0]));
const d0 = data[x0];
现在,工具提示圆圈会在悬停时显示并带有自动识别坐标。
我是 d3 的新手,从 Urvashi 女士那里找到了这个教程 Link Here
我现在可以看到绘制的折线图,但是鼠标工具提示会导致未定义的错误。它是未定义的,无法找到根本原因,因为数据是完全随机生成的,即使 console.log() 显示未定义。
所以这是错误:
TypeError: Cannot read properties of undefined (reading 'label')
SVGRectElement.mousemove
http://localhost:3000/static/js/main.chunk.js:269:54
266 | const x0 = bisect(data, xScale.invert(xPos));
267 | const d0 = data[x0];
268 | console.log(data[x0]);
> 269 | focus.attr('transform', `translate(${xScale(d0.label)},${yScale(d0.value)})`);
| ^ 270 | tooltip.transition().duration(300).style('opacity', 0.9);
271 | tooltip.html(d0.tooltipContent || d0.label).style('transform', `translate(${xScale(d0.label) + 30}px,${yScale(d0.value) - 30}px)`);
272 | } // d3.select('#container')
我一直在试图弄清楚为什么参数 d 及其属性未定义,但是图形呈现,除非将鼠标悬停在图形上。
原始代码如下:
import React, { useEffect } from 'react';
import './Linechart.scss';
import * as d3 from 'd3';
const Linechart = (props) => {
const { data, width, height } = props;
useEffect(() => {
drawChart();
}, [data])
const drawChart = () => {
//clears previous chart render
d3.select('#container')
.select('svg')
.remove();
d3.select('#container')
.select('.tooltip')
.remove();
const margin = { top: 50, right: 50, bottom: 50, left: 50 };
const yMinValue = d3.min(data, d => d.value);
const yMaxValue = d3.max(data, d => d.value);
const xMinValue = d3.min(data, d => d.label);
const xMaxValue = d3.max(data, d => d.label);
const svg = d3
.select('#container')
.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})`);
const xScale = d3 //x-axis
.scaleLinear()
.domain([xMinValue, xMaxValue])
.range([0, width]);
const yScale = d3 //y-axis
.scaleLinear()
.range([height, 0])
.domain([0, yMaxValue]);
const line = d3
.line()
.x(d => xScale(d.label))
.y(d => yScale(d.value))
.curve(d3.curveMonotoneX);
svg
.append('g')
.attr('class', 'grid')
.attr('transform', `translate(0,${height})`)
.call(
d3.axisBottom(xScale)
.tickSize(-height)
.tickFormat(''),
);
svg
.append('g')
.attr('class', 'grid')
.call(
d3.axisLeft(yScale)
.tickSize(-width)
.tickFormat(''),
);
svg
.append('g')
.attr('class', 'x-axis')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom().scale(xScale).tickSize(15));
svg
.append('g')
.attr('class', 'y-axis')
.call(d3.axisLeft(yScale));
svg
.append('path')
.datum(data)
.attr('fill', 'none')
.attr('stroke', '#f6c3d0')
.attr('stroke-width', 4)
.attr('class', 'line')
.attr('d', line);
const focus = svg
.append('g')
.attr('class', 'focus')
.style('display', 'none');
focus.append('circle').attr('r', 5).attr('class', 'circle');
const tooltip = d3
.select('#container')
.append('div')
.attr('class', 'tooltip')
.style('opacity', 0);
svg
.append('rect')
.attr('class', 'overlay')
.attr('width', width)
.attr('height', height)
.style('opacity', 0)
.on('mouseover', () => {
focus.style('display', null);
})
.on('mouseout', () => {
tooltip
.transition()
.duration(300)
.style('opacity', 0);
})
.on('mousemove', mousemove);
function mousemove(event) {
const bisect = d3.bisector(d => d.label).left;
const xPos = d3.pointer(this)[0];
const x0 = bisect(data, xScale.invert(xPos));
const d0 = data[x0];
console.log(data[x0]);
focus.attr(
'transform',
`translate(${xScale(d0.label)},${yScale(d0.value)})`,
);
tooltip
.transition()
.duration(300)
.style('opacity', 0.9);
tooltip
.html(d0.tooltipContent || d0.label)
.style(
'transform',
`translate(${xScale(d0.label) + 30}px,${yScale(d0.value) - 30}px)`,
);
}
}
return(
<div id="container"></div>
)
}
export default Linechart;
并且数据是通过这个函数生成的:
const [data, setData] = useState([]);
const regenerateData = () => {
var chartData = [];
for (let index = 0; index < 20; index++) {
var value = Math.floor(Math.random() * index + 3);
var dataObject = {
label: index,
value,
tooltipContent:
`<b>x: </b> ${index} <br />
<b>y: </b> ${value}`,
}
chartData.push(dataObject);
}
setData(chartData);
}
如果只是一个参数,为什么还要定义呢?我对此很困惑,我学得有点慢,所以如果我不得不问一些问题,我很抱歉。
找到了,经过无数次console.log()终于搞明白了
const xPos = d3.pointer(this)[0];
const x0 = bisect(data, xScale.invert(xPos));
似乎这是一种旧方法,我只是碰巧用指针替换了鼠标以进行迁移,但是当我 console.log(xPos) 时,它只是抛出 undefined ,为什么?基本上就是这样。
const xPos = d3.pointer(event);
const x0 = bisect(data, xScale.invert(xPos[0]));
const d0 = data[x0];
现在,工具提示圆圈会在悬停时显示并带有自动识别坐标。