AmCharts AmMap-设置缩放动作的起始位置

时间:2018-09-10 08:44:44

标签: amcharts

我想基于下拉菜单上的选择使用“ 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推入地图时,似乎设置了中间点。

我目前的工作环境是在地图上绘制所有点并将其隐藏。 然后,在选择一个国家/地区后,将州更改为可见。

但是,这种方法非常昂贵。 DOM节点从1300上升到9100。

选择国家/地区并完成缩放动画后创建动画的另一种方法是 有效。但是由于地图每次都从某个中心位置开始,因此不可行吗?还是我做某事错误吗?

这是我当前未执行的代码:

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

1 个答案:

答案 0 :(得分:3)

感谢您的彻底跟进,我得以重现此问题。您遇到的问题是由以下任一步骤触发的:

  1. 动态地将MapImageSeries推向图表
  2. 通过MapImage动态创建data(也请注意,在您提供的pastebind中,data需要一个数组,我必须在测试时更改它)

在任一步骤中,图表将完全缩小,就像在重置自身一样。我将调查为什么会发生这种情况,以及是否可以更改它,因此在此期间,让我们看看下面的解决方法是否对您有用。

如果我们仅使用一个预先设置的MapImageSeries(我看不出有多个MapImageSeries的原因,那不是吗?),这可以消除问题1的发生。在data的旁边,我们可以通过mapImageSeries.mapImages.create();create() MapImages manually,然后手动分配它们的latitudelongitude属性。这样一来,问题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并返回它,所以我已经传递了polygon来演示动态纬度/经度,我还分配了多边形数据(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返回一个Animation,则可以使用其'animationended'事件,例如

const animation = this.chart.zoomToMapObject(selectedPoloygon, this.countryZoom, true);
animation.events.on("animationended", () => {
    // ...
});

下面是一个示例,其中包含2个外部<button>,其中一个用于缩放至美国,另一个用于缩放巴西:

https://codepen.io/team/amcharts/pen/c1d1151803799c3d8f51afed0c6eb61d

这有帮助吗?如果没有,您可以提供一个minimal example,以便我们复制您遇到的问题吗?