javascript - 传单 Google map 和 d3 Voronoi 图叠加

标签 javascript google-maps d3.js leaflet voronoi

我正在关注 Chris Zetter 的 tutorial在 Leaflet 上创建 Voronoi 叠加层,但我已将 Mapbox 图 block 替换为 Google map 图 block (使用 Google Mutant Leaflet 插件)并使用我自己的数据。

voronoi 叠加层可以工作,但在移动 map 或重置 View (moveend 和 viewreset 事件)时不会更新。

似乎“viewreset”事件没有被触发,并且“moveend”事件没有触发“drawWithLoading”函数。

出现的错误是: 未捕获的类型错误:无法读取未定义的属性“调用”(...) 在指定的线上 这个函数的作用:

map.on('load', function() {

  d3.csv(url, function(csv) {
    points = csv;
    points.forEach(function(point) {
      pointTypes.set(point.type, {type: point.type, color: point.color});
    })
    drawPointTypeSelection();
    map.addLayer(mapLayer); //ERROR on this line
  })
});

这是它引用的mapLayer函数:

var mapLayer = {
  onAdd: function(map) {
    map.on('viewreset moveend', drawWithLoading);
    drawWithLoading();
  },
};

这是drawWithLoading 函数:

var drawWithLoading = function(e){

    console.log('drawWithLoading e', e); //TODO: delete later
    d3.select('#loading').classed('visible', true);
    if (e && e.type == 'viewreset') {
      d3.select('#overlay').remove();
    }
    setTimeout(function(){
      draw();
      d3.select('#loading').classed('visible', false);
    }, 0);
  }

我对 javascript 还很陌生,过去几天一直在尝试解决这个问题。

有谁知道为什么会出现mapLayer函数错误,以及为什么 map 不会在“moveend”和“viewreset”事件上重绘?

编辑以包含整个代码:

// Selects check boxes in selector menu //
showHide = function(selector) {
  d3.select(selector).select('.hide').on('click', function(){
    d3.select(selector)
      .classed('visible', false)
      .classed('hidden', true);
  });

  d3.select(selector).select('.show').on('click', function(){
    d3.select(selector)
      .classed('visible', true)
      .classed('hidden', false);
  });
}

// Draws Voronoi Map //
voronoiMap = function(map, url, initialSelections) {

  console.log('We got in here!');
  console.log('map', map);
  console.log('url', url);
  console.log('initialSelections', initialSelections);
  window.myMap = map;

  var pointTypes = d3.map(),
      points = [],
      lastSelectedPoint;

  var voronoi = d3.geom.voronoi()
      .x(function(d) { return d.x; })
      .y(function(d) { return d.y; });

  var selectPoint = function() {
    d3.selectAll('.selected').classed('selected', false);

    var cell = d3.select(this),
        point = cell.datum();

    lastSelectedPoint = point;
    cell.classed('selected', true);

    d3.select('#selected h1')
      .html('')
      .append('a')
        .text(point.name)
        .attr('href', point.url)
        .attr('target', '_blank')
  }

  var drawPointTypeSelection = function() {
    showHide('#selections')
    labels = d3.select('#toggles').selectAll('input')
      .data(pointTypes.values())
      .enter().append("label");

    labels.append("input")
      .attr('type', 'checkbox')
      .property('checked', function(d) {
        return initialSelections === undefined || initialSelections.has(d.type)
      })
      .attr("value", function(d) { return d.type; })
      .on("change", drawWithLoading);

    labels.append("span")
      .attr('class', 'key')
      .style('background-color', function(d) { return '#' + d.color; });

    labels.append("span")
      .text(function(d) { return d.type; });
  }

  var selectedTypes = function() {
    return d3.selectAll('#toggles input[type=checkbox]')[0].filter(function(elem) {
      return elem.checked;
    }).map(function(elem) {
      return elem.value;
    })
  }

  var pointsFilteredToSelectedTypes = function() {
    var currentSelectedTypes = d3.set(selectedTypes());
    return points.filter(function(item){
      return currentSelectedTypes.has(item.type);
    });
  }

  var drawWithLoading = function(e){

    console.log('drawWithLoading e', e); //TODO: delete later
    d3.select('#loading').classed('visible', true);
    if (e && e.type == 'viewreset') {
      d3.select('#overlay').remove();
    }
    setTimeout(function(){
      draw();
      d3.select('#loading').classed('visible', false);
    }, 0);
  }

  var draw = function() {
    d3.select('#overlay').remove();

    var bounds = map.getBounds(),
        topLeft = map.latLngToLayerPoint(bounds.getNorthWest()),
        bottomRight = map.latLngToLayerPoint(bounds.getSouthEast()),
        existing = d3.set(),
        drawLimit = bounds.pad(0.4);

    filteredPoints = pointsFilteredToSelectedTypes().filter(function(d) {
      var latlng = new L.LatLng(d.latitude, d.longitude);

      if (!drawLimit.contains(latlng)) { return false };

      var point = map.latLngToLayerPoint(latlng);

      key = point.toString();
      if (existing.has(key)) { return false };
      existing.add(key);

      d.x = point.x;
      d.y = point.y;
      return true;
    });

    voronoi(filteredPoints).forEach(function(d) { d.point.cell = d; });

    console.log('map.getPanes()', map.getPanes());

    var svg = d3.select(map.getPanes().overlayPane).append("svg")
      .attr('id', 'overlay')
      .attr("class", "leaflet-zoom-hide")
      .style("width", map.getSize().x + 'px')
      .style("height", map.getSize().y + 'px')
      .style("margin-left", topLeft.x + "px")
      .style("margin-top", topLeft.y + "px");

    var g = svg.append("g")
      .attr("transform", "translate(" + (-topLeft.x) + "," + (-topLeft.y) + ")");

    var svgPoints = g.attr("class", "points")
      .selectAll("g")
        .data(filteredPoints)
      .enter().append("g")
        .attr("class", "point")
        .attr('data-name', function(d) { return d.name } );

    var buildPathFromPoint = function(point) {
      return "M" + point.cell.join("L") + "Z";
    }

    svgPoints.append("path")
      .attr("class", "point-cell")
      .attr("d", buildPathFromPoint)
      .style('fill', function(d) { //return '#' + d.color
          if (d.name <= 10) {return "ffffd9"}
                    else if (d.name <=15 && d.name >10) {return "edf8b1"}
                    else if (d.name <=20 && d.name >15) {return "7fcdbb"}
                    else if (d.name <=25 && d.name >20) {return "41b6c4"}
                    else if (d.name <=35 && d.name >25) {return "1d91c0"}
                    else if (d.name <=45 && d.name >35) {return "253494"}
                    else {return "081d58"}
      })
      .attr("opacity", 0.5)
      .on('click', selectPoint)
      .classed("selected", function(d) { return lastSelectedPoint == d} );

    svgPoints.append("circle")
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
      .style('fill', function(d) { //return '#' + d.color
        if (d.name <= 10) {return "ffffd9"}
                    else if (d.name <=15 && d.name >10) {return "edf8b1"}
                    else if (d.name <=20 && d.name >15) {return "7fcdbb"}
                    else if (d.name <=25 && d.name >20) {return "41b6c4"}
                    else if (d.name <=35 && d.name >25) {return "1d91c0"}
                    else if (d.name <=45 && d.name >35) {return "253494"}
                    else {return "081d58"} } )
      .attr("r", 1.4)
      .attr("opacity", 0.6);
  }


  var mapLayer = {
    onAdd: function(map) {
      console.log("onviewreset map", map); //TODO: Delete later
      map.on('viewreset moveend', drawWithLoading);
      drawWithLoading();
    },
  };

  showHide('#about');

  map.on('load', function() {
    console.log('map ready');
    d3.csv(url, function(csv) {
      points = csv;
      points.forEach(function(point) {
        pointTypes.set(point.type, {type: point.type, color: point.color});
      })
      drawPointTypeSelection();
      console.log("addLayer"); //TODO: Delete Later
      map.addLayer(mapLayer);
      console.log("addedLayer"); //TODO: Delete Later
    })
  });

  console.log('got here too');
}

