在 RMarkdown HTML 文档中动态更新 Mapbox gl 中的图层(未捕获类型错误)

问题描述 投票:0回答:1

我正在 RMarkdown 中渲染一个 mapboxgl 地图(HTML 输出,在 R 中使用 r2d3 js 库作为 js 部分)。我正在尝试通过传入地图填充属性的动态变量(基于用户在下拉列表中选择的内容)来更新 mapboxgl 地图中显示的图层。

//set default property for map so it knows which field to use for the map fill color  
var dropdown_val = 'ODpc'

//function that initially draws the map   
function loadMap(dropdown_val) {
    
    map2.on('load', function () {
    map2.addSource('bb', { type: 'geojson', data: data, generateId: true});
    map2.addLayer({
      'id': 'berlin',
      'type': 'fill',
      'source': 'bb',
      'paint': {
        'fill-color': {
            'property': dropdown_val,
            'stops': [[break1, '#feebe2'], [break2, '#fbb4b9'], [break3, '#f768a1'], [break4, '#c51b8a'], [break5, '#7a0177']]
          },
        'fill-opacity': .65
          }
    });
    map2.addLayer({
      'id': 'berlin-stroke',
      'type': 'line',
      'source': 'bb',
      'paint': {
        'line-color': '#000',
        'line-width': [
          'case',
          ['boolean', ['feature-state', 'hover'], false],
          2,
          .5
          ]
      }
    });
});
  
  
}

loadMap(dropdown_val)


//call the function that adds the year dropdown, other map elements like legend, etc.
document.body.onload = addElement;


function addElement() {
  
  //Create array of options to be added
  var array = ["2014-2022", "2022","2021","2020","2019", "2018", "2017", "2016", "2015", "2014"];
  var val_array = ["ODpc", "ODpc2022","ODpc2021","ODpc2020","ODpc2019", "ODpc2018", "ODpc2017", "ODpc2016", "ODpc2015", "ODpc2014"];

  //Create and append select list
  var selectList = document.createElement("select");
  selectList.id = "mySelect";
  selectList.className = "mySelect";


  //Create and append the options
  for (var i = 0; i < array.length; i++) {
    var option = document.createElement("option");
    option.value = val_array[i];
    option.text = array[i];
    selectList.appendChild(option);
  }

  //make legend etc.. etc...

});

 // create a function that gets the current value of the dropdown
 document.getElementById('mySelect').onchange = function(){
  
     dropdown_val = document.getElementById('mySelect').value;
     return dropdown_val
  
}

这按预期工作 - 初始地图渲染良好,我可以按预期返回当前下拉值。

我的问题:我想根据下拉列表的当前值动态更新地图。当我添加

document.getElementById('mySelect').onchange
事件侦听器(根据下拉值更新地图)时,我遇到了问题:

//set default property for map so it knows which field to use for the map fill color  
var dropdown_val = 'ODpc'

//function that initially draws the map   
function loadMap(dropdown_val) {
    
    map2.on('load', function () {
    map2.addSource('bb', { type: 'geojson', data: data, generateId: true});
    map2.addLayer({
      'id': 'berlin',
      'type': 'fill',
      'source': 'bb',
      'paint': {
        'fill-color': {
            'property': dropdown_val,
            'stops': [[break1, '#feebe2'], [break2, '#fbb4b9'], [break3, '#f768a1'], [break4, '#c51b8a'], [break5, '#7a0177']]
          },
        'fill-opacity': .65
          }
    });
    map2.addLayer({
      'id': 'berlin-stroke',
      'type': 'line',
      'source': 'bb',
      'paint': {
        'line-color': '#000',
        'line-width': [
          'case',
          ['boolean', ['feature-state', 'hover'], false],
          2,
          .5
          ]
      }
    });
});
  
  
}

loadMap(dropdown_val)


//call the function that adds the year dropdown, other map elements like legend, etc.
document.body.onload = addElement;


