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 * 256d.y * 256,而不是 d[0] * 256d[1] * 256