【问题标题】:Google maps with d3.js (v5) overlay带有 d3.js (v5) 叠加层的 Google 地图
【发布时间】:2020-10-05 21:57:24
【问题描述】:

我正在做一个项目,其中有一个如下所示的 JSON:

 [
    {
        "lat": 53.1521596106757,
        "lon": -0.486577431632087,
        "size": 3598,
        "field": "TestField",
        "variety": "TestVariety",
        "count": 67
    },
    {
        "lat": 53.1521596106757,
        "lon": -0.486287281632087,
        "size": 4077,
        "field": "TestField",
        "variety": "TestVariety",
        "count": 73
    }
]

我正在尝试使用 count 添加文本,但使用以下代码没有看到预期的结果:

let testField = new google.maps.LatLng(53.1519, -0.4895);

const map = new google.maps.Map(d3.select('#map').node(), {
  zoom: 17,
  center: testField,
  mapTypeId: 'satellite',
  streetViewControl: false,
  mapTypeControl: false,
});

//colour scale
// const colorScale = d3.scaleSequential(d3.interpolateBlues);    

d3.json('/small_example.json')
  .then(data => {

    let countInfo = data.map(function (testVariety) {
      return testVariety.count;
    })

    // colorScale.domain(data.map(d => d.countInfo))

    //create overlay
    const overlay = new google.maps.OverlayView();

    // Add the container when the overlay is added to the map.
    overlay.onAdd = function () {
      const layer = d3.select(this.getPanes().overlayLayer).append('div')
        .attr('class', 'panes');

      // Draw each marker as a separate SVG element.
      overlay.draw = function () {
        const projection = this.getProjection(),
          padding = 10;

        const marker = layer.selectAll('svg')
          .data(d3.entries(data))
          .each(transform) // update existing markers
          .enter().append('svg')
          .each(transform)
          .attr('class', 'marker')

        //add a rect
        marker.append('rect')
          .attr('height', 15)
          .attr('width', 15)
        // .style('fill', d => colorScale(d.count));
        // .style('fill', function(d) {return d.count})

        let countInfo = data.map(function (testVariety) {
          return testVariety.count;
        })

        countInfo.forEach(element => {
          //add lable
          marker.append('text')
            .attr('x', padding + 7)
            .attr('y', padding)
            .attr('dy', '.31em')
            .each(transform)
            .text(function (d) {
              return element
            });
          console.log(element)
        });

        function transform(d) {
          d = new google.maps.LatLng(d.value.lat, d.value.lon);
          d = projection.fromLatLngToDivPixel(d);
          return d3.select(this)
            .style('left', (d.x - padding) + 'px')
            .style('top', (d.y - padding) + 'px')
        }
      };
    };

    // Bind overlay to the map
    overlay.setMap(map);
  });

console.log(element) 正在显示我想看到的结果,但我不知道如何在屏幕上显示它。

我觉得我快到了,但需要有人帮忙。

【问题讨论】:

标签: javascript arrays json google-maps d3.js


【解决方案1】:

尽量使您的示例成为一个 sn-p,以便它是一个最小的可重现示例,包括数据、库版本、所有脚本标签等。

但是对于您的示例,具有跨域的外部代码框架将无法在堆栈溢出 sn-p 上工作(至少对于我来说 Chrome 不一致)。因此,在这种情况下,请尝试使用 codePen 或其他代码沙箱类型网站。

我的完整示例如下(但它在堆栈溢出中对我来说并没有始终如一地运行)或者它在 codePen 中可用(工作):https://codepen.io/Alexander9111/pen/mdVOmJL

你错过的最重要的是这部分:

之前:

const marker = layer.selectAll('svg')
          .data(d3.entries(data)) //tansform object to array
          .each(transform) // update existing markers
          .enter().append('svg')
          .each(transform)
          .attr('class', 'marker')

之后:

const marker = layer.selectAll("svg")
          .data(data) //no need to transform array of objects
          .each(transform) // update existing markers
          .enter().append("svg")
          .each(transform)
          .attr("class", "marker");

