问题
I have been on this for 10 hours now and I am starting to think that it is either something really small or something fundamental I am missing here.
This is a simple component that all I want is to render the us map with the d3 version 4 via geoAlbersUsa and PROJECT it in a panel so that it is SCALED. If I remove the projection all works great and I get the map. The moment in any shape or form I do the projection it simply shows a colored rectangle. Here is the code:
import React from 'react';
import * as d3 from 'd3';
import * as topojson from 'topojson';
import { Panel, Alert } from 'react-bootstrap';
class MapBlock extends React.Component {
constructor(props) {
super(props);
this.state = {
states: []
};
this.projection = d3.geoAlbersUsa().scale(1000);
this.geoPath = d3.geoPath().projection(this.projection);
}
componentDidMount() {
d3.json("https://d3js.org/us-10m.v1.json", function(error, us) {
if (error) throw error;
this.setState({states: topojson.feature(us, us.objects.states).features})
}.bind(this));
}
render() {
let { states } = this.state;
return (
<Panel>
<svg width="550" height="430">
<g className="states">
{
states.map((feature, index) => <path key={index} d={this.geoPath(feature)} />)
}
</g>
</svg>
</Panel>
)
}
}
export default MapBlock
The html is also pretty simple:
<Grid>
<Row className="show-grid">
<Col sm={12} md={6}>
<MapBlock />
</Col>
<Col sm={12} md={6}>
Some Text ...
</Col>
</Row>
</Grid>
Any help is appreciated and please let me know if the details are not enough. Thanks in advance.
UPDATE:
Here is what I get now trying to work with the suggestion from the initial comment from @Mark.
I tried something like this:
var states = topojson.feature(us, us.objects.states).features;
var width = 560;
var height = 300;
var b = path.bounds(states[0]),
s = .98 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
// Update the projection to use computed scale & translate.
projection
.scale(s)
.translate(t);
vis.selectAll("path")
.data(states)
.enter()
.append("path")
.attr("class", "states")
.attr("d", path);
For this I changed to render to be just:
<Panel>
<div id="vis"></div>
</Panel>
What I am not sure here is path.bounds(states[0])
was a guess of mine just so I can see if it would work based on the panel boundary I have. I did "scale" it as you can see from the image but I guess not exactly :)
回答1:
I just realized that d3
version 4 has an even easier way to fit a projection to a bounding space. They've introduced the fitSize method on the projection.
Here it is in action:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>jQuery UI Resizable - Default functionality</title>
<script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
<script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/topojson.v2.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" />
<style>
#resizable {
width: 150px;
height: 150px;
padding: 0.5em;
}
</style>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(function() {
$("#resizable").resizable({
resize: function(event, ui) {
drawMap(ui.size.width, ui.size.height);
}
});
var svg = d3.select("#resizable")
.append("svg"),
path = svg.append("path");
var states;
d3.json('https://jsonblob.com/api/9e44a352-eb09-11e6-90ab-059f7355ffbc', function(error, data) {
states = topojson.feature(data, data.objects.states);
drawMap(150, 150);
});
function drawMap(w, h) {
svg.attr('width', w)
.attr('height', h);
var projection = d3.geoAlbersUsa()
.scale(1).fitSize([w, h], states);
var geoPath = d3.geoPath().projection(projection);
path
.datum(states)
.attr("d", geoPath);
}
});
</script>
</head>
<body>
<div id="resizable" class="ui-widget-content"></div>
</body>
</html>
来源:https://stackoverflow.com/questions/42041148/reactjs-d3-v4-projection-issue