我创建了一个使用 ol-cesium 的新 Angular 项目。 以下是我正在使用的版本:
问题是我在使用 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));
}
}
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]);
}
除此之外,我对您的代码做了一些更改。
将 viewChildren 更改为
viewChild
,因为只有一个。
添加了
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);