3D 可视化问题(Angular + ol-cesium),变化时闪烁

问题描述 投票:0回答:1

我创建了一个使用 ol-cesium 的新 Angular 项目。 以下是我正在使用的版本:

  • Angular v19
  • olcs 2.22.1
  • 铯1.123
  • ol 10.3.1

问题是我在使用 3D 视图时执行的任何操作都会导致其“闪烁”。 我在 2D 视图中没有任何问题。

此类操作的示例包括:删除和添加矢量图层、更改要素的坐标或更新要素的样式。

应用程序非常简单:我有一个主组件(app.component.ts),其中包含一些按钮,这些按钮触发另一个组件(cesium.directive.ts)中的方法,所有逻辑都驻留在其中。

有人遇到过这个问题吗?

下面是两个组件的示例,转到 3D 并单击按钮移动视图闪烁的图标。

import { Component, ViewChild, ViewChildren, QueryList, AfterViewInit} from '@angular/core';
import { CesiumDirective } from './cesium.directive';

@Component({
    selector: 'app-root',
    template: `
    <div class="map-container">
      <div
        id="map"
        appCesium
        #cesiumDirective
      ></div>
      <button class="toggle-view-button" (click)="toggleView()">Toggle 2D/3D View</button>
      <button class="move-button" (click)="moveButton()">move</button>
    </div>
  `,
    styles: [`
    .map-container {
      width: 100%;
      height: 100vh;
      position: relative;
    }
    #map {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      left: 0;
    }
    .toggle-view-button {
      position: absolute;
      top: 10px;
      right: 10px;
      z-index: 1000;
    }
    .move-button {
      position: absolute;
      top: 90px;
      right: 10px;
      z-index: 1000;
    }
  `],
    standalone: false
})
export class AppComponent implements AfterViewInit {
  @ViewChildren(CesiumDirective)
  cesiumDirectives!: QueryList<CesiumDirective>;
  private cesiumDirective!: CesiumDirective;

  ngAfterViewInit() {
    setTimeout(() => {
      this.cesiumDirective = this.cesiumDirectives.first;
      console.log('Cesium Directive found:', this.cesiumDirective);
    });
  }

