Closed joyguy55 closed 6 years ago
Hi, I don't understand your problem. I made this example showing how it works, and I think that is ok...
https://beta.observablehq.com/@rveciana/d3-composite-projections-issue17
When I import albersUsa the appropriate paths come through but the scale function is undefined. in just looking at your node modules I see two definitions of GeoAlbers one with and one without scale. Is there a special way you are importing by any chance?
OK, then your problem is that you aren't loading the library properly, that's why is undefined. If you are loading the library directly from the html page, like here, use:
const projection = d3Projections.albersUsa.scale(1000);
If you want to use browserify:
var d3_composite = require("d3-composite-projections"); var projection = d3_composite.geoAlbersUsa();
Does it work with that?
Oh, now I see. I'll take a look.
Can you please tell me where do you see the different definitions of AlbersUsa? The ones at the src directory have both the scale function... Are you using ES6 with imports or the traditional browser html including all the library in a script tag?
I'm using ES6 with imports.
OK, now I see.
Change
const projection = d3Projections.albersUsa.scale(1000);
to
const projection = d3Projections.geoAlbersUsa().scale(1000);
It's working now?
d3Projections does not import like so
import { d3Projections } from 'd3-composite-projections';
It will always return undefined. I can however import like so
import { geoAlbersUsa } from 'd3-composite-projections';
However it will not render the map correctly it renders this weird box.
The only import that renders the map properly is
import { albersUsa } from from 'd3-composite-projections';
I made this example with react, like in this example, using the import style you said, and the result seems ok too... which is logical, because the functions are copies of the original d3 code.
Also, the strange squares are not the ones after calling .getCompositionBorders()
, right?
Maybe if you put a larger part of the code...
import logo from './logo.svg';
import { geoAlbersUsa } from 'd3-composite-projections';
import { geoPath } from "d3-geo"
import { feature } from "topojson-client"
import './App.css';
class App extends Component {
constructor() {
super()
this.state = {
worldData: [],
}
}
projection() {
return geoAlbersUsa()
.scale(1000)
.translate([ 800 / 2, 450 / 2 ])
}
componentDidMount() {
fetch("/us.json")
.then(response => {
if (response.status !== 200) {
console.log(`There was a problem: ${response.status}`)
return
}
response.json().then(worldData => {
this.setState({
worldData: feature(worldData, worldData.objects.states).features,
})
})
})
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<svg width={ 800 } height={ 450 } viewBox="0 0 800 450">
<g className="countries">
{
this.state.worldData.map((d,i) => (
<path
key={ `path-${ i }` }
d={ geoPath().projection(this.projection())(d) }
className="country"
fill={ `rgba(38,50,56,${1 / this.state.worldData.length * i})` }
stroke="#FFFFFF"
strokeWidth={ 0.5 }
/>
))
}
</g>
<g className="projBorders">
<path fill='None' stroke='#333' d={this.projection().getCompositionBorders()}/>
</g>
</svg>
</div>
);
}
}
export default App;
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import * as d3 from 'd3';
import { geoAlbersUsa } from 'd3-composite-projections';
import { geoPath } from "d3-geo"
import { feature } from 'topojson-client';
import { select } from 'd3-selection';
import ToolTip from './ToolTip'
import './UsMap.css';
class WorldMap extends Component {
constructor() {
super();
this.state = {
geojson: [],
toolTipIsOpen: false,
selectedState: {},
};
}
componentDidMount() {
fetch('https://d3js.org/us-10m.v1.json').then(response => {
if (response.status !== 200) {
console.log(`There was a problem: ${response.status}`);
return;
}
response
.json()
.then(usdata => {
this.setState({
geojson: feature(usdata, usdata.objects.states).features
});
});
});
this.createMap()
}
componentDidUpdate() {
this.createMap()
}
handleBlur = () => {
console.log('blurHandled')
this.setState({toolTipIsOpen: false})
}
handleToolTip = (state) => {
const selectedState = this.props.electionData.find((data)=>{
return data.State_GeoJson_ID === parseInt(state.id,0)
})
this.setState({
top: d3.event.pageY - 250,
left: d3.event.pageX > 700 ? d3.event.pageX - 513 : d3.event.pageX + 25,
toolTipIsOpen: true,
stateId: state.id,
selectedState,
})
}
createMap = () => {
const node = this.node;
const { geojson } = this.state;
const projection = geoAlbersUsa().scale(1000)
const path = geoPath().projection(projection)
select(node)
.selectAll('path')
.data(geojson)
.enter()
.append('path')
.attr('d', path)
.attr('class', 'state')
.style('stroke', '#fff')
.style('stroke-width', '1')
.on('click', this.handleToolTip.bind(this))
.on('mouseover', function(state) {
select(this).style('fill', 'grey');
})
.on('mouseout', function(state) {
select(this).style('fill', 'black');
})
}
// Can't use arrow functions on d3 events?
render() {
const { toolTipIsOpen, top, left, selectedState} = this.state
return (
<Fragment>
<svg
id="map"
ref={ node => {this.node = node}}
width={600}
height={600}
/>
{ toolTipIsOpen ?
<ToolTip
handleBlur={this.handleBlur}
top={top}
left={left}
selectedState={selectedState}
/> : <span/> }
</Fragment >
);
}
}
I imagine that your method is probably preferred. I was passing a ref to a node which is used when you want to retain control of d3 transitions. But I don't imagine needing too many transitions with the map.
Also you seem to be setting up a fetch method for getting your map from what appears to be a non usable url. Unless your fetching it locally? But then wouldn't you just import it directly? That might be why my map is rendering so funny if the JSON objects aren't identical.
![Uploading screen_shot.png…]()
Don't know if this matters but I get this odd warning notice in Visual Studio code regarding the node module. Sorry for the weird picture had to take it with my phone as it only appears when I am scrolling over the package.
I copied the example from this page and just changed the projection: https://medium.com/@zimrick/how-to-create-pure-react-svg-maps-with-topojson-and-d3-geo-e4a6b6848a98 So yes, many things could be different... I have never tried to do d3 transitions in react this way. The us.json file is stored in the public directory, but you are right. Actually, I saw some examples where the topojson is converted into an object and imported directly, since the data won't change. Here's another example that loads the file as in my case: https://medium.com/@zimrick/how-to-create-pure-react-svg-maps-with-topojson-and-d3-geo-e4a6b6848a98 Finally, I can't see any picture with the VS code warning! I understand that the projection worked well, by the way, ir you still have problems?
Yeah the fetch doesn't work.
componentDidMount() {
fetch("/us.json")
.then(response => {
if (response.status !== 200) {
console.log(`There was a problem: ${response.status}`)
return
}
response.json().then(worldData => {
this.setState({
worldData: feature(worldData, worldData.objects.states).features,
})
})
})
}
I think that this is an issue with the JSON file. Have you looked inside? The one I'm using is this one: https://bl.ocks.org/rveciana/raw/ee2119324e835e1bad42d0e4c1b9ab0d/us.json The error message says that the first position in the json is a <, which is invalid and seems the beginning of an HTML file or similar...
Ok I would suggest showing the source for that type of particular map. Because its obviously critical to your module I was using a completely different topojson map that wasn't working anyhow seems like a pretty critical point. Super thanks for you help.
You are welcome! It's true that the docs should be better, and adapted to React and the new stuff people is using.
I don't believe the scale works the way you imagined it would. Or maybe I'm confused about how you intended it to be called but it does not seem that clear.