使用经纬度在地图上放置位置时如何使用 zoomToMapObject
How to use zoomToMapObject when using lat and long for putting locations on map
我正在 angular
中处理 amcharts map
。我在 lat
和 long
上使用绑定位置,我没有国家 id
而有位置名称。我想使用 zoomToMapObject
.
缩放特定位置
我有下拉菜单,当我 select 一个国家时,我想放大它。
这是我的 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"
},
当我 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);
})
}
}
我正在 angular
中处理 amcharts map
。我在 lat
和 long
上使用绑定位置,我没有国家 id
而有位置名称。我想使用 zoomToMapObject
.
我有下拉菜单,当我 select 一个国家时,我想放大它。
这是我的 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"
},
当我 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);
})
}
}