使用经纬度在地图上放置位置时如何使用 zoomToMapObject

How to use zoomToMapObject when using lat and long for putting locations on map

我正在 angular 中处理 amcharts map。我在 latlong 上使用绑定位置,我没有国家 id 而有位置名称。我想使用 zoomToMapObject.

缩放特定位置

我有下拉菜单,当我 select 一个国家时,我想放大它。

这是我的 objectlocationData

{
    "dId": 28046,
    "lat": 33.8627681,
    "long": -117.8870831,
    "loc": "Fullerton  CA"
    "color":"red"
},
    {
    "dId": 25535,
    "lat": 31.5649775,
    "long": -110.2591639,
    "loc": "Sierra Vista  AZ"
     "color":"yellow"
},
    "dId": 31222,
    "lat": 33.4308114,
    "long": -70.7828727,
    "loc": "Pudahuel  Metropolitana"
     "color":"green"
},
{
    "dId": 23280,
    "lat": 36.1676717,
    "long": -94.1298177,
    "loc": "Springdale  AR"
    "color":"red"
},

当我 select 下拉菜单时,在 SelectCountry 我怎样才能让我的代码工作。这些所有变量都返回 undefined,因此 zoomToMapObject 不起作用

public mapCountry_selected(country)
{
   setTimeout( () => {  
     this.mapChart.zoomToGeoPoint({latitude:country.lat,longitude:country.long},17,true)
   }, 100);
}

这是我的代码

public locationMap()
{
    this.mapChart = am4core.create("productsMap", am4maps.MapChart);
    this.mapChart .geodata = am4geodata_worldLow;
    this.mapChart .projection = new am4maps.projections.Miller();
    this.polygonSeries = this.mapChart .series.push(new am4maps.MapPolygonSeries());
    this.polygonSeries.exclude = ["AQ"];
    this.polygonSeries.useGeodata = true;
    this.polygonSeries.calculateVisualCenter = true;

    let imageSeries = this.mapChart .series.push(new am4maps.MapImageSeries());
  
    var place = imageSeries.mapImages.template;
    place.nonScaling = true;
    place.propertyFields.latitude = "lat";
    place.propertyFields.longitude = "long";

    imageSeries.data=this.locationData;
    var circle = place.createChild(am4core.Circle);
    circle.propertyFields.fill = "color";  
  
    imageSeries.heatRules.push({
     "target": circle,
     "property": "radius",
     "min": 3,
     "max": 10,
     "dataField": "value",
    })
}

编辑1:

我为每个位置 ("target": circle) 显示了绿色、黄色、红色三种颜色的圆圈。现在在添加 true 点后,第 2 点和第 3 点已解决(来自我的评论)。在 select 从下拉列表中输入一个位置后,我需要 highlight/popover 位置,这样用户可以直接知道我已经 select 编辑的这个位置,因为彼此之间有很多位置。

编辑2:

从下拉菜单select输入位置后的地图

对问题修订 1 的初始响应

推荐方法

根据您掌握的信息,考虑使用 MapChart 对象上可用的 zoomToGeoPoint 方法可能更容易,例如

//assuming the selected country is as follows
var country = { 
    "dId": 23280,
    "lat": 36.1676717,
    "long": -94.1298177,
    "loc": "Springdale  AR",
    "color":"red",
};
this.mapChart.zoomToGeoPoint({latitude:country.lat,longitude:country.long},17)

其中 17 是您想要的缩放级别。 zoomToMapObject 在处理图表事件时特别有用。

更具体地针对您的问题

但是,如果您想使用 zoomToMapObject 方法,根据您的示例,可以考虑以下方法。

对于数据集中的每个数据点,并使用存储在 am4geodata_worldLow 中的初始数据,其中每个多边形具有“id”(例如,提取第一个 am4geodata_worldLow.features[0].id 的 id),您可以使用最接近每个多边形中心的 lat/lng 坐标来确定每个 country/place。

在您存储在 this.mapChart 中的 MapChart 对象中,有多个系列(模糊地被认为是层),您必须检查多边形或 MapObjects。这些可以使用以下方法提取:

