如何在 Leaflet 地图上以图形方式映射 JSON 数据?
How to map JSON data graphically on a Leaflet map?
我想使用 Citybik.es API (http://api.citybik.es/) 在 Leaflet 地图上显示数据。
如何在 JSON 的地图上实现此数据? 我已经在 componentDidMount()
中从 API 获取信息,但我不知道如何将这些数据放入地图中。
响应看起来像这样:
{
"networks": [
{
"company": [
"Bike U Sp. z o.o."
],
"href": "/v2/networks/bbbike",
"id": "bbbike",
"location": {
"city": "Bielsko-Bia\u0142a",
"country": "PL",
"latitude": 49.8225,
"longitude": 19.044444
},
"name": "BBBike"
},
{
"company": [
"PBSC",
"Alta Bicycle Share, Inc"
],
"href": "/v2/networks/melbourne-bike-share",
"id": "melbourne-bike-share",
"location": {
"city": "Melbourne",
"country": "AU",
"latitude": -37.814107,
"longitude": 144.96328
},
"name": "Melbourne Bike Share"
}
}
感谢您的帮助!
import React, { Component } from 'react';
import L from 'leaflet';
import { Map, TileLayer, Marker, Popup } from 'react-leaflet';
// code for map marker icon
var myIcon = L.icon({
iconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAFgUlEQVR4Aa1XA5BjWRTN2oW17d3YaZtr2962HUzbDNpjszW24mRt28p47v7zq/bXZtrp/lWnXr337j3nPCe85NcypgSFdugCpW5YoDAMRaIMqRi6aKq5E3YqDQO3qAwjVWrD8Ncq/RBpykd8oZUb/kaJutow8r1aP9II0WmLKLIsJyv1w/kqw9Ch2MYdB++12Onxee/QMwvf4/Dk/Lfp/i4nxTXtOoQ4pW5Aj7wpici1A9erdAN2OH64x8OSP9j3Ft3b7aWkTg/Fm91siTra0f9on5sQr9INejH6CUUUpavjFNq1B+Oadhxmnfa8RfEmN8VNAsQhPqF55xHkMzz3jSmChWU6f7/XZKNH+9+hBLOHYozuKQPxyMPUKkrX/K0uWnfFaJGS1QPRtZsOPtr3NsW0uyh6NNCOkU3Yz+bXbT3I8G3xE5EXLXtCXbbqwCO9zPQYPRTZ5vIDXD7U+w7rFDEoUUf7ibHIR4y6bLVPXrz8JVZEql13trxwue/uDivd3fkWRbS6/IA2bID4uk0UpF1N8qLlbBlXs4Ee7HLTfV1j54APvODnSfOWBqtKVvjgLKzF5YdEk5ewRkGlK0i33Eofffc7HT56jD7/6U+qH3Cx7SBLNntH5YIPvODnyfIXZYRVDPqgHtLs5ABHD3YzLuespb7t79FY34DjMwrVrcTuwlT55YMPvOBnRrJ4VXTdNnYug5ucHLBjEpt30701A3Ts+HEa73u6dT3FNWwflY86eMHPk+Yu+i6pzUpRrW7SNDg5JHR4KapmM5Wv2E8Tfcb1HoqqHMHU+uWDD7zg54mz5/2BSnizi9T1Dg4QQXLToGNCkb6tb1NU+QAlGr1++eADrzhn/u8Q2YZhQVlZ5+CAOtqfbhmaUCS1ezNFVm2imDbPmPng5wmz+gwh+oHDce0eUtQ6OGDIyR0uUhUsoO3vfDmmgOezH0mZN59x7MBi++WDL1g/eEiU3avlidO671bkLfwbw5XV2P8Pzo0ydy4t2/0eu33xYSOMOD8hTf4CrBtGMSoXfPLchX+J0ruSePw3LZeK0juPJbYzrhkH0io7B3k164hiGvawhOKMLkrQLyVpZg8rHFW7E2uHOL888IBPlNZ1FPzstSJM694fWr6RwpvcJK60+0HCILTBzZLFNdtAzJaohze60T8qBzyh5ZuOg5e7uwQppofEmf2++DYvmySqGBuKaicF1blQjhuHdvCIMvp8whTTfZzI7RldpwtSzL+F1+wkdZ2TBOW2gIF88PBTzD/gpeREAMEbxnJcaJHNHrpzji0gQCS6hdkEeYt9DF/2qPcEC8RM28Hwmr3sdNyht00byAut2k3gufWNtgtOEOFGUwcXWNDbdNbpgBGxEvKkOQsxivJx33iow0Vw5S6SVTrpVq11ysA2Rp7gTfPfktc6zhtXBBC+adRLshf6sG2RfHPZ5EAc4sVZ83yCN00Fk/4kggu40ZTvIEm5g24qtU4KjBrx/BTTH8ifVASAG7gKrnWxJDcU7x8X6Ecczhm3o6YicvsLXWfh3Ch1W0k8x0nXF+0fFxgt4phz8QvypiwCCFKMqXCnqXExjq10beH+UUA7+nG6mdG/Pu0f3LgFcGrl2s0kNNjpmoJ9o4B29CMO8dMT4Q5ox8uitF6fqsrJOr8qnwNbRzv6hSnG5wP+64C7h9lp30hKNtKdWjtdkbuPA19nJ7Tz3zR/ibgARbhb4AlhavcBebmTHcFl2fvYEnW0ox9xMxKBS8btJ+KiEbq9zA4RthQXDhPa0T9TEe69gWupwc6uBUphquXgf+/FrIjweHQS4/pduMe5ERUMHUd9xv8ZR98CxkS4F2n3EUrUZ10EYNw7BWm9x1GiPssi3GgiGRDKWRYZfXlON+dfNbM+GgIwYdwAAAAASUVORK5CYII=',
iconSize: [25, 41],
iconAnchor: [12.5, 41],
popupAnchor: [0, -41]
});
class App extends Component {
state = {
location: {
lat: 51.505,
lng: -0.09,
},
haveUsersLocation: false,
zoom: 2,
networks: null
}
//lifecycle method to get the user's current position(if they so desire).
componentDidMount() {
fetch('https://api.citybik.es/v2/networks')
.then(res => res.json())
.then(response => {
console.log("response", response);
console.log(response.networks)
const networkData = response.networks
const networkList = networkData.map((data) => {
console.log(data);
})
})
navigator.geolocation.getCurrentPosition((position) => {
this.setState({
location: {
lat: position.coords.latitude,
lng: position.coords.longitude
},
haveUsersLocation: true,
zoom: 13
});
}, () => {
console.log('Uops! The user didnt give its location!');
fetch('https://ipapi.co/json')
.then(res => res.json())
.then(location => {
this.setState({
location: {
lat: location.latitude,
lng: location.longitude
},
haveUsersLocation: true,
zoom: 13
});
})
});
}
render() {
const position = [this.state.location.lat, this.state.location.lng]
return (
<Map className="map" center={position} zoom={this.state.zoom}>
<TileLayer
attribution="&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{
this.state.haveUsersLocation ?
<Marker
position={position}
icon={myIcon}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker> : ''
}
</Map>
)
}
}
ReactDOM.render(<App/>,
document.getElementById('root')
);
body {
margin: 0px;
width: 100vw;
height: 100vh;
}
#root {
height: 100%;
}
.map {
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<link href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css" rel="stylesheet"/>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<title>Leaflet map</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
您必须渲染多个 Marker
元素。目前,如果您有当前用户位置,您正在渲染一个 Marker
。以类似的方式,我们将遍历其他坐标并渲染它们。
在您的 componentDidMount
中,将您收到的回复保存到状态
fetch('https://api.citybik.es/v2/networks')
.then(res => res.json())
.then(response => {
console.log("response", response);
console.log(response.networks)
const networkData = response.networks
const networkList = networkData.map((data) => {
this.setState({ bikeData: data });
})
})
然后在您的 render
方法中,遍历 bikeData
并呈现 Markers
.
<Map className="map" center={position} zoom={this.state.zoom}>
<TileLayer
attribution="&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{
this.state.haveUsersLocation ?
<Marker
position={position}
icon={myIcon}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker> : ''
}
{
this.state.bikeData &&
this.state.bikeData.networks.map((idx, data) => (
<Marker key={data.id} position={[data.location.latitude, data.location.longitude]}> <Popup> Name: {data.name} </Popup> </Marker>))
}
</Map>
您最好将输出 JSON 重新格式化为 GeoJSON,然后使用 Leaflet 和 Mapbox 在地图上绘制对象会非常简单。
示例:
https://gist.github.com/arfeo/3580f3796a31ca95b7cf30b99bfd6be5
const openJsonFile = (file) => {
return new Promise(function(resolve, reject) {
const _ = new XMLHttpRequest();
_.overrideMimeType("application/json");
_.open("GET", file, true);
_.onload = function() {
if(this.readyState == 4) {
if(this.status >= 200 && this.status < 300) {
resolve(_.responseText);
} else {
reject(_.statusText);
}
}
};
_.onerror = function () {
reject(_.statusText);
};
_.send();
});
};
// Create a map
const map = L.map('map').setView([55.92, 37.83], 12);
// Add Mapbox tiles to map
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoiYXJmZW8iLCJhIjoiY2pjeGw5bG5nMTF5ZjMzczZoZWVzbWdyNSJ9.Yh3u2uEHErWpTvAg3Ak_qw', {
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
maxZoom: 20,
id: 'mapbox.streets',
accessToken: 'pk.eyJ1IjoiYXJmZW8iLCJhIjoiY2pjeGw5bG5nMTF5ZjMzczZoZWVzbWdyNSJ9.Yh3u2uEHErWpTvAg3Ak_qw'
}).addTo(map);
// Open and parse heojson file
openJsonFile("output.geojson")
.then(function(json) {
const data = JSON.parse(json);
// Draw GeoJSON features on map
for(const feature of data.features) {
const x = L.geoJSON(feature).addTo(map);
// If a feature is Point, add a popup (if applicable)
if(feature.geometry.type === "Point")
x.bindPopup((name = feature.properties.name) ? name : null);
}
})
.catch(function(error) {
console.error("Error:", error);
});
我想使用 Citybik.es API (http://api.citybik.es/) 在 Leaflet 地图上显示数据。
如何在 JSON 的地图上实现此数据? 我已经在 componentDidMount()
中从 API 获取信息,但我不知道如何将这些数据放入地图中。
响应看起来像这样:
{
"networks": [
{
"company": [
"Bike U Sp. z o.o."
],
"href": "/v2/networks/bbbike",
"id": "bbbike",
"location": {
"city": "Bielsko-Bia\u0142a",
"country": "PL",
"latitude": 49.8225,
"longitude": 19.044444
},
"name": "BBBike"
},
{
"company": [
"PBSC",
"Alta Bicycle Share, Inc"
],
"href": "/v2/networks/melbourne-bike-share",
"id": "melbourne-bike-share",
"location": {
"city": "Melbourne",
"country": "AU",
"latitude": -37.814107,
"longitude": 144.96328
},
"name": "Melbourne Bike Share"
}
}
感谢您的帮助!
import React, { Component } from 'react';
import L from 'leaflet';
import { Map, TileLayer, Marker, Popup } from 'react-leaflet';
// code for map marker icon
var myIcon = L.icon({
iconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAFgUlEQVR4Aa1XA5BjWRTN2oW17d3YaZtr2962HUzbDNpjszW24mRt28p47v7zq/bXZtrp/lWnXr337j3nPCe85NcypgSFdugCpW5YoDAMRaIMqRi6aKq5E3YqDQO3qAwjVWrD8Ncq/RBpykd8oZUb/kaJutow8r1aP9II0WmLKLIsJyv1w/kqw9Ch2MYdB++12Onxee/QMwvf4/Dk/Lfp/i4nxTXtOoQ4pW5Aj7wpici1A9erdAN2OH64x8OSP9j3Ft3b7aWkTg/Fm91siTra0f9on5sQr9INejH6CUUUpavjFNq1B+Oadhxmnfa8RfEmN8VNAsQhPqF55xHkMzz3jSmChWU6f7/XZKNH+9+hBLOHYozuKQPxyMPUKkrX/K0uWnfFaJGS1QPRtZsOPtr3NsW0uyh6NNCOkU3Yz+bXbT3I8G3xE5EXLXtCXbbqwCO9zPQYPRTZ5vIDXD7U+w7rFDEoUUf7ibHIR4y6bLVPXrz8JVZEql13trxwue/uDivd3fkWRbS6/IA2bID4uk0UpF1N8qLlbBlXs4Ee7HLTfV1j54APvODnSfOWBqtKVvjgLKzF5YdEk5ewRkGlK0i33Eofffc7HT56jD7/6U+qH3Cx7SBLNntH5YIPvODnyfIXZYRVDPqgHtLs5ABHD3YzLuespb7t79FY34DjMwrVrcTuwlT55YMPvOBnRrJ4VXTdNnYug5ucHLBjEpt30701A3Ts+HEa73u6dT3FNWwflY86eMHPk+Yu+i6pzUpRrW7SNDg5JHR4KapmM5Wv2E8Tfcb1HoqqHMHU+uWDD7zg54mz5/2BSnizi9T1Dg4QQXLToGNCkb6tb1NU+QAlGr1++eADrzhn/u8Q2YZhQVlZ5+CAOtqfbhmaUCS1ezNFVm2imDbPmPng5wmz+gwh+oHDce0eUtQ6OGDIyR0uUhUsoO3vfDmmgOezH0mZN59x7MBi++WDL1g/eEiU3avlidO671bkLfwbw5XV2P8Pzo0ydy4t2/0eu33xYSOMOD8hTf4CrBtGMSoXfPLchX+J0ruSePw3LZeK0juPJbYzrhkH0io7B3k164hiGvawhOKMLkrQLyVpZg8rHFW7E2uHOL888IBPlNZ1FPzstSJM694fWr6RwpvcJK60+0HCILTBzZLFNdtAzJaohze60T8qBzyh5ZuOg5e7uwQppofEmf2++DYvmySqGBuKaicF1blQjhuHdvCIMvp8whTTfZzI7RldpwtSzL+F1+wkdZ2TBOW2gIF88PBTzD/gpeREAMEbxnJcaJHNHrpzji0gQCS6hdkEeYt9DF/2qPcEC8RM28Hwmr3sdNyht00byAut2k3gufWNtgtOEOFGUwcXWNDbdNbpgBGxEvKkOQsxivJx33iow0Vw5S6SVTrpVq11ysA2Rp7gTfPfktc6zhtXBBC+adRLshf6sG2RfHPZ5EAc4sVZ83yCN00Fk/4kggu40ZTvIEm5g24qtU4KjBrx/BTTH8ifVASAG7gKrnWxJDcU7x8X6Ecczhm3o6YicvsLXWfh3Ch1W0k8x0nXF+0fFxgt4phz8QvypiwCCFKMqXCnqXExjq10beH+UUA7+nG6mdG/Pu0f3LgFcGrl2s0kNNjpmoJ9o4B29CMO8dMT4Q5ox8uitF6fqsrJOr8qnwNbRzv6hSnG5wP+64C7h9lp30hKNtKdWjtdkbuPA19nJ7Tz3zR/ibgARbhb4AlhavcBebmTHcFl2fvYEnW0ox9xMxKBS8btJ+KiEbq9zA4RthQXDhPa0T9TEe69gWupwc6uBUphquXgf+/FrIjweHQS4/pduMe5ERUMHUd9xv8ZR98CxkS4F2n3EUrUZ10EYNw7BWm9x1GiPssi3GgiGRDKWRYZfXlON+dfNbM+GgIwYdwAAAAASUVORK5CYII=',
iconSize: [25, 41],
iconAnchor: [12.5, 41],
popupAnchor: [0, -41]
});
class App extends Component {
state = {
location: {
lat: 51.505,
lng: -0.09,
},
haveUsersLocation: false,
zoom: 2,
networks: null
}
//lifecycle method to get the user's current position(if they so desire).
componentDidMount() {
fetch('https://api.citybik.es/v2/networks')
.then(res => res.json())
.then(response => {
console.log("response", response);
console.log(response.networks)
const networkData = response.networks
const networkList = networkData.map((data) => {
console.log(data);
})
})
navigator.geolocation.getCurrentPosition((position) => {
this.setState({
location: {
lat: position.coords.latitude,
lng: position.coords.longitude
},
haveUsersLocation: true,
zoom: 13
});
}, () => {
console.log('Uops! The user didnt give its location!');
fetch('https://ipapi.co/json')
.then(res => res.json())
.then(location => {
this.setState({
location: {
lat: location.latitude,
lng: location.longitude
},
haveUsersLocation: true,
zoom: 13
});
})
});
}
render() {
const position = [this.state.location.lat, this.state.location.lng]
return (
<Map className="map" center={position} zoom={this.state.zoom}>
<TileLayer
attribution="&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{
this.state.haveUsersLocation ?
<Marker
position={position}
icon={myIcon}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker> : ''
}
</Map>
)
}
}
ReactDOM.render(<App/>,
document.getElementById('root')
);
body {
margin: 0px;
width: 100vw;
height: 100vh;
}
#root {
height: 100%;
}
.map {
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<link href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css" rel="stylesheet"/>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<title>Leaflet map</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
您必须渲染多个 Marker
元素。目前,如果您有当前用户位置,您正在渲染一个 Marker
。以类似的方式,我们将遍历其他坐标并渲染它们。
在您的 componentDidMount
中,将您收到的回复保存到状态
fetch('https://api.citybik.es/v2/networks')
.then(res => res.json())
.then(response => {
console.log("response", response);
console.log(response.networks)
const networkData = response.networks
const networkList = networkData.map((data) => {
this.setState({ bikeData: data });
})
})
然后在您的 render
方法中,遍历 bikeData
并呈现 Markers
.
<Map className="map" center={position} zoom={this.state.zoom}>
<TileLayer
attribution="&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{
this.state.haveUsersLocation ?
<Marker
position={position}
icon={myIcon}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker> : ''
}
{
this.state.bikeData &&
this.state.bikeData.networks.map((idx, data) => (
<Marker key={data.id} position={[data.location.latitude, data.location.longitude]}> <Popup> Name: {data.name} </Popup> </Marker>))
}
</Map>
您最好将输出 JSON 重新格式化为 GeoJSON,然后使用 Leaflet 和 Mapbox 在地图上绘制对象会非常简单。
示例:
https://gist.github.com/arfeo/3580f3796a31ca95b7cf30b99bfd6be5
const openJsonFile = (file) => {
return new Promise(function(resolve, reject) {
const _ = new XMLHttpRequest();
_.overrideMimeType("application/json");
_.open("GET", file, true);
_.onload = function() {
if(this.readyState == 4) {
if(this.status >= 200 && this.status < 300) {
resolve(_.responseText);
} else {
reject(_.statusText);
}
}
};
_.onerror = function () {
reject(_.statusText);
};
_.send();
});
};
// Create a map
const map = L.map('map').setView([55.92, 37.83], 12);
// Add Mapbox tiles to map
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoiYXJmZW8iLCJhIjoiY2pjeGw5bG5nMTF5ZjMzczZoZWVzbWdyNSJ9.Yh3u2uEHErWpTvAg3Ak_qw', {
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
maxZoom: 20,
id: 'mapbox.streets',
accessToken: 'pk.eyJ1IjoiYXJmZW8iLCJhIjoiY2pjeGw5bG5nMTF5ZjMzczZoZWVzbWdyNSJ9.Yh3u2uEHErWpTvAg3Ak_qw'
}).addTo(map);
// Open and parse heojson file
openJsonFile("output.geojson")
.then(function(json) {
const data = JSON.parse(json);
// Draw GeoJSON features on map
for(const feature of data.features) {
const x = L.geoJSON(feature).addTo(map);
// If a feature is Point, add a popup (if applicable)
if(feature.geometry.type === "Point")
x.bindPopup((name = feature.properties.name) ? name : null);
}
})
.catch(function(error) {
console.error("Error:", error);
});