React/Dash 内使用 D3-tile 的未定义数据
Undefined data using D3-tile within React/Dash
我试图在 React 中复制这个 d3 map example 以便我可以将它用作 Plotly Dash 中的一个组件。但是,有一个问题(我认为是 D3-tile)导致 opnestreemap url 中出现未定义的字符串。这可以防止代码获取图块的实际图像,并产生下图:
放大时产生的错误如下所示:
这是完整的 MyMap.react.js 代码。似乎错误来自未填充数据的 tiles 变量,但我不确定这是什么原因。任何帮助将不胜感激!
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import * as d3 from 'd3';
import {mesh} from 'topojson-client';
import * as d3Tile from 'd3-tile';
function createGeoMap(divId) {
var pi = Math.PI,
tau = 2 * pi;
var width = Math.max(960, window.innerWidth),
height = Math.max(500, window.innerHeight);
// Initialize the projection to fit the world in a 1×1 square centered at the origin.
var projection = d3.geoMercator()
.scale(1 / tau)
.translate([0, 0]);
var path = d3.geoPath()
.projection(projection);
var tile = d3Tile.tile()
.size([width, height]);
var zoom = d3.zoom()
.scaleExtent([1 << 11, 1 << 14])
.on('zoom', zoomed);
var svg = d3.select('#' + divId).append('svg')
.attr('width', width)
.attr('height', height);
var raster = svg.append('g');
var vector = svg.append('path');
d3.json('https://gist.githubusercontent.com/mbostock/4090846/raw/d534aba169207548a8a3d670c9c2cc719ff05c47/us.json', function(error, us) {
if (error) throw error;
vector
.datum(mesh(us, us.objects.states));
// Compute the projected initial center.
var center = projection([-98.5, 39.5]);
// Apply a zoom transform equivalent to projection.{scale,translate,center}.
svg
.call(zoom)
.call(zoom.transform, d3.zoomIdentity
.translate(width / 2, height / 2)
.scale(1 << 12)
.translate(-center[0], -center[1]));
});
function zoomed() {
var transform = d3.event.transform;
var tiles = tile
.scale(transform.k)
.translate([transform.x, transform.y])
();
projection
.scale(transform.k / tau)
.translate([transform.x, transform.y]);
vector
.attr('d', path);
var image = raster
.attr('transform', stringify(tiles.scale, tiles.translate))
.selectAll('image')
.data(tiles, function(d) { return d; });
image.exit().remove();
image.enter().append('image')
.attr('xlink:href', function(d) { return 'http://' + 'abc'[d[1] % 3] + '.tile.openstreetmap.org/' + d[2] + '/' + d[0] + '/' + d[1] + '.png'; })
.attr('x', function(d) { return d[0] * 256; })
.attr('y', function(d) { return d[1] * 256; })
.attr('width', 256)
.attr('height', 256);
}
function stringify(scale, translate) {
var k = scale / 256, r = scale % 1 ? Number : Math.round;
return 'translate(' + r(translate[0] * scale) + ',' + r(translate[1] * scale) + ') scale(' + k + ')';
}
}
export default class MyMap extends Component {
constructor() {
super();
this.plot = this.plot.bind(this);
}
plot(props) {
createGeoMap(props.id);
}
componentDidMount() {
this.plot(this.props);
}
shouldComponentUpdate() {
return false;
}
componentWillReceiveProps(newProps) {
if(newProps.id !== this.props.id) {
this.plot(newProps);
}
}
render() {
const {id} = this.props;
return (
<div id={id} />
);
}
}
MyMap.propTypes = {
/**
* The ID used to identify this compnent in Dash callbacks
*/
id: PropTypes.string,
};
问题
看来documentation and linked examples for d3 tile use v0.0.3; however, using 0.0.4 breaks the documentation and examples (see this issue report)。由于您似乎正在使用文档链接到的示例之一作为模板,因此在使用最新版本的 d3.tile.
时,您的代码将被破坏
您可以通过查看您请求的图块来了解此中断的症状,正如您所注意到的,您正在为每个图块请求这样的图像:
"http://undefined.tile.openstreetmap.org/undefined/undefined/undefined.png"
v0.0.4 中的更改
在 v0.0.3 中,表示每个图块的 x、y、z 值的数组由 d3.tile 生成:[1,2,3]
在 v0.0.4 中,具有 x、y、z 值属性的对象由 d3.tile 生成:{x:1,y:2,z:3}
修复
所以你可以改变:
return 'http://' + 'abc'[d[1] % 3] + '.tile.openstreetmap.org/' + d[2] + '/' + d[0] + '/' + d[1] + '.png'
到
return 'http://' + 'abc'[d.y % 3] + '.tile.openstreetmap.org/' + d.z + '/' + d.x + '/' + d.y + '.png'; })
当然每个图块的 x,y 属性也需要设置为 d.x * 256
和 d.y * 256
,而不是 d[0] * 256
和 d[1] * 256
。
我试图在 React 中复制这个 d3 map example 以便我可以将它用作 Plotly Dash 中的一个组件。但是,有一个问题(我认为是 D3-tile)导致 opnestreemap url 中出现未定义的字符串。这可以防止代码获取图块的实际图像,并产生下图:
放大时产生的错误如下所示:
这是完整的 MyMap.react.js 代码。似乎错误来自未填充数据的 tiles 变量,但我不确定这是什么原因。任何帮助将不胜感激!
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import * as d3 from 'd3';
import {mesh} from 'topojson-client';
import * as d3Tile from 'd3-tile';
function createGeoMap(divId) {
var pi = Math.PI,
tau = 2 * pi;
var width = Math.max(960, window.innerWidth),
height = Math.max(500, window.innerHeight);
// Initialize the projection to fit the world in a 1×1 square centered at the origin.
var projection = d3.geoMercator()
.scale(1 / tau)
.translate([0, 0]);
var path = d3.geoPath()
.projection(projection);
var tile = d3Tile.tile()
.size([width, height]);
var zoom = d3.zoom()
.scaleExtent([1 << 11, 1 << 14])
.on('zoom', zoomed);
var svg = d3.select('#' + divId).append('svg')
.attr('width', width)
.attr('height', height);
var raster = svg.append('g');
var vector = svg.append('path');
d3.json('https://gist.githubusercontent.com/mbostock/4090846/raw/d534aba169207548a8a3d670c9c2cc719ff05c47/us.json', function(error, us) {
if (error) throw error;
vector
.datum(mesh(us, us.objects.states));
// Compute the projected initial center.
var center = projection([-98.5, 39.5]);
// Apply a zoom transform equivalent to projection.{scale,translate,center}.
svg
.call(zoom)
.call(zoom.transform, d3.zoomIdentity
.translate(width / 2, height / 2)
.scale(1 << 12)
.translate(-center[0], -center[1]));
});
function zoomed() {
var transform = d3.event.transform;
var tiles = tile
.scale(transform.k)
.translate([transform.x, transform.y])
();
projection
.scale(transform.k / tau)
.translate([transform.x, transform.y]);
vector
.attr('d', path);
var image = raster
.attr('transform', stringify(tiles.scale, tiles.translate))
.selectAll('image')
.data(tiles, function(d) { return d; });
image.exit().remove();
image.enter().append('image')
.attr('xlink:href', function(d) { return 'http://' + 'abc'[d[1] % 3] + '.tile.openstreetmap.org/' + d[2] + '/' + d[0] + '/' + d[1] + '.png'; })
.attr('x', function(d) { return d[0] * 256; })
.attr('y', function(d) { return d[1] * 256; })
.attr('width', 256)
.attr('height', 256);
}
function stringify(scale, translate) {
var k = scale / 256, r = scale % 1 ? Number : Math.round;
return 'translate(' + r(translate[0] * scale) + ',' + r(translate[1] * scale) + ') scale(' + k + ')';
}
}
export default class MyMap extends Component {
constructor() {
super();
this.plot = this.plot.bind(this);
}
plot(props) {
createGeoMap(props.id);
}
componentDidMount() {
this.plot(this.props);
}
shouldComponentUpdate() {
return false;
}
componentWillReceiveProps(newProps) {
if(newProps.id !== this.props.id) {
this.plot(newProps);
}
}
render() {
const {id} = this.props;
return (
<div id={id} />
);
}
}
MyMap.propTypes = {
/**
* The ID used to identify this compnent in Dash callbacks
*/
id: PropTypes.string,
};
问题
看来documentation and linked examples for d3 tile use v0.0.3; however, using 0.0.4 breaks the documentation and examples (see this issue report)。由于您似乎正在使用文档链接到的示例之一作为模板,因此在使用最新版本的 d3.tile.
时,您的代码将被破坏您可以通过查看您请求的图块来了解此中断的症状,正如您所注意到的,您正在为每个图块请求这样的图像:
"http://undefined.tile.openstreetmap.org/undefined/undefined/undefined.png"
v0.0.4 中的更改
在 v0.0.3 中,表示每个图块的 x、y、z 值的数组由 d3.tile 生成:[1,2,3]
在 v0.0.4 中,具有 x、y、z 值属性的对象由 d3.tile 生成:{x:1,y:2,z:3}
修复
所以你可以改变:
return 'http://' + 'abc'[d[1] % 3] + '.tile.openstreetmap.org/' + d[2] + '/' + d[0] + '/' + d[1] + '.png'
到
return 'http://' + 'abc'[d.y % 3] + '.tile.openstreetmap.org/' + d.z + '/' + d.x + '/' + d.y + '.png'; })
当然每个图块的 x,y 属性也需要设置为 d.x * 256
和 d.y * 256
,而不是 d[0] * 256
和 d[1] * 256
。