看看你再次引用的示例代码:https://bl.ocks.org/mbostock/899711

他们的数据格式如下。这意味着它是一个对象,每个键都是 4 个字母代码,然后对应的值是一个 [lat, lon, longName, someArr] 形式的数组:

{
  "KMAE":[-120.12,36.98,"MADERA MUNICIPAL AIRPORT",[26,1,2,5,6,3,2,1,2,7,29,12,3]],
  "KSJC":[-121.92,37.37,"SAN JOSE INTERNATIONAL  AIRPORT",[28,1,1,1,6,10,5,3,2,4,14,21,7]],
  ...
}

而您的数据具有以下形式。这意味着它是一个对象数组,每个对象都有 lat、lon、field 等的键,以及每个对象上分配给每个属性的相应值:

[
    {
        "lat": 53.1521596106757,
        "lon": -0.486577431632087,
        "size": 3598,
        "field": "TestField",
        "variety": "TestVariety",
        "count": 67
    },
    {
        "lat": 53.1521596106757,
        "lon": -0.486287281632087,
        "size": 4077,
        "field": "TestField",
        "variety": "TestVariety",
        "count": 73
    },
    ...
];

所以,虽然您引用的示例的数据需要使用d3.entries(data) 进行转换,但您的数据已经是一个数组,因此您不需要将其从对象转换为数组,您可以直接应用数据.

// Create the Google Map…
const map = new google.maps.Map(d3.select("#map").node(), {
  zoom: 7,
  center: new google.maps.LatLng(53.5, -0.466),
  mapTypeId: google.maps.MapTypeId.TERRAIN
});

// Load the field data. When the data comes back, create an overlay.
//this is commented our for example purposes, and data is declared directly above
//d3.json("/small_example.json", function(error, data) {
  //if (error) throw error;

  const overlay = new google.maps.OverlayView();

  // Add the container when the overlay is added to the map.
  overlay.onAdd = function() {
    const layer = d3.select(this.getPanes().overlayLayer).append("div")
        .attr("class", "stations");

    // Draw each marker as a separate SVG element.
    // We could use a single SVG, but what size would it have?
    overlay.draw = function() {
      const projection = this.getProjection(),
          padding = 10;

      const marker = layer.selectAll("svg")
          .data(data)
          .each(transform) // update existing markers
        .enter().append("svg")
          .each(transform)
          .attr("class", "marker");

      // Add a circle.
      marker.append("circle")
          .attr("r", 4.5)
          .attr("cx", padding)
          .attr("cy", padding);

      // Add a label.
      marker.append("text")
          .attr("x", padding + 7)
          .attr("y", padding)
          .attr("dy", ".31em")
          .text(function(d) { return d.field; });

      function transform(d) {
        d = new google.maps.LatLng(d.lat, d.lon);
        d = projection.fromLatLngToDivPixel(d);
        return d3.select(this)
            .style("left", (d.x - padding) + "px")
            .style("top", (d.y - padding) + "px");
      }
    };
  };

  // Bind our overlay to the map…
  overlay.setMap(map);
//this closing bracket pair is commented out, while d3.json() is not in use: 
//});
html, body, #map {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

.stations, .stations svg {
  position: absolute;
}

.stations svg {
  width: 60px;
  height: 20px;
  padding-right: 100px;
  font: 10px sans-serif;
}

.stations circle {
  fill: brown;
  stroke: black;
  stroke-width: 1.5px;
}
<script src="//maps.google.com/maps/api/js?sensor=true"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="map"></div>

<script id="initData">
const data = [
    {
		"lat": 53.1521596106757,
		"lon": -0.486577431632087,
		"size": 3598,
		"field": "TestField",
		"variety": "TestVariety",
		"count": 67
	},
	{
		"lat": 53.1521596106757,
		"lon": -0.486287281632087,
		"size": 4077,
		"field": "TestField",
		"variety": "TestVariety",
		"count": 73
	}
];
</script>

输出:

【讨论】:

  • 太棒了。非常感谢!
猜你喜欢
  • 2020-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-02
  • 1970-01-01
相关资源
最近更新 更多