2

Plotly Dash のコンポーネントとして使用できるように、React 内でこの d3マップの例を複製しようとしています。ただし、opnestreemap の URL で未定義の文字列が発生するという問題があります (D3 タイルにあると思います)。これにより、コードがタイルの実際の画像を取得できなくなり、次の画像になります。

ズームインすると生成されるエラーは次のようになります。

ここに画像の説明を入力

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,

};
4

1 に答える 1