2017-02-04 48 views
1

Я был на этом в течение 10 часов, и я начинаю думать, что это что-то действительно маленькое или что-то фундаментальное, чего я здесь не хватает.Reactjs + D3 v4 проблема с проекцией

Это простой компонент, который я хочу сделать, чтобы отобразить карту с d3-версией 4 через geoAlbersUsa и ПРОЕКТА в панели, чтобы она была 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> 

любая помощь и, пожалуйста, дайте мне знать, если детали не достаточно. Заранее спасибо.

UPDATE:

Вот что я получаю сейчас пытается работать с предложением от первоначального комментария от @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]) была догадка моя просто поэтому я могу видеть, будет ли это работать на основе границы панели, которую у меня есть. Я сделал «масштабирование», как вы можете видеть по изображению, но я не думаю точно :)

+1

Похоже, что вы произвольно сорвала '.scale' 1000, но необходимо определить масштаб/перевод, который работает на карте и контейнер. См. Этот ответ [здесь] (http://stackoverflow.com/a/14691788/16363) – Mark

+0

Хм ... Я пробовал от 10 до 500 до 5000 ... даже @ наименьший, он просто показывает маленький прямоугольник внутри родитель. Но я проверю ссылку. Спасибо за ваш комментарий. Я ценю это. – Akrion

+0

Я догадываюсь, что я до сих пор не хватает ... вы полагаете, чтобы вычислить проекцию/переход один раз для всей карты или для каждого состояния карты geoAlbersUsa? И даже вы от вас все равно должны видеть какую-то форму, которая более или менее похожа на карту нас нет? Независимо от того, что я делаю до сих пор, я получаю только цветной прямоугольник независимо от масштаба/перехода, который я пытаюсь сделать. – Akrion

ответ

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="[email protected]" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script> 
 
    <script data-require="[email protected]" 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>

+0

Удивительный! Спасибо за вашу помощь. – Akrion

+0

Просто еще одно примечание ... Мне пришлось на самом деле вытащить версию 4.5 для fitSize ... У меня было 4.1.1, и он жаловался на отсутствие функции. Я сделал рефакторинг, чтобы теперь переключиться на fitSize. Еще раз спасибо! – Akrion

 Смежные вопросы

  • Нет связанных вопросов^_^