var mapPolygons = this.mapChart.series.values.flatMap(function(seriesItem){return seriesItem.mapPolygons.values;});

然后您可以构建一个数据结构,将您的每个自定义 country/place 映射到映射中可用的 ID(例如对象 {"your-country-id":mapPolygonObject}

对于每个 mapPolygon 您可以使用

提取坐标点
var coordinates = mapPolygon.points[0][0]; //returns an array of x,y coordinates
//eg
coordinates = 
[{"x":691.2713756097037,"y":137.68935508639663},{"x":691.2544487420046,"y":137.69150482342081},{"x":691.2544487420046,"y":137.67239542245633},{"x":691.2695833531237,"y":137.6702455263596}];

然后您可以找到多边形中心点和您所在国家/地区之间的 center/centroid of this polygon using these points as bounds and then for each of your country points you would find the euclidean distance。最短距离可以假设这个国家与这一点相关联。可能会考虑距离(注意。由于您使用的是坐标,请务必至少考虑小数点后 5 位)为 50,000 英里(请观察您的坐标系,了解如何将 lat/lng 距离转换为 metres/miles) 可能意味着这些是不同的地方。

然后您可以提取 ID 并构建您的地图对象,以便稍后在您的脚本中使用。这可能是耗时且计算密集型的,理想情况下,如果您之前这样做会更好,并且已经存储了必要的参考以供以后使用。

另一种搜索 ID 的方法

此外,如果您有国家/地区 ID,那么搜索会更简单,如下所示:

//assuming the selected country is as follows
var country = { 
    "dId": 23280,
    "lat": 36.1676717,
    "long": -94.1298177,
    "loc": "Springdale  AR",
    "color":"red",
};
//for this example I am extracting the country id from the object,it would be ideal to have it otherwise
//NB. country ids are also available in the `am4geodata_worldLow` used to initialize the map
var countryId = country.loc.split(" ")[1]; //this would return the country code - 'AR' 

//we will now search the created chart for mapObjects with this id
//this will give us an array of map objects/polygons with the id if found
var possibleMapObjects = this.mapChart.series.values.map(function(seriesItem){
    return seriesItem.getPolygonById(countryId)
}).flat();


if(possibleMapObjects.length > 0){
   // we have found a map object
   var countryMapObject = possibleMapObjects[0]; //taking the first item of array
   //now we can zoom to map object
   //the 3rd parameter true implies centering the map
   this.mapChart.zoomToMapObject(countryMapObject,17,true)
}

问题修订 2 (Edit1) 的初始响应

根据更新后的代码,我注意到了一些问题,我无法在您的地图上看到标记,因此我进行了一些修改。此外,修改现在允许您通过 id 检索 marker/map 对象,因为我已经使用您使用的 id 扩充了数据,请参阅下面的更新代码。

我创建了一个 dropdown/select 节点来模拟 onchange 事件,在 callback/event 处理程序中,onCountryChange 您将看到我们如何通过新的 [=77] 检索标记=] 我们指定并根据 Documented MapImage API

调用操作(我将打开一个弹出窗口)

locationData = [

  {
    "dId": 28046,
    "lat": 33.8627681,
    "long": -117.8870831,
    "loc": "Fullerton  CA",
    "color": "red"
  },
  {
    "dId": 25535,
    "lat": 31.5649775,
    "long": -110.2591639,
    "loc": "Sierra Vista  AZ",
    "color": "yellow"
  },
  {
    "dId": 31222,
    "lat": 33.4308114,
    "long": -70.7828727,
    "loc": "Pudahuel  Metropolitana",
    "color": "green"
  },
  {
    "dId": 23280,
    "lat": 36.1676717,
    "long": -94.1298177,
    "loc": "Springdale  AR",
    "color": "red"
  },
].map(function(place) {
  place.id = place.dId;
  return place;
});

this.mapChart = am4core.create("productsMap", am4maps.MapChart);
this.mapChart.geodata = am4geodata_worldLow;
this.mapChart.projection = new am4maps.projections.Miller();
this.polygonSeries = this.mapChart.series.push(new am4maps.MapPolygonSeries());
this.polygonSeries.exclude = ["AQ"];
this.polygonSeries.useGeodata = true;
this.polygonSeries.calculateVisualCenter = true;

