在我的REACT应用程序中,我正在阅读JSON响应(使用axis),我将使用react-faux-dom传递给组件,以尝试重新创建Mike Bostock的{{3} }(使用D3 v4)。
在我的组件中运行console.log(apiData)
会显示我期望的对象 - 但是,我已经尝试了我能想到的一切,我能得到的最好的是空X和Y轴(以及我的&# 34; scratchpad&#34; <g>
元素,我试图用它来了解我正在使用的内容。)
有人可以指导我做错了吗?
{
"roles": [
{
"AA": [
{
"date": "20150101",
"total": 6.0
},
{
"date": "20150201",
"total": 14.5
},
{
"date": "20150301",
"total": 14.5
}],
"AB": [
{
"date": "20150301",
"total": 1.6
},
{
"date": "20150401",
"total": 1.6
},
{
"date": "20150501",
"total": 7.24
}]
}]
}
App.js
文件:import React, { Component } from 'react';
import './App.css';
import axios from 'axios';
import { MyD3ReactComponentExport } from './D3Timeseries'
class App extends Component {
/* ... assign API response to "apiResponse" */
render() {
const {
apiResponse
} = this.state
return (
<div className="App">
<button onClick={this.requestData}>Refresh Data</button>
<MyD3ReactComponentExport apiData={apiResponse} />
</div>
);
}
}
import React from 'react'
import * as d3 from 'd3'
import PropTypes from 'prop-types'
import { withFauxDOM } from 'react-faux-dom'
class MyD3ReactComponent extends React.Component {
constructor (props) {
super(props)
this.renderD3 = this.renderD3.bind(this)
this.updateD3 = this.updateD3.bind(this)
}
componentDidMount () {
this.renderD3()
}
componentDidUpdate (prevProps, prevState) {
if (this.props.data !== prevProps.data) {
this.updateD3()
}
}
render () {
return (
<div>
<h2>Amazing timeseries:</h2>
{this.props.myChart}
</div>
)
}
renderD3() {
const {
apiData
} = this.props
let faux = this.props.connectFauxDOM('div', 'myChart');
let svg = d3.select(faux).append('svg')
.attr("width",960)
.attr("height",500);
let margin = {top: 20, right: 80, bottom: 30, left: 50},
width = svg.attr("width") - margin.left - margin.right,
height = svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
let parseTime = d3.timeParse("%Y%m%d");
let x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
let line = d3.line()
.curve(d3.curveBasis)
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.total); });
// ----- PASS apiData RESPONSE OBJECT INTO HERE ------
if (apiData) {
console.log( apiData )
x.domain(d3.extent( d3.map(apiData.roles, function(d) { return parseTime(d.date) }) ));
y.domain([
d3.min( apiData.roles, function(c) { return d3.min(c, function(d) { return d.total; }); }),
d3.max( apiData.roles, function(c) { return d3.max(c, function(d) { return d.total; }); }),
]);
z.domain( Object.keys(apiData) );
g.append("text").attr("y",height/3).attr("x", width/3).text( ">>>" + apiData.roles.map( function(d) { d }).map(function (e) { return e } ).map(function (f) { return f } ) + "<<<" ) ;
} else {
g.append("text").attr("y",height/2).attr("x", width/2).text( "No API DATA!!!" );
}
// ----Everything below here is 'stock' Bostock D3 code
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0,"+ height +")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("fill", "#000")
.text("Total resource");
let city = g.selectAll(".city")
.data(apiData)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return z(d.id); });
city.append("text")
.datum(function(d) { return {id: d.key, value: d.values[d.values.length - 1]}; })
.attr("transform", function(r) { return function(d) { return "translate(" + x(d.date) + "," + y(d.total) + ")"; } })
.attr("x", 3)
.attr("dy", "0.35em")
.style("font", "10px sans-serif")
.text(function(d) { return d.id; });
// function type(d, _, columns) {
// d.date = parseTime(d.date);
// for (var i = 1, n = columns.length, c; i < n; ++i) d[c = columns[i]] = +d[c];
// return d;
// }
}
updateD3() {
this.props.animateFauxDOM(800)
d3.select('text').text(this.props.title)
}
}
MyD3ReactComponent.defaultProps = {
myChart: 'loading'
};
MyD3ReactComponent.propTypes = {
// title: PropTypes.string.isRequired,
apiData: PropTypes.object.isRequired
}
const MyD3ReactComponentExport = withFauxDOM(MyD3ReactComponent);
export { MyD3ReactComponentExport }
答案 0 :(得分:0)
设置域名的问题在于,roles
数组包含您尝试map
的对象,找到d3.min
并查找导致d3.max
的{{1}} 无效值,因为这些功能仅适用于ARRAYS。
例如,
y.domain([
d3.min( apiData.roles, function(c) { return d3.min(c, function(d) { return d.total; }); }),
d3.max( apiData.roles, function(c) { return d3.max(c, function(d) { return d.total; }); }),
]);
在上述方案中,使用apiData
变量c
是min
,max
无法应用的对象。
建议:尽可能多地使用console.log并使用Chrome控制台或任何调试器添加断点。
为了做到这一点,我首先按以下方式格式化数据:
// format data
var data = [];
apiData.roles.forEach(function(d) {
var keys = Object.keys(d);
keys.forEach(function(k) {
data.push({key: k, values: d[k]});
})
});
这是新格式化数据的外观:
[
{
"key": "AA",
"values": [
{
"date": "20150101",
"total": 6
},
{
"date": "20150201",
"total": 14.5
},
{
"date": "20150301",
"total": 14.5
}
]
},
{
"key": "AB",
"values": [
{
"date": "20150301",
"total": 1.6
},
{
"date": "20150401",
"total": 1.6
},
{
"date": "20150501",
"total": 7.24
}
]
}
]
使用这些数据,图表可以按如下方式创建:(我已经注释掉了文本部分:请使用格式化的数据来解决这个问题)
var apiData = {
"roles": [
{
"AA": [
{
"date": "20150101",
"total": 6.0
},
{
"date": "20150201",
"total": 14.5
},
{
"date": "20150301",
"total": 14.5
}
],
"AB": [
{
"date": "20150301",
"total": 1.6
},
{
"date": "20150401",
"total": 1.6
},
{
"date": "20150501",
"total": 7.24
}]
}]
};
// format data
var data = [];
apiData.roles.forEach(function(d) {
var keys = Object.keys(d);
keys.forEach(function(k) {
data.push({key: k, values: d[k]});
})
});
//console.log(data);
let svg = d3.select('div#chart').append('svg')
.attr("width",960)
.attr("height",500);
let margin = {top: 20, right: 80, bottom: 30, left: 50},
width = svg.attr("width") - margin.left - margin.right,
height = svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
let parseTime = d3.timeParse("%Y%m%d");
let x = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
let line = d3.line()
.curve(d3.curveBasis)
.x(function(d) {
return x(parseTime(d.date));
})
.y(function(d) { return y(d.total); });
// ----- PASS apiData RESPONSE OBJECT INTO HERE ------
if (apiData) {
// console.log( apiData )
x.domain([
d3.min( data, function(c) { return d3.min(c.values, function(d) { return parseTime(d.date); }); }),
d3.max( data, function(c) { return d3.max(c.values, function(d) { return parseTime(d.date); }); })
]);
// console.log(x.domain());
y.domain([
d3.min( data, function(c) { return d3.min(c.values, function(d) { return +d.total; }); }),
d3.max( data, function(c) { return d3.max(c.values, function(d) { return +d.total; }); }),
]);
//console.log(y.domain());
z.domain( data.map(function(d) { return d.key; }) );
/* g.append("text").attr("y",height/3).attr("x", width/3).text( ">>>" + apiData.roles.map( function(d) { d }).map(function (e) { return e } ).map(function (f) { return f } ) + "<<<" ) ; */
// ----Everything below here is 'stock' Bostock D3 code
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0,"+ height +")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("fill", "#000")
.text("Total resource");
let city = g.selectAll(".city")
.data(data)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return z(d.key); });
/* city.append("text")
.datum(function(d) { return {id: d.key, value: d.values[d.values.length - 1]}; })
.attr("transform", function(r) {
return function(d) { return "translate(" + x(d.date) + "," + y(d.total) + ")"; } })
.attr("x", 3)
.attr("dy", "0.35em")
.style("font", "10px sans-serif")
.text(function(d) { return d.key; }); */
} else {
g.append("text").attr("y",height/2).attr("x", width/2).text( "No API DATA!!!" );
}
.city path {
fill: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="chart">
</div>
希望这会有所帮助。 :)