Javascript react应用中用d3条形图调用动态响应
我尝试渲染动态响应,并使用d3图表,实际上此应用程序是使用recharts开发的,因此开始使用d3实现,因此我在这里包括d3。bard3有一个问题,无法正确渲染数据并引发此错误 错误Javascript react应用中用d3条形图调用动态响应,javascript,reactjs,angular,d3.js,charts,Javascript,Reactjs,Angular,D3.js,Charts,我尝试渲染动态响应,并使用d3图表,实际上此应用程序是使用recharts开发的,因此开始使用d3实现,因此我在这里包括d3。bard3有一个问题,无法正确渲染数据并引发此错误 错误 TypeError: Cannot read property 'count' of undefined BarChartD3 src/components/BarChart.js:64 × TypeError: Cannot read property 'count' of undefined (a
TypeError: Cannot read property 'count' of undefined
BarChartD3
src/components/BarChart.js:64
×
TypeError: Cannot read property 'count' of undefined
(anonymous function)
src/components/BarChart.js:12
9 | const width = 500;
10 | const margin = { top: 20, right: 30, bottom: 30, left: 40 };
11 |
> 12 | const x = d3
| ^ 13 | .scaleBand()
14 | .domain(data.map((d) => d.Orders.count))
15 | .rangeRound([margin.left, width - margin.right])
View compiled
(anonymous function)
src/components/BarChart.js:12
9 | const width = 500;
10 | const margin = { top: 20, right: 30, bottom: 30, left: 40 };
11 |
> 12 | const x = d3
| ^ 13 | .scaleBand()
14 | .domain(data.map((d) => d.Orders.count))
15 | .rangeRound([margin.left, width - margin.right])
View compiled
(anonymous function)
src/components/useD3.js:8
5 | const ref = React.useRef();
6 |
7 | React.useEffect(() => {
> 8 | renderChartFn(d3.select(ref.current));
| ^ 9 | return () => {};
10 | }, dependencies);
11 | return ref;
结果集数据
这是我试图渲染的结果数据,但在某个点失败
loadResponse:
annotation:
dimensions: {}
measures: {Orders.count: {…}, Products.count: {…}, LineItems.count: {…}, Orders.totalAmount:
{…}, LineItems.cumulativeTotalRevenue: {…}, …}
segments: {}
timeDimensions: {Orders.completedAt.day: {…}, Orders.completedAt: {…}}
__proto__: Object
data: Array(30)
0: {Orders.completedAt.day: "2021-02-12T00:00:00.000", Orders.completedAt: "2021-02-
12T00:00:00.000", Orders.count: "5", Products.count: "5", LineItems.count: "11", …}
1: {Orders.completedAt.day: "2021-02-13T00:00:00.000", Orders.completedAt: "2021-02-
13T00:00:00.000", Orders.count: "7", Products.count: "7", LineItems.count: "15", …}
2: {Orders.completedAt.day: "2021-02-14T00:00:00.000", Orders.completedAt: "2021-02-
14T00:00:00.000", Orders.count: "8", Products.count: "8", LineItems.count: "15", …}
3: {Orders.completedAt.day: "2021-02-15T00:00:00.000", Orders.completedAt: "2021-02-
15T00:00:00.000", Orders.count: "6", Products.count: "6", LineItems.count: "15", …}
4: {Orders.completedAt.day: "2021-02-16T00:00:00.000", Orders.completedAt: "2021-02-
16T00:00:00.000", Orders.count: "6", Products.count: "6", LineItems.count: "11", …}
5: {Orders.completedAt.day: "2021-02-17T00:00:00.000", Orders.completedAt: "2021-02-
17T00:00:00.000", Orders.count: "6", Products.count: "6", LineItems.count: "12", …}
6: {Orders.completedAt.day: "2021-02-18T00:00:00.000", Orders.completedAt: "2021-02-
18T00:00:00.000", Orders.count: "5", Products.count: "5", LineItems.count: "8", …}
7: {Orders.completedAt.day: "2021-02-19T00:00:00.000", Orders.completedAt: "2021-02-
19T00:00:00.000", Orders.count: "4", Products.count: "4", LineItems.count: "8", …}
8: {Orders.completedAt.day: "2021-02-20T00:00:00.000", Orders.completedAt: "2021-02-
20T00:00:00.000", Orders.count: "5", Products.count: "5", LineItems.count: "15", …}
9: {Orders.completedAt.day: "2021-02-21T00:00:00.000", Orders.completedAt: "2021-02-
21T00:00:00.000", Orders.count: "5", Products.count: "5", LineItems.count: "5", …}
10: {Orders.completedAt.day: "2021-02-22T00:00:00.000", Orders.completedAt: "2021-02-
22T00:00:00.000", Orders.count: "6", Products.count: "6", LineItems.count: "14", …}
11: {Orders.completedAt.day: "2021-02-23T00:00:00.000", Orders.completedAt: "2021-02-
23T00:00:00.000", Orders.count: "1", Products.count: "1", LineItems.count: "2", …}
12: {Orders.completedAt.day: "2021-02-24T00:00:00.000", Orders.completedAt: "2021-02-
24T00:00:00.000", Orders.count: "10", Products.count: "10", LineItems.count: "20", …}
13: {Orders.completedAt.day: "2021-02-25T00:00:00.000", Orders.completedAt: "2021-02-
25T00:00:00.000", Orders.count: "9", Products.count: "9", LineItems.count: "22", …}
14: {Orders.completedAt.day: "2021-02-26T00:00:00.000", Orders.completedAt: "2021-02-
26T00:00:00.000", Orders.count: "5", Products.count: "5", LineItems.count: "14", …}
15: {Orders.completedAt.day: "2021-02-27T00:00:00.000", Orders.completedAt: "2021-02-
27T00:00:00.000", Orders.count: "3", Products.count: "3", LineItems.count: "6", …}
16: {Orders.completedAt.day: "2021-02-28T00:00:00.000", Orders.completedAt: "2021-02-
28T00:00:00.000", Orders.count: "6", Products.count: "6", LineItems.count: "13", …}
17: {Orders.completedAt.day: "2021-03-01T00:00:00.000", Orders.completedAt: "2021-03-
01T00:00:00.000", Orders.count: "1", Products.count: "1", LineItems.count: "1", …}
18: {Orders.completedAt.day: "2021-03-02T00:00:00.000", Orders.completedAt: "2021-03-
02T00:00:00.000", Orders.count: "9", Products.count: "9", LineItems.count: "21", …}
19: {Orders.completedAt.day: "2021-03-03T00:00:00.000", Orders.completedAt: "2021-03-
03T00:00:00.000", Orders.count: "5", Products.count: "5", LineItems.count: "10", …}
20: {Orders.completedAt.day: "2021-03-04T00:00:00.000", Orders.completedAt: "2021-03-
04T00:00:00.000", Orders.count: "3", Products.count: "3", LineItems.count: "3", …}
21: {Orders.completedAt.day: "2021-03-05T00:00:00.000", Orders.completedAt: "2021-03-
05T00:00:00.000", Orders.count: "5", Products.count: "5", LineItems.count: "10", …}
22: {Orders.completedAt.day: "2021-03-06T00:00:00.000", Orders.completedAt: "2021-03-
06T00:00:00.000", Orders.count: "5", Products.count: "5", LineItems.count: "14", …}
23: {Orders.completedAt.day: "2021-03-07T00:00:00.000", Orders.completedAt: "2021-03-
07T00:00:00.000", Orders.count: "4", Products.count: "4", LineItems.count: "7", …}
24: {Orders.completedAt.day: "2021-03-08T00:00:00.000", Orders.completedAt: "2021-03-
08T00:00:00.000", Orders.count: "4", Products.count: "2", LineItems.count: "5", …}
25: {Orders.completedAt.day: "2021-03-09T00:00:00.000", Orders.completedAt: "2021-03-
09T00:00:00.000", Orders.count: "8", Products.count: "8", LineItems.count: "17", …}
26: {Orders.completedAt.day: "2021-03-10T00:00:00.000", Orders.completedAt: "2021-03-
10T00:00:00.000", Orders.count: "6", Products.count: "6", LineItems.count: "10", …}
27: {Orders.completedAt.day: "2021-03-11T00:00:00.000", Orders.completedAt: "2021-03-
11T00:00:00.000", Orders.count: "1", Products.count: "1", LineItems.count: "2", …}
28: {Orders.completedAt.day: "2021-03-12T00:00:00.000", Orders.completedAt: "2021-03-
12T00:00:00.000", Orders.count: "4", Products.count: "4", LineItems.count: "5", …}
29: {Orders.completedAt.day: "2021-03-13T00:00:00.000", Orders.completedAt: "2021-03-
13T00:00:00.000", Orders.count: "6", Products.count: "6", LineItems.count: "10", …}
length: 30
__proto__: Array(0)
lastRefreshTime: "2021-03-14T09:28:12.152Z"
query: {measures: Array(7), timeDimensions: Array(1), dimensions: Array(0), segments:
Array(0), filters: Array(0), …}
slowQuery: false
__proto__: Object
__proto__: Object
barChart.js
import { useD3 } from './useD3';
import React from 'react';
import * as d3 from 'd3';
const productcount = 0
function BarChartD3({ data }) {
const ref = useD3(
(svg) => {
const height = 500;
const width = 500;
const margin = { top: 20, right: 30, bottom: 30, left: 40 };
const x = d3
.scaleBand()
.domain(data.map((d) => d.Orders.completedAt))
.rangeRound([margin.left, width - margin.right])
.padding(0.1);
const y1 = d3
.scaleLinear()
.domain([0, d3.max(data, (d) => d.Orders.totalAmount || productcount)])
.rangeRound([height - margin.bottom, margin.top]);
const xAxis = (g) =>
g.attr("transform", `translate(0,${height - margin.bottom})`).call(
d3
.axisBottom(x)
.tickValues(
d3
.ticks(...d3.extent(x.domain()), width / 40)
.filter((v) => x(v) !== undefined)
)
.tickSizeOuter(0)
);
const y1Axis = (g) =>
g
.attr("transform", `translate(${margin.left},0)`)
.style("color", "steelblue")
.call(d3.axisLeft(y1).ticks(null, "s"))
.call((g) => g.select(".domain").remove())
.call((g) =>
g
.append("text")
.attr("x", -margin.left)
.attr("y", 10)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.text(data.y1)
);
svg.select(".x-axis").call(xAxis);
svg.select(".y-axis").call(y1Axis);
svg.select(".plot-area")
.attr("fill", "steelblue")
.selectAll(".bar")
.data(data)
.join("rect")
.attr("class", "bar")
.attr("x", (d) => x(d.Orders.completedAt))
.attr("width", x.bandwidth())
.attr("y", (d) => y1(d.Orders.totalAmount || productcount))
.attr("height", (d) => y1(0) - y1(d.Orders.totalAmount || productcount));
},
[data.length]
);
return (
<svg
ref={ref}
style={{
height: 500,
width: "100%",
marginRight: "0px",
marginLeft: "0px",
}}
>
<g className="plot-area" />
<g className="x-axis" />
<g className="y-axis" />
</svg>
);
}
export default BarChartD3;
从“/useD3”导入{useD3};
从“React”导入React;
从“d3”导入*作为d3;
const productcount=0
函数BarChartD3({data}){
常数ref=useD3(
(svg)=>{
常数高度=500;
常数宽度=500;
常量边距={顶部:20,右侧:30,底部:30,左侧:40};
常数x=d3
.scaleBand()
.domain(data.map((d)=>d.Orders.completedAt))
.rangeRound([margin.left,width-margin.right])
.填充(0.1);
常数y1=d3
.scaleLinear()
.domain([0,d3.max(数据,(d)=>d.Orders.totalAmount | | productcount)])
.rangeRound([高度-边距.底部,边距.顶部]);
常数xAxis=(g)=>
g、 attr(“transform”,`translate(0,${height-margin.bottom})`)。调用(
d3
.axisBottom(x)
.价值观(
d3
.ticks(…d3.extent(x.domain()),宽度/40)
.过滤器((v)=>x(v)!==未定义)
)
.滴答器(0)
);
常数Y轴=(g)=>
G
.attr(“transform”,translate(${margin.left},0)`)
.风格(“颜色”、“钢蓝色”)
.call(d3.axisLeft(y1.ticks)(null,“s”))
.call((g)=>g.select(“.domain”).remove())
.呼叫((g)=>
G
.append(“文本”)
.attr(“x”,-页边距。左)
.attr(“y”,10)
.attr(“填充”、“当前颜色”)
.attr(“文本锚定”、“开始”)
.文本(数据.y1)
);
svg.select(“.x轴”).call(xAxis);
svg.选择(“.y轴”).调用(Y1轴);
svg.选择(“绘图区域”)
.attr(“填充”、“钢蓝”)
.selectAll(“.bar”)
.数据(数据)
.join(“rect”)
.attr(“类”、“条”)
.attr(“x”,(d)=>x(d.Orders.completedAt))
.attr(“宽度”,x.带宽())
.attr(“y”,(d)=>y1(d.Orders.totalAmount | | productcount))
.attr(“高度”,(d)=>y1(0)-y1(d.Orders.totalAmount | | productcount));
},
[数据长度]
);
返回(
);
}
导出默认条形图3;
图表组件
import React from "react";
import * as d3 from "d3";
import PropTypes from "prop-types";
import { useCubeQuery } from "@cubejs-client/react";
import { Spin, Row, Col, Statistic, Table } from "antd";
import {
CartesianGrid,
PieChart,
Pie,
Cell,
AreaChart,
Area,
ZAxis,
XAxis,
Scatter,
YAxis,
Tooltip,
ResponsiveContainer,
Legend,
BarChart,
ScatterChart,
Bar,
LineChart,
Line
} from "recharts";
import PieSVG from './PieSVG'
import styled from 'styled-components';
import "./recharts-theme.less";
import moment from "moment";
import numeral from "numeral";
import PieChartD3 from "./pieChartd3";
import PieHooks from "./pieHooks";
import BarChartData from './BarChartData';
import BarChartD3 from './BarChart';
import BubbleChartData from './BubbleChartData';
import TreemapD3 from "./TreeContainer";
// import {Treemap} from './Treemap';
import LineChartD3 from './LineChart';
// import BarChartD3 from './BarChart';
const numberFormatter = item => numeral(item).format("0,0");
const dateFormatter = item => moment(item).format("MMM YY");
const colors = ["#7DB3FF", "#49457B", "#FF7C78"];
const xAxisFormatter = (item) => {
if (moment(item).isValid()) {
return dateFormatter(item)
} else {
return item;
}
}
const CartesianChart = ({ resultSet, children, ChartComponent, height }) => (
<ResponsiveContainer width="100%" height={height}>
<ChartComponent margin={{ left: -10 }} data={resultSet.chartPivot()}>
<XAxis axisLine={false} tickLine={false} tickFormatter={xAxisFormatter} dataKey="x" minTickGap={20} />
<YAxis axisLine={false} tickLine={false} tickFormatter={numberFormatter} />
<CartesianGrid vertical={false} />
{children}
<Legend />
<Tooltip labelFormatter={dateFormatter} formatter={numberFormatter} />
</ChartComponent>
</ResponsiveContainer>
)
const TypeToChartComponent = {
line: ({ resultSet, height }) => (
<CartesianChart resultSet={resultSet} height={height} ChartComponent={LineChart}>
{resultSet.seriesNames().map((series, i) => (
<Line
key={series.key}
stackId="a"
dataKey={series.key}
name={series.title}
stroke={colors[i]}
/>
))}
</CartesianChart>
),
bar: ({ resultSet, height }) => (
<CartesianChart resultSet={resultSet} height={height} ChartComponent={BarChart}>
{resultSet.seriesNames().map((series, i) => (
<Bar
key={series.key}
stackId="a"
dataKey={series.key}
name={series.title}
fill={colors[i]}
/>
))}
</CartesianChart>
),
area: ({ resultSet, height }) => (
<CartesianChart resultSet={resultSet} height={height} ChartComponent={AreaChart}>
{resultSet.seriesNames().map((series, i) => (
<Area
key={series.key}
stackId="a"
dataKey={series.key}
name={series.title}
stroke={colors[i]}
fill={colors[i]}
/>
))}
</CartesianChart>
),
pie: ({ resultSet, height }) => (
<ResponsiveContainer width="100%" height={height}>
<PieChart>
<Pie
isAnimationActive={false}
data={resultSet.chartPivot()}
nameKey="x"
dataKey={resultSet.seriesNames()[0].key}
fill="#8884d8"
>
{resultSet.chartPivot().map((e, index) => (
<Cell key={index} fill={colors[index % colors.length]} />
))}
</Pie>
<Legend />
<Tooltip />
</PieChart>
</ResponsiveContainer>
),
table: ({ resultSet }) => (
<Table
pagination={false}
columns={resultSet.tableColumns().map(c => ({ ...c, dataIndex: c.key }))}
dataSource={resultSet.tablePivot()}
/>
),
number: ({ resultSet }) => (
<Row
type="flex"
justify="center"
align="middle"
style={{
height: "100%"
}}
>
<Col>
{resultSet.seriesNames().map(s => (
<Statistic value={resultSet.totalRow()[s.key]} />
))}
</Col>
</Row>
),
bubble: ({ resultSet, height }) => (
<CartesianChart resultSet={resultSet} height={height} ChartComponent={ScatterChart}>
{resultSet.seriesNames().map((series, i) => (
<Scatter
key={series.key}
stackId="a"
dataKey={series.key}
name={series.title}
stroke={colors[i]}
/>
))}
</CartesianChart>
),
// pied3: ({ resultSet,height }) => (
// <CartesianChart resultSet={resultSet} height={height} ChartComponent={PieSVG}>
// {resultSet.seriesNames().map((series, i) => (
// <PieSVG
// data={data}
// width={200}
// height={200}
// innerRadius={60}
// outerRadius={100}
// />
// ))}
// </CartesianChart>
// ),
// pied3:({ resultSet,height,}) => (
// <ResponsiveContainer width="100%" height={height}>
// <PieSVG
// data={resultSet.chartPivot()}
// dataKey={resultSet.seriesNames()[0].key}
// />
// </ResponsiveContainer>
// ),
pied3: ({ resultSet, height }) => (
<ResponsiveContainer width="100%" height={height}>
<PieChartD3 data={[40, 100]}
// key={resultSet.seriesNames()[0].key}
/>
</ResponsiveContainer>
),
// bard3:({ resultSet, height }) => (
// <CartesianChart resultSet={resultSet} height={height} ChartComponent={BarChartData}>
// {resultSet.seriesNames().map((series, i) => (
// <BarChartData />
// ))}
// </CartesianChart>
// ),
bard3: ({ resultSet, height }) => (
<ResponsiveContainer width="100%" height={height}>
<BarChartD3 data={resultSet.loadResponse.data} />
</ResponsiveContainer>
),
bubbled3: ({ resultSet, height }) => (
<ResponsiveContainer width="100%" height={height}>
<BubbleChartData />
</ResponsiveContainer>
),
lined3: ({ height }) => (
<ResponsiveContainer width="100%" height={height}>
<LineChartD3 />
</ResponsiveContainer>
)
// treed3:({}) => (
// <TreemapD3 Graphic={Treemap} url = "https://raw.githubusercontent.com/noe-lc/about-me/master/src/data/product_data.csv"/>
// )
// pied3:({resultSet, height}) => (
// <ResponsiveContainer width="100%" height={height}>
// <PieHooks
// data={[100,200,50,45]}
// width={100}
// height={height}
// innerRadius={0}
// outerRadius={100}
// />
// </ResponsiveContainer>
// ),
};
const TypeToMemoChartComponent = Object.keys(TypeToChartComponent)
.map(key => ({
[key]: React.memo(TypeToChartComponent[key])
}))
.reduce((a, b) => ({ ...a, ...b }));
const SpinContainer = styled.div`
text-align: center;
padding: 30px 50px;
margin-top: 30px;
`
const Spinner = () => (
<SpinContainer>
<Spin size="large" />
</SpinContainer>
)
const renderChart = Component => ({ resultSet, error, height }) =>
(resultSet && <Component height={height} resultSet={resultSet} />) ||
(error && error.toString()) || <Spinner />;
const ChartRenderer = ({ vizState, chartHeight }) => {
const { query, chartType } = vizState;
const component = TypeToMemoChartComponent[chartType];
const renderProps = useCubeQuery(query);
return component && renderChart(component)({ height: chartHeight, ...renderProps });
};
ChartRenderer.propTypes = {
vizState: PropTypes.object,
cubejsApi: PropTypes.object
};
ChartRenderer.defaultProps = {
vizState: {},
chartHeight: 300,
cubejsApi: null
};
export default ChartRenderer;
从“React”导入React;
从“d3”导入*作为d3;
从“道具类型”导入道具类型;
从“@cubejs-client/react”导入{useCubeQuery}”;
从“antd”导入{Spin,Row,Col,Statistic,Table};
进口{
CartesianGrid,
皮查特,
馅饼
细胞,
面积图,
地区
扎克西斯,
XAxis,
分散
亚克斯,
工具提示,
响应容器,
传奇
柱状图,
散点图,
酒吧,
线条图,
线
}来自“雷哈特”;
从“/PieSVG”导入PieSVG
从“样式化组件”导入样式化;
导入“/recharts theme.less”;
从“时刻”中导入时刻;
从“数字”中导入数字;
从“/PieChartD3”导入PieChartD3;
从“/PieHooks”导入PieHooks;
从“/BarChartData”导入BarChartData;
从“/BarChart”导入条形图3;
从“/BubbleChartData”导入BubbleChartData;
从“/TreeContainer”导入TreemapD3;
//从“/Treemap”导入{Treemap};
从“/LineChart”导入线形图3;
//从“/BarChart”导入条形图3;
常量numberFormatter=item=>数字(item).format(“0,0”);
const dateFormatter=item=>moment(item).format(“MMM-YY”);
常量颜色=[“7DB3FF”、“49457B”、“FF7C78”];
常量XaxiFormatter=(项)=>{
if(力矩(项).isValid()){
返回日期格式化程序(项目)
}否则{
退货项目;
}
}
常量CartesianChart=({resultSet,children,ChartComponent,height})=>(
{儿童}
)
常量TypeToChartComponent={
行:({resultSet,height})=>(
{resultSet.seriesNames().map((series,i)=>(
))}
),
条:({resultSet,height})=>(
{resultSet.seriesNames().map((series,i)=>(
))}
),
区域:({resultSet,height})=>(
{resultSet.seriesNames().map((series,i)=>(
))}
),
饼图:({resultSet,height})=>(
{resultSet.chartPivot().map((e,索引)=>(
))}
),
表:({resultSet})=>(
({…c,dataIndex:c.key})的
dataSource={resultSet.tablePivot()}
/>
),
编号:({resultSet})=>(
{resultSet.seriesNames().map(s=>(
))}
),
气泡:({resultSet,height})=>(
{resultSet.seriesNames().map((series,i)=>(
))}
),
//pied3:({resultSet,height})=>(
//
//{resultSet.seriesNames().map((series,i)=>(
//
// ))}
//
// ),
//pied3:({resultSet,height,})=>(
//
//
//
// ),
pied3:({resultSet,height})=>(
),
//bard3:({resultSet,height})=>(
//
//{resultSet.seriesNames().map((series,i)=>(
//
// ))}
//
// ),
bard3:({resultSet,height})=>(