【问题标题】:How to use zoomToMapObject when using lat and long for putting locations on map使用 lat 和 long 在地图上放置位置时如何使用 zoomToMapObject
【发布时间】:2020-09-22 14:29:27
【问题描述】:

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

我有下拉菜单,当我从中选择一个国家时,我想放大它。

这是我的object 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"
},

当我选择下拉菜单时,在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 点之后(来自我的评论)。从下拉列表中选择一个后,我需要突出显示/弹出位置,以便用户可以直接知道我选择的这个位置,因为彼此周围有很多位置。

编辑2:

从下拉列表中选择位置后的地图

【问题讨论】:

  • zoomToMapObject 在使用事件监听器时特别有用。但是,由于在您的国家/地区数据中您已经有了纬度和经度,您可以使用this.mapChart.zoomToGeoPoint({latitude:country.lat,longitude:country.long},17) 缩放到一个位置,其中 17 是缩放级别。您是想专门从 amcharts api 中提取地图对象以进行缩放,还是对您有用?
  • 更新后的答案现在使用 zoomToMapObject,我创建了伪 ID 并包含了一个工作示例
  • 非常感谢您的回答。由于您在我的数据上添加了function(place),我的所有数据都在this.locationData 中,而不是普通的JSON,所以添加.map(function(place) 应该在this.locationData 上完成。
  • 我假设 this.locationData 有一个对象数组,如示例所示,所以是的,您可以更新为 this.locationData.map(function(place) .....and the rest of the code

标签: javascript angular amcharts ammap


【解决方案1】:

对问题修订 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),您可以确定每个国家/地区/place 使用最接近每个多边形中心的 lat/lng 坐标。

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

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

然后您可以构建一个数据结构,将您的每个自定义国家/地区映射到地图中可用的 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,然后对于您所在国家/地区的每个点,您会在多边形中心点和您的国家/地区之间找到euclidean distance。最短的距离可以假设这个国家与这一点有关。可能需要考虑距离(注意。由于您使用的是坐标,请务必考虑至少 5 个小数点)因为 50,000 英里(请注意您的坐标系,了解将纬度/经度距离转换为米/英里的方法)可能表示这些是不同的地方。

然后您可以提取 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 检索标记/地图对象,因为我已经使用您使用的 id 扩充了数据,请参阅下面的更新代码。

我创建了一个下拉/选择节点来模拟 onchange 事件,在回调/事件处理程序onCountryChange 您将看到我们如何通过我们指定的新伪 ID 检索标记并调用操作(我将打开一个弹出窗口)根据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>

【讨论】:

  • 我使用了zoomToGeoPoint。你能检查这些点1)zoom之后我怎么知道我放大了哪个地方像border/animation/highlight因为地图上有很多位置/圈子2) 在zoom 之后,如果我选择另一个位置,则没有任何反应3) 有什么方法可以在Center 中搜索位置
  • 我试图用发布的内容复制您的示例,我只看到一张地图,其中国家/地区为绿色,没有点/圆。 1)您可以在选择每个位置之前或之后添加带有弹出框和突出显示link的地图标记/图钉/圆圈,而不是尝试突出显示您没有ID的多边形。 2) 请分享有关您如何调用或已将 SelectCountry 方法附加到 events/html 的代码。 3)您可以添加true作为第三个参数,例如this.mapChart.zoomToGeoPoint({latitude:country.lat,longitude:country.long},17,true)
  • 我已经更新了我的问题、数据和选择事件代码。请检查。谢谢。
  • 这个例子很棒,但不知道如何在选择时做到这一点,请您检查一下。我只需要一点区别就可以了。 amcharts.com/demos/map-with-pulsating-bullets
  • 我更新了响应,请参阅编辑以及示例中的工作示例和 cmets
【解决方案2】:

我就是这样解决的

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);
      })
    }

  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-04
    • 2020-02-19
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多