Reactjs + D3 v4投影问题

时间:2017-02-04 13:50:15

标签: reactjs d3.js projection topojson

我现在已经这样做了10个小时了,我开始认为它是一个非常小的东西或者我在这里缺少的东西。

这是一个简单的组件,我想要的是通过geoAlbersUsa渲染带有d3版本4的us地图,并在面板中将它PROJECT,以便它是SCALED。如果我删除投影,一切都很好,我得到了地图。任何形状或形式的时刻我做投影它只是显示一个彩色矩形。这是代码:

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

html也很简单:

<Grid>
    <Row className="show-grid">
        <Col sm={12} md={6}>
            <MapBlock />
        </Col>
        <Col sm={12} md={6}>
            Some Text ...
        </Col>
   </Row>
</Grid>

感谢任何帮助,如果细节不够,请告诉我。提前谢谢。

更新

以下是我现在尝试使用@Mark初始评论的建议。

enter image description here 我试过这样的事情:

 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);

为此,我改为渲染为:

<Panel>
    <div id="vis"></div>
</Panel>

我不确定这里path.bounds(states[0])是我的猜测,所以我可以看看它是否能够根据我的面板边界工作。我做了&#34;规模&#34;你可以从图像中看到它,但我猜不完全正确:))

1 个答案:

答案 0 :(得分:2)

我刚刚意识到d3版本4有一种更简单的方法可以将投影拟合到边界空间。他们在投影中引入了fitSize方法。

这是在行动:

<!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>