function addElement() {
  
  //Create array of options to be added
  var array = ["2014-2022", "2022","2021","2020","2019", "2018", "2017", "2016", "2015", "2014"];
  var val_array = ["ODpc", "ODpc2022","ODpc2021","ODpc2020","ODpc2019", "ODpc2018", "ODpc2017", "ODpc2016", "ODpc2015", "ODpc2014"];

  //Create and append select list
  var selectList = document.createElement("select");
  selectList.id = "mySelect";
  selectList.className = "mySelect";


  //Create and append the options
  for (var i = 0; i < array.length; i++) {
    var option = document.createElement("option");
    option.value = val_array[i];
    option.text = array[i];
    selectList.appendChild(option);
  }

  //make legend etc.. etc...

});

//update the map  based on the dropdown value
$(document).ready(function() {

 document.getElementById('mySelect').onchange = function(){
  

    //remove any existing layers so that they can be re-drawn according to whatever the user has selected in dropdown
    if (map2.getLayer('berlin')) {
        map2.removeLayer('berlin');
      }
    if (map2.getLayer('berlin-stroke')) {
       map2.removeLayer('berlin-stroke');
    }
    if (map2.getLayer(dropdown_val)) {
       map2.removeLayer(dropdown_val);
    }
    if (map2.getLayer('stroke')) {
       map2.removeLayer('stroke');
    }
       
   dropdown_val = document.getElementById('mySelect').value;

   //call function to load in current dropdown value and re-draw map fill to be based on that property
   map2.addLayer({
      'id': dropdown_val,
      'type': 'fill',
      'source': 'bb',
      'paint': {
      'fill-color': {
          'property': 'ODpc'+dropdown_val,
          'stops': [[break1, '#feebe2'], [break2, '#fbb4b9'], [break3, '#f768a1'], [break4, '#c51b8a'], [break5, '#7a0177']]
        },
      'fill-opacity': .65
        }
  });
   map2.addLayer({
     'id': 'stroke',
     'type': 'line',
     'source': 'bb',
     'paint': {
        'line-color': '#000',
        'line-width': [
           'case',
           ['boolean', ['feature-state', 'hover'], false],
          2,
          .5
          ]
       }
    })     
  }
})

document.getElementById('mySelect').onchange = function()
行我收到错误:

Uncaught TypeError: Cannot set properties of null (setting 'onchange')

地图实际上会使用 onchange 函数进行更新,它只是有点小故障,有时无法工作,具体取决于页面加载的方式。

似乎错误可能是由于在 DOM 中实际渲染下拉列表之前调用了

onchange
函数?但是,如果我将
onchange
函数移到
addElement()
函数(在
document.body.onload
上调用)中,它根本不起作用(我没有收到错误消息,但地图图层没有被删除并且重新绘制)。

提前致谢。

javascript r r-markdown mapbox-gl-js mapbox-gl
1个回答
0
投票

现在,这是一个疯狂的猜测,但如果您创建下拉列表并在 map2 加载函数中订阅它,则不应该存在竞争条件。

//set default property for map so it knows which field to use for the map fill color  
var dropdown_val = 'ODpc'

//function that initially draws the map   
function loadMap(dropdown_val) {
  map2.on('load', function () {
    // Add source and layers, etc...

    // Create and inside the load function instead.
    addElement();
  });
}

loadMap(dropdown_val)

function addElement() {
  //Create array of options to be added
  var array = ["2014-2022", "2022","2021","2020","2019", "2018", "2017", "2016", "2015", "2014"];
  var val_array = ["ODpc", "ODpc2022","ODpc2021","ODpc2020","ODpc2019", "ODpc2018", "ODpc2017", "ODpc2016", "ODpc2015", "ODpc2014"];

  //Create and append select list
  var selectList = document.createElement("select");
  selectList.id = "mySelect";
  selectList.className = "mySelect";


  //Create and append the options
  for (var i = 0; i < array.length; i++) {
    var option = document.createElement("option");
    option.value = val_array[i];
    option.text = array[i];
    selectList.appendChild(option);
  }

  //make legend etc.. etc...

  // Connect the event listener
  selectList.addEventListener('change', onChange);

  // Add the element where you want it, for example body.
  body.appendChild(selectList)
};

function onChange(event) {
  const dropdown_val = event.target.value;
  // Update the layers depending on the value
}
© www.soinside.com 2019 - 2024. All rights reserved.