英文:
How to show dynamic data in a pie chart with needle
问题
在 Meter
组件中,你正在尝试使用 value
变量进行映射,而 value
是一个数组,这可能导致错误。你可以尝试修改 value
的赋值方式,确保它是一个数字,而不是包含数据的数组。例如,你可以使用 conData[0].data
:
const value = conData[0].data;
或者,如果你想显示所有州的总能耗,你可能需要在 Calculation
组件中对所有选定州的能耗数据进行求和,然后将总和传递给 Meter
组件。
另外,确保 conData
不是 undefined
或 null
,可以在 Meter
组件中添加一个条件来检查:
const value = conData ? conData[0].data : 0;
这样可以避免在 conData
为 undefined
时引发错误。
英文:
I am trying to make a pie chart with needle with recharts. Link. Actually I am selecting a state name from a dropdown and wanting to show the selected state's energy consumption data in the pie chart via needle. So here is my states.json file:
[
{
"state_id": "1",
"sortname": "AF",
"state_name": "ANDAMAN & NICOBAR ISLANDS",
"energyData": [
{
"data_id": "1",
"data": "367.3948635",
"state_id": "1"
}
]
},
{
"state_id": "2",
"sortname": "DZ",
"state_name": "ANDHRA PRADESH",
"energyData": [
{
"data_id": "2",
"data": "328.8017687",
"state_id": "2"
}
]
},
{
"state_id": "3",
"sortname": "AS",
"state_name": "ARUNACHAL PRADESH",
"energyData": [
{
"data_id": "3",
"data": "120.9100817",
"state_id": "3"
}
]
},
{
"state_id": "4",
"sortname": "AD",
"state_name": "ASSAM",
"energyData": [
{
"data_id": "4",
"data": "105.9831799",
"state_id": "4"
}
]
},
{
"state_id": "5",
"sortname": "AO",
"state_name": "CHANDIGARH",
"energyData": [
{
"data_id": "5",
"data": "564.5855402",
"state_id": "5"
}
]
},
{
"state_id": "6",
"sortname": "AI",
"state_name": "BIHAR",
"energyData": [
{
"data_id": "6",
"data": "118.696485",
"state_id": "6"
}
]
},
{
"state_id": "7",
"sortname": "AQ",
"state_name": "CHHATTISGARH",
"energyData": [
{
"data_id": "7",
"data": "213.6288618",
"state_id": "7"
}
]
},
{
"state_id": "8",
"sortname": "AG",
"state_name": "DADRA & NAGAR HAVELI",
"energyData": [
{
"data_id": "7",
"data": "213.6288618",
"state_id": "8"
}
]
},
{
"state_id": "9",
"sortname": "AR",
"state_name": "DAMAN & DIU ",
"energyData": [
{
"data_id": "7",
"data": "213.6288618",
"state_id": "9"
}
]
},
{
"state_id": "10",
"sortname": "AM",
"state_name": "GOA",
"energyData": [
{
"data_id": "7",
"data": "213.6288618",
"state_id": "10"
}
]
}
]
And here is my calculation page, where is the dropdown :
import React, { useState } from 'react';
import LetsGoButton from './LetsGoButton';
import statesData from '../../public/states.json'
import Meter from './Meter';
const Calculation = () => {
const [statesId, setStatesId] = useState('')
const [avgConsumptionData, setAvgConsumptionData] = useState([])
const [conDataId, setConDataId] = useState('')
const handleStates = (e) => {
const getStateId = e.target.value
const getAvgEnergyData = statesData.find(state => state.state_id === getStateId)?.energyData
setAvgConsumptionData(getAvgEnergyData)
setStatesId(getStateId)
}
const handleAvgConsumptionData = (e) => {
const conDataId = e.target.value
console.log(conDataId);
setConDataId(conDataId)
}
return (
<section>
<div>
<div>
{/* STATE */}
<div>
<select defaultValue="State" name="state" id="state" onChange={(e) => handleStates(e)}>
<option selected disabled>State</option>
{
statesData.map((data, idx) => (
<option value={data.state_id} key={idx}>{data.state_name}</option>
))
}
</select>
</div>
<Meter conData={avgConsumptionData} />
</div>
<LetsGoButton />
</div>
</section>
);
};
export default Calculation;
I passed the avgConsumptionData to the Meter component and tried to set the data dynamically in the needle value. Here is the Meter component :
import React, { useState } from 'react';
import { PieChart, Pie, Cell } from 'recharts';
const Meter = ({ conData}) => {
console.log(conData);
const RADIAN = Math.PI / 180;
const data = [
{ name: '0', value: 0, color: '#ff0000' },
{ name: '150', value: 150, color: '#00ff00' },
{ name: '300', value: 300, color: '#0000ff' },
{ name: '450', value: 450, color: '#924f64' },
{ name: '600', value: 600, color: '#dc8965' },
{ name: '750', value: 750, color: '#d2e1f7' },
{ name: '900', value: 900, color: '#131b27' },
];
const cx = 150;
const cy = 200;
const iR = 50;
const oR = 100;
const value = conData
// const value = conData[0].data
// const value = conData.map(x => x.data)
const needle = (value, data, cx, cy, iR, oR, color) => {
let total = 0;
data.forEach((v) => {
total += v.value;
});
const ang = 180.0 * (1 - value / total);
const length = (iR + 2 * oR) / 3;
const sin = Math.sin(-RADIAN * ang);
const cos = Math.cos(-RADIAN * ang);
const r = 5;
const x0 = cx + 5;
const y0 = cy + 5;
const xba = x0 + r * sin;
const yba = y0 - r * cos;
const xbb = x0 - r * sin;
const ybb = y0 + r * cos;
const xp = x0 + length * cos;
const yp = y0 + length * sin;
return [
<circle cx={x0} cy={y0} r={r} fill={color} stroke="none" />,
<path d={`M${xba} ${yba}L${xbb} ${ybb} L${xp} ${yp} L${xba} ${yba}`} stroke="#none" />,
];
};
return (
<div>
<PieChart>
<Pie
dataKey="value"
startAngle={180}
endAngle={0}
data={data}
cx={cx}
cy={cy}
innerRadius={iR}
outerRadius={oR}
fill="#8884d8"
stroke="none"
>
{data.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
{needle(value, data, cx, cy, iR, oR, '#d0d000')}
</PieChart>
</div>
);
};
export default Meter;
So when I am logging in the "value" variable which contains the conData which is having the selected states data, I see an Array in the console that contains data_id, data, and state_id. But when I want to map the array an error occurs :
> TypeError: Cannot read properties of undefined (reading 'map')
why this error is occurring? Is the passing method of data from the calculation component to the Meter component correct or wrong? is there any other way to solve it?
答案1
得分: 0
I just changed the data type you were passing on your Meter component from Array to Object.
Calculation.js
const handleStates = (e) => {
const getStateId = e.target.value
const getAvgEnergyData = statesData.find(state => state.state_id === getStateId)?.energyData
setAvgConsumptionData(getAvgEnergyData[0])
setStatesId(getStateId)
}
Meter.js
const Meter = ({ conData}) => {
console.log(conData);
const RADIAN = Math.PI / 180;
const data = [
{ name: '0', value: 0, color: '#ff0000' },
{ name: '150', value: 150, color: '#00ff00' },
{ name: '300', value: 300, color: '#0000ff' },
{ name: '450', value: 450, color: '#924f64' },
{ name: '600', value: 600, color: '#dc8965' },
{ name: '750', value: 750, color: '#d2e1f7' },
{ name: '900', value: 900, color: '#131b27' },
];
const cx = 150;
const cy = 200;
const iR = 50;
const oR = 100;
const value = conData.data;
// const value = conData[0].data
// const value = conData.map(x => x.data)
const needle = (value, data, cx, cy, iR, oR, color) => {
let total = 0;
data.forEach((v) => {
total += v.value;
});
const ang = 180.0 * (1 - value / total);
const length = (iR + 2 * oR) / 3;
const sin = Math.sin(-RADIAN * ang);
const cos = Math.cos(-RADIAN * ang);
const r = 5;
const x0 = cx + 5;
const y0 = cy + 5;
const xba = x0 + r * sin;
const yba = y0 - r * cos;
const xbb = x0 - r * sin;
const ybb = y0 + r * cos;
const xp = x0 + length * cos;
const yp = y0 + length * sin;
return [
<circle cx={x0} cy={y0} r={r} fill={color} stroke="none" />,
<path d={`M${xba} ${yba}L${xbb} ${ybb} L${xp} ${yp} L${xba} ${yba}`} stroke="#none" />,
];
};
return (
<div>
<PieChart width={400} height={500}>
<Pie
dataKey="value"
startAngle={180}
endAngle={0}
data={data}
cx={cx}
cy={cy}
innerRadius={iR}
outerRadius={oR}
fill="#8884d8"
stroke="none"
>
{data.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
{needle(value, data, cx, cy, iR, oR, '#d0d000')}
</PieChart>
</div>
);
};
export default Meter;
You can simply get the data attribute from the object with conData.data.
Also don't forget to add width and height attributes to your PieChart.
<PieChart width={400} height={500}>
英文:
I just changed the data type you were passing on your Meter component from Array to Object.
Calculation.js
const handleStates = (e) => {
const getStateId = e.target.value
const getAvgEnergyData = statesData.find(state => state.state_id === getStateId)?.energyData
setAvgConsumptionData(getAvgEnergyData[0])
setStatesId(getStateId)
}
Meter.js
const Meter = ({ conData}) => {
console.log(conData);
const RADIAN = Math.PI / 180;
const data = [
{ name: '0', value: 0, color: '#ff0000' },
{ name: '150', value: 150, color: '#00ff00' },
{ name: '300', value: 300, color: '#0000ff' },
{ name: '450', value: 450, color: '#924f64' },
{ name: '600', value: 600, color: '#dc8965' },
{ name: '750', value: 750, color: '#d2e1f7' },
{ name: '900', value: 900, color: '#131b27' },
];
const cx = 150;
const cy = 200;
const iR = 50;
const oR = 100;
const value = conData.data
// const value = conData[0].data
// const value = conData.map(x => x.data)
const needle = (value, data, cx, cy, iR, oR, color) => {
let total = 0;
data.forEach((v) => {
total += v.value;
});
const ang = 180.0 * (1 - value / total);
const length = (iR + 2 * oR) / 3;
const sin = Math.sin(-RADIAN * ang);
const cos = Math.cos(-RADIAN * ang);
const r = 5;
const x0 = cx + 5;
const y0 = cy + 5;
const xba = x0 + r * sin;
const yba = y0 - r * cos;
const xbb = x0 - r * sin;
const ybb = y0 + r * cos;
const xp = x0 + length * cos;
const yp = y0 + length * sin;
return [
<circle cx={x0} cy={y0} r={r} fill={color} stroke="none" />,
<path d={`M${xba} ${yba}L${xbb} ${ybb} L${xp} ${yp} L${xba} ${yba}`} stroke="#none" />,
];
};
return (
<div>
<PieChart width={400} height={500}>
<Pie
dataKey="value"
startAngle={180}
endAngle={0}
data={data}
cx={cx}
cy={cy}
innerRadius={iR}
outerRadius={oR}
fill="#8884d8"
stroke="none"
>
{data.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
{needle(value, data, cx, cy, iR, oR, '#d0d000')}
</PieChart>
</div>
);
};
export default Meter;
You can simply get the data attribute from the object with conData.data.
Also don't forget to add width and height attributes to your PieChart.
<PieChart width={400} height={500}>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论