// Draws Google Maps tiles using Road and Style tiles //
var map = L.map('map');

var roadMutant = L.gridLayer.googleMutant({
            maxZoom: 24,
            type:'roadmap'
}).addTo(map);

var styleMutant = L.gridLayer.googleMutant({
            styles: [
                {elementType: 'labels', stylers: [{visibility: 'off'}]},
                {featureType: 'water', stylers: [{color: '#444444'}]},
                {featureType: 'landscape', stylers: [{color: '#eeeeee'}]},
                {featureType: 'road', stylers: [{visibility: 'on'}]},
                {featureType: 'poi', stylers: [{visibility: 'off'}]},
                {featureType: 'transit', stylers: [{visibility: 'on'}]},
                {featureType: 'administrative', stylers: [{visibility: 'off'}]},
                {featureType: 'administrative.locality', stylers: [{visibility: 'off'}]}
            ],
            maxZoom: 24,
            type:'roadmap'
});

// Creates a styles selector menu //
L.control.layers({
  Roadmap: roadMutant,
  Styles: styleMutant
}, {}, {
  collapsed: false
}).addTo(map);



url = 'AllCoords_supertrial.csv';
initialSelection = d3.set(['1','2','3']); //Ideally would like to have all selected to start with or take away having to check boxes before drawing//
voronoiMap(map, url, initialSelection);

最佳答案

即使您已经发布了一些代码和 fiddle ,但还是很难知道发生了什么。请尝试更新您的问题以提供complete example .

我将做出一个大胆的猜测并指出这一行代码:

var mapLayer = {
   ...
};

如果您阅读 Leaflet tutorials ,特别是关于扩展Leaflet来创建新类型的 map 图层,您会意识到创建Layer子类的方法是:

var mapLayer = L.Layer.extend({
    onAdd: function(map) {...},
    ...
});

Leaflet 期望 map 图层是 L.Layer 的实例,实现所有内部方法。如果您尝试添加不实现L.Layer“接口(interface)”的内容,事情将会崩溃。

如果您不了解子类化和类接口(interface)等,请刷新您的知识OOP .

这可能不是代码中的唯一问题,但这是我现在在没有正确查看完整示例的情况下看到的唯一问题。

关于javascript - 传单 Google map 和 d3 Voronoi 图叠加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40772876/

相关文章:

java - Placepicker 仅在双击后工作

android - 如何在 Google Maps V2 for Android 上触发标记的 onClick 事件?

javascript - 是否可以连接 KML 图层以在一个复选框(Google map )中显示它们?

javascript - 使用 D3 绘制条形图中的 Time.Scale 和 RangeBand

javascript - D3 : Using a closure to update a selection without re-binding data

javascript - 为函数(带参数)分配变量名? [JavaScript]

javascript - 为什么 forkJoin 从我的可观察量中返回错误的值?

javascript - Django,如何为网站上显示的脚本制作下载按钮

javascript - forEach 返回未定义 - 如何改为返回数组?

javascript - 在多焦点 d3 力布局中重新定位节点