在React/Dash中使用D3-tile的未定义数据 [英] Undefined data using D3-tile within React/Dash

查看:85
本文介绍了在React/Dash中使用D3-tile的未定义数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在React中复制此d3 地图示例,以便我可以使用它作为Plotly Dash中的组件.但是,存在一个问题(我认为是D3拼写),导致opnestreemap网址中的字符串未定义.这样可以防止代码获取瓦片的实际图像,并生成以下图像:

I'm trying to duplicate this d3 map example within React so that I can use it as a component in Plotly Dash. However, there is an issue (I think with D3-tile) that's resulting in undefined strings in the opnestreemap urls. This prevents the code from grabbing the actual images for the tiles, and results in the following image:

放大时产生的错误如下:

The errors produced as you zoom in look like this:

这是完整的MyMap.react.js代码.似乎错误是由于tile变量未填充数据引起的,但是我不确定这是什么原因.任何帮助将不胜感激!

Here is the full MyMap.react.js code. It seems like the error is coming from the tiles variable not being filled with data, but I'm not sure what the cause of that would be. Any help would be greatly appreciated!

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,

};

推荐答案

问题

似乎文档和d3磁贴的链接示例使用v0.0.3;但是,使用0.0.4会破坏文档和示例(请参见此问题报告 ).由于似乎您使用的是文档链接到的示例之一作为模板,因此在使用最新版本的d3.tile时,您的代码将被破坏.

It appears that the 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). Since it appears as though you are using one of the examples that the documentation links to as a template, your code will be broken when using the newest version of d3.tile.

您可以通过查看所请求的图块来查看此中断的症状,如您所注意到的,您正在为每个图块按以下方式请求图像:

You can see the symptom of this break by looking the tiles you are requesting, as you note, you are requesting an image at something like this for each tile:

"http://undefined.tile.openstreetmap.org/undefined/undefined/undefined.png"

v0.0.4中的更改

在v0.0.3中,由d3.tile生成的数组表示每个图块的x,y,z值:[1,2,3]

In v0.0.3, an array representing the x,y,z values for each tile was produced by d3.tile: [1,2,3]

在v0.0.4中,由d3.tile生成具有x,y,z值属性的对象:{x:1,y:2,z:3}

In v0.0.4, an object with properties for the x,y,z values is produced by by 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 * 256d.y * 256,而不是d[0] * 256d[1] * 256.

And of course the x,y attributes of each tile needs to be set to d.x * 256 and d.y * 256 as well, rather than d[0] * 256 and d[1] * 256.

这篇关于在React/Dash中使用D3-tile的未定义数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