let imageSeries = this.mapChart.series.push(new am4maps.MapImageSeries());

var place = imageSeries.mapImages.template;
place.nonScaling = true;
place.propertyFields.latitude = "lat";
place.propertyFields.longitude = "long";

imageSeries.data = locationData;
var circle = place.createChild(am4core.Circle);
circle.propertyFields.fill = "color";
/// code below made circles visible and used value in {loc} / location name as tooltiptext
circle.width = 20;
circle.height = 20;
circle.nonScaling = false;
circle.tooltipText = "{loc}";
circle.horizontalCenter = "middle";
circle.verticalCenter = "bottom";

var circle2 = imageSeries.mapImages.template.createChild(am4core.Circle);
circle2.radius = 3;
circle2.propertyFields.fill = "color";


circle2.events.on("inited", function(event){
  animateBullet(event.target);
})


function animateBullet(circle) {
    var animation = circle.animate([{ property: "scale", from: 1, to: 5 }, 
 
   {property: "opacity", from: 1, to: 0 }], 1000, am4core.ease.circleOut);
    animation.events.on("animationended", function(event){
      animateBullet(event.target.object);
    })
}

imageSeries.heatRules.push({
  "target": circle,
  "property": "radius",
  "min": 3,
  "max": 10,
  "dataField": "value",
});

//just initializing the ui (you have already done this in angular)
var ddlPlaceChooser = document.getElementById("ddlPlaceChooser");

locationData.map(function(location) {
    var option = document.createElement("option");
    option.value = location.id;
    option.innerText = location.loc;
    return option;
  })
  .forEach(function(option) {
    ddlPlaceChooser.appendChild(option)
  })

function onCountryChange(event) {

  //however you retrieve the selected id
  var placeId = ddlPlaceChooser.selectedOptions[0].value;
  //retrieve map object
  var mapObject = imageSeries.getImageById(placeId);
  //zoom to map object
  mapChart.zoomToMapObject(mapObject, 17, true);
  //optionally open popup with message of choice
  mapObject.openModal("You choose me!")
  //mapObject.openPopup("You choose me!")



}

ddlPlaceChooser.addEventListener('change', onCountryChange)
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/maps.js"></script>
<script src="https://www.amcharts.com/lib/4/geodata/worldLow.js"></script>
<script src="https://cdn.amcharts.com/lib/4/themes/animated.js"></script>
<div>
  <label for="placeChooser">Choose Place</label>
  <select id="ddlPlaceChooser" name="placeChooser"></select>
</div>
<hr />
<div id="productsMap"></div>

我就是这样修复的

public selectedLocation(country)
  {  
    var imageSeries = this.mChart.series.push(new am4maps.MapImageSeries());
    var mapImage = imageSeries.mapImages.template;
    var mapMarker = mapImage.createChild(am4core.Sprite);
    mapMarker.path = "M4 12 A12 12 0 0 1 28 12 C28 20, 16 32, 16 32 C16 32, 4 20 4 12 M11 12 A5 5 0 0 0 21 12 A5 5 0 0 0 11 12 Z";
    mapMarker.width = 5;
    mapMarker.height = 3;
    mapMarker.scale = 0.02;
    mapMarker.fill = am4core.color("#ff0000");
    mapMarker.fillOpacity = 0.8;
    mapMarker.horizontalCenter = "middle";
    mapMarker.verticalCenter = "bottom";
    var marker = imageSeries.mapImages.create();
    marker.latitude = country.lat;
    marker.longitude = country.long;


    setTimeout( () => {
      this.Animate = this.mChart.zoomToGeoPoint({latitude:country.lat,longitude:country.long},25,true)
    }, 100);

    marker.events.on("inited", function(event){
      animateBullet(event.target);
    })

    function animateBullet(obj) {
      let animation = obj.animate([{ property: "scale", from: 1, to: 3 }, { property: "opacity", from: 0, to: 1 }], 1000, am4core.ease.circleOut);
      animation.events.on("animationended", function(event){
        animateBullet(event.target.object);
      })
    }

  }