AmCharts AmMap - 设置缩放操作的起始位置
AmCharts AmMap - Set starting location for zoom actions
我想在下拉菜单中使用基于 selection 的 "zoomToMapObject" 方法。
由于某种原因,开始缩放位置是地图的中间而不是设置的 geoPoint。
(缩放有效,但起始位置让它看起来有点奇怪。)
我目前的做法是这样的:
const duration = this.chart.zoomToMapObject(selectedPoloygon, this.countryZoom, true).duration;
setTimeout(() => {
this.chart.homeGeoPoint = geoPoint;
this.chart.homeZoomLevel = this.countryZoom;
}, duration);
this.handleCountrySelection(selectedPoloygon);
不知何故,即使设置 homeGeoPoint / homeZoomLevel 也不会影响下一个缩放操作。
**更新:解决高成本(从 1300 个节点到 9000 多个节点)**
我进一步检查了这个问题。当我将新的 mapImageSeries 推入地图时,似乎设置了中间点。
我目前的解决方法是在地图上绘制所有点并隐藏它们。
然后在我 select 一个国家之后,我将状态更改为可见。
然而,这种方法的成本非常高。 DOM-节点从 1300 上升到 ~ 9100。
我在一个国家 selected 并且缩放动画完成后创建它们的另一种方法是更多
有效的。但是由于地图每次都从中心位置开始,这是不可行的吗?或者我做了 s.th。错了?
这是我当前的代码,但性能不佳:
// map.ts
export class MapComponent implements AfterViewInit, OnDestroy {
imageSeriesMap = {};
// ... standard map initialization ( not in zone of course )
// creating the "MapImages" which is very costly
this.dataService.getCountries().forEach(country => {
const imageSeriesKey = country.id;
const imageSeriesVal = chart.series.push(new am4maps.MapImageSeries()); // takes arround 1-2 ms -> 300 x 2 ~ 500 ms.
const addressForCountry = this.dataService.filterAddressToCountry(country.id); // returns "DE" or "FR" for example.
const imageSeriesTemplate = imageSeriesVal.mapImages.template;
const circle = imageSeriesTemplate.createChild(am4core.Circle);
circle.radius = 4;
circle.fill = am4core.color(this.colorRed);
circle.stroke = am4core.color('#FFFFFF');
circle.strokeWidth = 2;
circle.nonScaling = true;
circle.tooltipText = '{title}';
imageSeriesTemplate.propertyFields.latitude = 'latitude';
imageSeriesTemplate.propertyFields.longitude = 'longitude';
imageSeriesVal.data = addressForCountry.map(address => {
return {
latitude: Number.parseFloat(address.lat),
longitude: Number.parseFloat(address.long),
title: address.company
};
});
imageSeriesVal.visible = false;
this.imageSeriesMap[imageSeriesKey] = imageSeriesVal;
});
// clicking on the map
onSelect(country) {
this.imageSeriesMap[country].visible = true;
setTimeout( () => {
const chartPolygons = <any>this.chart.series.values[0];
const polygon = chartPolygons.getPolygonById(country);
const anim = this.chart.zoomToMapObject(polygon, 1, true, 1000);
anim.events.on('animationended', () => {});
this.handleCountrySelection(polygon);
}, 100);
});
}
handleCountrySelection(polygon: am4maps.MapPolygon) {
if (this.selectedPolygon && this.selectedPolygon !== polygon) {
this.selectedPolygon.isActive = false;
}
polygon.isActive = true;
const geoPoint: IGeoPoint = {
latitude: polygon.latitude,
longitude: polygon.longitude
};
this.chart.homeGeoPoint = geoPoint;
this.chart.homeZoomLevel = this.countryZoom;
this.selectedPolygon = polygon;
}
}
多亏了你的彻底跟进,我才能够重现这个问题。您遇到的问题是由以下任一步骤触发的:
- 将
MapImageSeries
动态推送到图表
- 通过
data
动态创建 MapImage
(另请注意,在您提供的粘贴绑定中,data
需要一个数组,我必须在测试时更改它)
在任一步骤中,图表都将完全缩小,就像重置自身一样。我将调查为什么会发生这种情况以及是否可以更改它,所以与此同时让我们看看下面的解决方法是否适合您。
如果我们只使用一个预先设置的 MapImageSeries
(我没有特别看到有多个 MapImageSeries
的理由,一个不可以吗?),这就消除了问题 1 的发生.除了 data
,我们还可以通过 mapImageSeries.mapImages.create();
create()
MapImages
manually 然后手动分配它们的 latitude
和 longitude
属性。至此,问题2也没有出现,我们似乎就可以了。
这是一个修改版 pastebin 的演示:
https://codepen.io/team/amcharts/pen/c460241b0efe9c8f6ab1746f44d666af
变化是 MapImageSeries
代码从 createMarkers
函数中取出,因此它只发生一次:
const mapImageSeries = chart.series.push(new am4maps.MapImageSeries());
const imageSeriesTemplate = mapImageSeries.mapImages.template;
const circle = imageSeriesTemplate.createChild(am4core.Circle);
circle.radius = 10;
circle.fill = am4core.color('#ff0000');
circle.stroke = am4core.color('#FFFFFF');
circle.strokeWidth = 2;
circle.nonScaling = true;
circle.tooltipText = 'hi';
在这种情况下,没有必要将 chart
传递给 createMarkers
和 return,所以我传递 polygon
只是为了演示动态 latitude/longitudes,我还将我们的新 MapImage
分配给多边形的数据 (dataItem.dataContext
),以便我们稍后参考。这是 createMarkers
的新正文:
function createMarkers(polygon) {
console.log('calling createMarkers');
if ( !polygon.dataItem.dataContext.redDot) {
const dataItem = polygon.dataItem;
// Object notation for making a MapImage
const redDot = mapImageSeries.mapImages.create();
// Note the lat/long are direct properties
redDot.id = `reddot-${dataItem.dataContext.id}`;
// attempt to make a marker in the middle of the country (note how this is inaccurate for US since we're getting the center for a rectangle, but it's not a rectangle)
redDot.latitude = dataItem.north - (dataItem.north - dataItem.south)/2;
redDot.longitude = dataItem.west - (dataItem.west - dataItem.east)/2;;
dataItem.dataContext.redDot = redDot;
}
}
不需要 animationended
事件或任何东西,它就可以正常工作,因为不再有任何东西干扰您的代码。你也应该恢复你的表现。
这对你有用吗?
以下问题编辑前的原始答案:
我无法复制您提到的行为。另外,我不知道 this.countryZoom
是什么。
只需在按钮处理程序中使用以下内容...
chart.zoomToMapObject(polygon);
...似乎可以很好地缩放到国家/地区,无论当前地图位置如何/zoomLevel
。
如果您需要在缩放动画结束后计时,zoomToMapObject
return 是一个 Animation
, you can use its 'animationended'
事件,例如
const animation = this.chart.zoomToMapObject(selectedPoloygon, this.countryZoom, true);
animation.events.on("animationended", () => {
// ...
});
这是一个示例,其中包含 2 个外部 <button>
s,一个用于缩放到美国,另一个用于缩放到巴西:
https://codepen.io/team/amcharts/pen/c1d1151803799c3d8f51afed0c6eb61d
这有帮助吗?如果没有,您能否提供一个 minimal example 以便我们可以复制您遇到的问题?
我想在下拉菜单中使用基于 selection 的 "zoomToMapObject" 方法。 由于某种原因,开始缩放位置是地图的中间而不是设置的 geoPoint。
(缩放有效,但起始位置让它看起来有点奇怪。)
我目前的做法是这样的:
const duration = this.chart.zoomToMapObject(selectedPoloygon, this.countryZoom, true).duration;
setTimeout(() => {
this.chart.homeGeoPoint = geoPoint;
this.chart.homeZoomLevel = this.countryZoom;
}, duration);
this.handleCountrySelection(selectedPoloygon);
不知何故,即使设置 homeGeoPoint / homeZoomLevel 也不会影响下一个缩放操作。
**更新:解决高成本(从 1300 个节点到 9000 多个节点)**
我进一步检查了这个问题。当我将新的 mapImageSeries 推入地图时,似乎设置了中间点。
我目前的解决方法是在地图上绘制所有点并隐藏它们。 然后在我 select 一个国家之后,我将状态更改为可见。
然而,这种方法的成本非常高。 DOM-节点从 1300 上升到 ~ 9100。
我在一个国家 selected 并且缩放动画完成后创建它们的另一种方法是更多 有效的。但是由于地图每次都从中心位置开始,这是不可行的吗?或者我做了 s.th。错了?
这是我当前的代码,但性能不佳:
// map.ts
export class MapComponent implements AfterViewInit, OnDestroy {
imageSeriesMap = {};
// ... standard map initialization ( not in zone of course )
// creating the "MapImages" which is very costly
this.dataService.getCountries().forEach(country => {
const imageSeriesKey = country.id;
const imageSeriesVal = chart.series.push(new am4maps.MapImageSeries()); // takes arround 1-2 ms -> 300 x 2 ~ 500 ms.
const addressForCountry = this.dataService.filterAddressToCountry(country.id); // returns "DE" or "FR" for example.
const imageSeriesTemplate = imageSeriesVal.mapImages.template;
const circle = imageSeriesTemplate.createChild(am4core.Circle);
circle.radius = 4;
circle.fill = am4core.color(this.colorRed);
circle.stroke = am4core.color('#FFFFFF');
circle.strokeWidth = 2;
circle.nonScaling = true;
circle.tooltipText = '{title}';
imageSeriesTemplate.propertyFields.latitude = 'latitude';
imageSeriesTemplate.propertyFields.longitude = 'longitude';
imageSeriesVal.data = addressForCountry.map(address => {
return {
latitude: Number.parseFloat(address.lat),
longitude: Number.parseFloat(address.long),
title: address.company
};
});
imageSeriesVal.visible = false;
this.imageSeriesMap[imageSeriesKey] = imageSeriesVal;
});
// clicking on the map
onSelect(country) {
this.imageSeriesMap[country].visible = true;
setTimeout( () => {
const chartPolygons = <any>this.chart.series.values[0];
const polygon = chartPolygons.getPolygonById(country);
const anim = this.chart.zoomToMapObject(polygon, 1, true, 1000);
anim.events.on('animationended', () => {});
this.handleCountrySelection(polygon);
}, 100);
});
}
handleCountrySelection(polygon: am4maps.MapPolygon) {
if (this.selectedPolygon && this.selectedPolygon !== polygon) {
this.selectedPolygon.isActive = false;
}
polygon.isActive = true;
const geoPoint: IGeoPoint = {
latitude: polygon.latitude,
longitude: polygon.longitude
};
this.chart.homeGeoPoint = geoPoint;
this.chart.homeZoomLevel = this.countryZoom;
this.selectedPolygon = polygon;
}
}
多亏了你的彻底跟进,我才能够重现这个问题。您遇到的问题是由以下任一步骤触发的:
- 将
MapImageSeries
动态推送到图表 - 通过
data
动态创建MapImage
(另请注意,在您提供的粘贴绑定中,data
需要一个数组,我必须在测试时更改它)
在任一步骤中,图表都将完全缩小,就像重置自身一样。我将调查为什么会发生这种情况以及是否可以更改它,所以与此同时让我们看看下面的解决方法是否适合您。
如果我们只使用一个预先设置的 MapImageSeries
(我没有特别看到有多个 MapImageSeries
的理由,一个不可以吗?),这就消除了问题 1 的发生.除了 data
,我们还可以通过 mapImageSeries.mapImages.create();
create()
MapImages
manually 然后手动分配它们的 latitude
和 longitude
属性。至此,问题2也没有出现,我们似乎就可以了。
这是一个修改版 pastebin 的演示:
https://codepen.io/team/amcharts/pen/c460241b0efe9c8f6ab1746f44d666af
变化是 MapImageSeries
代码从 createMarkers
函数中取出,因此它只发生一次:
const mapImageSeries = chart.series.push(new am4maps.MapImageSeries());
const imageSeriesTemplate = mapImageSeries.mapImages.template;
const circle = imageSeriesTemplate.createChild(am4core.Circle);
circle.radius = 10;
circle.fill = am4core.color('#ff0000');
circle.stroke = am4core.color('#FFFFFF');
circle.strokeWidth = 2;
circle.nonScaling = true;
circle.tooltipText = 'hi';
在这种情况下,没有必要将 chart
传递给 createMarkers
和 return,所以我传递 polygon
只是为了演示动态 latitude/longitudes,我还将我们的新 MapImage
分配给多边形的数据 (dataItem.dataContext
),以便我们稍后参考。这是 createMarkers
的新正文:
function createMarkers(polygon) {
console.log('calling createMarkers');
if ( !polygon.dataItem.dataContext.redDot) {
const dataItem = polygon.dataItem;
// Object notation for making a MapImage
const redDot = mapImageSeries.mapImages.create();
// Note the lat/long are direct properties
redDot.id = `reddot-${dataItem.dataContext.id}`;
// attempt to make a marker in the middle of the country (note how this is inaccurate for US since we're getting the center for a rectangle, but it's not a rectangle)
redDot.latitude = dataItem.north - (dataItem.north - dataItem.south)/2;
redDot.longitude = dataItem.west - (dataItem.west - dataItem.east)/2;;
dataItem.dataContext.redDot = redDot;
}
}
不需要 animationended
事件或任何东西,它就可以正常工作,因为不再有任何东西干扰您的代码。你也应该恢复你的表现。
这对你有用吗?
以下问题编辑前的原始答案:
我无法复制您提到的行为。另外,我不知道 this.countryZoom
是什么。
只需在按钮处理程序中使用以下内容...
chart.zoomToMapObject(polygon);
...似乎可以很好地缩放到国家/地区,无论当前地图位置如何/zoomLevel
。
如果您需要在缩放动画结束后计时,zoomToMapObject
return 是一个 Animation
, you can use its 'animationended'
事件,例如
const animation = this.chart.zoomToMapObject(selectedPoloygon, this.countryZoom, true);
animation.events.on("animationended", () => {
// ...
});
这是一个示例,其中包含 2 个外部 <button>
s,一个用于缩放到美国,另一个用于缩放到巴西:
https://codepen.io/team/amcharts/pen/c1d1151803799c3d8f51afed0c6eb61d
这有帮助吗?如果没有,您能否提供一个 minimal example 以便我们可以复制您遇到的问题?