  moveButton() {
    if(this.cesiumDirective) {
      this.cesiumDirective.moveButton();
    }
  }
}
import { Directive, ElementRef, OnInit } from '@angular/core';
import OLCesium from 'olcs';
import Map from 'ol/Map';
import { Feature, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import { OSM } from 'ol/source';
import { Point } from 'ol/geom';
import {Fill, Icon, Stroke, Style, Text} from 'ol/style';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';


@Directive({
    selector: '[appCesium]',
    standalone: false,
})
export class CesiumDirective implements OnInit {
  private map!: Map;
  private ol3d: any;
  private vectorLayer!: VectorLayer;
  private is3DEnabled: boolean = false;
  private icon1Feature!: any;

  constructor(private el: ElementRef) {
  }

  ngOnInit(): void {
    this.initMap();
    this.addFeature();
  }

  private addFeature(): void {
    // Creare le feature con icone
    this.icon1Feature = new Feature({
      geometry: new Point([700000, 200000, 10000])
    });
    this.icon1Feature.setStyle(new Style({
      image: new Icon({
        anchor: [0.5, 1],
        src: 'assets/icon.png'
      }),
      text: new Text({
        text: 'Icon with anchor on the bottom center',
        stroke: new Stroke({
          color: 'black',
          width: 3
        }),
        fill: new Fill({
          color: 'white'
        })
      })
    }));

    // Creare la sorgente e il layer vettoriale
    const vectorSource = new VectorSource({
      features: [this.icon1Feature]
    });

    this.vectorLayer = new VectorLayer({
      source: vectorSource
    });

    this.map.addLayer(this.vectorLayer);
  }

  private initMap(): void {
    
    try {
      this.map = new Map({
        target: this.el.nativeElement,
        layers: [
          new TileLayer({
            visible: true,
            preload: Infinity,
            source: new OSM(),
          })
        ],
        view: new View({
          zoom: 5,
          center: [6000000, 4000000]
        })
      });

      this.ol3d = new OLCesium({ 
        map: this.map,
        target: this.el.nativeElement,
      });
            
      const scene = this.ol3d.getCesiumScene();
      scene.debugShowFramesPerSecond = true;

      this.ol3d.setEnabled(false);

    } catch (error) {
      console.error('Error initializing map:', error);
    }
  }

  public toggleView(): void {
    try {
      this.is3DEnabled = !this.is3DEnabled;
      
      if (this.ol3d) {
        this.ol3d.setEnabled(this.is3DEnabled);
      }
    } catch (error) {
      console.error('Error in toggleView:', error);
    }
  }

  public moveButton() {
    const currentCoordinates = this.icon1Feature.getGeometry().getCoordinates();

    const deltaX = 100;
    const deltaY = 200;
    
    const newCoordinates = [currentCoordinates[0] + deltaX, currentCoordinates[1] + deltaY, currentCoordinates[2]];

    this.icon1Feature.setGeometry(new Point(newCoordinates));
  }

}
angular gis openlayers cesiumjs
1个回答
0
投票

moveButton
功能代码似乎无效或导致地图重新渲染,您可以尝试此替代代码以使其满足您的要求。

public moveButton() {
  var center = this.map.getView().getCenter()!;
  var resolution = this.map.getView().getResolution()!;
  this.map
  this.map.getView().setCenter([center[0] + 100*resolution, center[1] + 200*resolution]);
}

除此之外,我对您的代码做了一些更改。

  1. 将 viewChildren 更改为

    viewChild
    ,因为只有一个。

  2. 添加了

    map
    ol3d
    的输入。

完整代码:

import {
  Component,
  ViewChild,
  ViewChildren,
  QueryList,
  AfterViewInit,
} from '@angular/core';
import { Directive, ElementRef, OnInit } from '@angular/core';
import OLCesium from 'olcs';
import Map from 'ol/Map';
import { Feature, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import { OSM } from 'ol/source';
import { Point } from 'ol/geom';
import { Fill, Icon, Stroke, Style, Text } from 'ol/style';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import { bootstrapApplication } from '@angular/platform-browser';

@Directive({
  selector: '[appCesium]',
  standalone: true,
})
export class CesiumDirective implements OnInit {
  private map!: Map;
  private ol3d!: OLCesium;
  private vectorLayer!: VectorLayer;
  private is3DEnabled: boolean = false;
  private icon1Feature!:Feature;

  constructor(private el: ElementRef) {}

  ngOnInit(): void {
    this.initMap();
    this.addFeature();
  }

  private addFeature(): void {
    // Creare le feature con icone
    this.icon1Feature = new Feature({
      geometry: new Point([700000, 200000, 10000]),
    });
    this.icon1Feature.setStyle(
      new Style({
        image: new Icon({
          anchor: [0.5, 1],
          src: 'assets/icon.png',
        }),
        text: new Text({
          text: 'Icon with anchor on the bottom center',
          stroke: new Stroke({
            color: 'black',
            width: 3,
          }),
          fill: new Fill({
            color: 'white',
          }),
        }),
      })
    );

    // Creare la sorgente e il layer vettoriale
    const vectorSource = new VectorSource({
      features: [this.icon1Feature],
    });

    this.vectorLayer = new VectorLayer({
      source: vectorSource,
    });

    this.map.addLayer(this.vectorLayer);
  }

  private initMap(): void {
    try {
      this.map = new Map({
        target: this.el.nativeElement,
        layers: [
          new TileLayer({
            visible: true,
            preload: Infinity,
            source: new OSM(),
          }),
        ],
        view: new View({
          zoom: 5,
          center: [6000000, 4000000],
        }),
      });

      this.ol3d = new OLCesium({
        map: this.map,
        target: this.el.nativeElement,
      });

      const scene = this.ol3d.getCesiumScene();
      scene.debugShowFramesPerSecond = true;

      this.ol3d.setEnabled(false);
    } catch (error) {
      console.error('Error initializing map:', error);
    }
  }

  public toggleView(): void {
    try {
      this.is3DEnabled = !this.is3DEnabled;

      if (this.ol3d) {
        this.ol3d.setEnabled(this.is3DEnabled);
      }
    } catch (error) {
      console.error('Error in toggleView:', error);
    }
  }

  public moveButton() {
    var center = this.map.getView().getCenter()!;
    var resolution = this.map.getView().getResolution()!;
    this.map
    this.map.getView().setCenter([center[0] + 100*resolution, center[1] + 200*resolution]);
  }
}
@Component({
  selector: 'app-root',
  imports: [CesiumDirective],
  template: `
    <div class="map-container">
      <div
        id="map"
        appCesium
      ></div>
      <button class="toggle-view-button" (click)="toggleView()">Toggle 2D/3D View</button>
      <button class="move-button" (click)="moveButton()">move</button>
    </div>
  `,
  styles: [
    `
    .map-container {
      width: 100%;
      height: 100vh;
      position: relative;
    }
    #map {
      width: 100%;
      height: 100%;
      position: absolute; 
      top: 0;
      left: 0;
    }
    .toggle-view-button {
      position: absolute;
      top: 10px;
      right: 10px;
      z-index: 1000;
    }
    .move-button {
      position: absolute;
      top: 90px;
      right: 10px;
      z-index: 1000;
    }
  `,
  ],
  standalone: true,
})
export class AppComponent implements AfterViewInit {
  @ViewChild(CesiumDirective)
  cesiumDirective!: CesiumDirective;

  ngAfterViewInit() {
  }

  moveButton() {
    this.cesiumDirective.moveButton();
  }

  toggleView() {
    this.cesiumDirective.toggleView();
  }
}

bootstrapApplication(AppComponent);
© www.soinside.com 2019 - 2024. All rights reserved.