Part of AngularCesiumWidgetsModule
are useful geometry drawing tools:
​CirclesEditorService
- For drawing circles
​EllipsesEditorService
- For drawing ellipses and circles
​PolylinesEditorService
- For drawing polylines
​PolygonsEditorService
- For drawing polygons
​PointEditorService
- For drawing points
​RectanglesEditorService
- For drawing rectangles
​HippodromeEditorService
- For drawing hippodromes (path in cesium)
Check out our blog post about geometry drawing tools.
First Add AngularCesiumWidgetsModule
to your app.module file.
@NgModule({// ...imports: [AngularCesiumModule.forRoot(),AngularCesiumWidgetsModule,// ...],})export class AppModule {}​
Each editor service work with a with editor component. Therefor you need to create a editor-component
for each editor service, And of course somewhere under <ac-map>
.
For the Polygons editor service we will do:
<ac-map><polygons-editor></polygons-editor> // Or somewhere else in the hierarchy</ac-map>​
All editors have a similar API, the following examples are relevant to all editors
Next we just need to provide the editor service, with the editor service you will create() and edit() your geometry. You can provide the service in the root module level or any where in your hierarchy, In our Example:
@Component({...providers: [PolygonEditorService],})export class MyMapComponent {editing$: PolygonEditorObservable;constructor(private polygonEditor: PolygonsEditorService) {}startDraw() {this.editing$ = this.polygonEditor.create();// Or Edit from existing pointsconst initialPos = [Cesium.Cartesian3.fromDegrees(20, 40),Cesium.Cartesian3.fromDegrees(45, 40),Cesium.Cartesian3.fromDegrees(30, 20)];this.editing$ = this.polygonEditor.edit(initialPos);});}}
<ac-map><polygons-editor></polygons-editor></ac-map>
Check the full stackblitz example:
​
Use create()
to start creating your geometry. The default events are click for adding points and double click for finish creating the shape, these events are configurable:
startDraw() {// Each editor has it own events to configureconst editing$ = this.polygonsEditor.create({addPointEvent: CesiumEvent.RIGHT_CLICK, // Default: LEFT_CLICKaddLastPointEvent: CesiumEvent.RIGHT_CLICK, // Default: LEFT_DOUBLE_CLICKaddLastPointModifier: CesiumEventModifier.CTRL, // Default: none})}
In create mode a geometry is created from scratch, for every click on the map a new point is added to your shape. After you finish creating your shape in will change to edit mode.
In edit mode you can update, delete and add your shape positions. You can do it by dragging the points to update their locations and deleting points by right click on the point. Adding new points can be done by dragging the "virtual points" created in the edit mode - which converts the virtual point the a "real" point, of course all is configurable:
this.editing$ = this.polygonsEditor.edit(initialPositions, {pointProps: {showVirtual: true // Default: true}});
All editors return a custom Observer object that allows you to subscribe to the shape actions and to manipulate your geometry from the code. All have dispose()
method for removing the geometry.
this.editing$ = this.polygonsEditor.create();​// Stop editng and remove the geomertythis.editing$.dispose();​// Subscribe to events updatesthis.editing$.subscribe((editUpdate: PolygonEditUpdate) => {if (editUpdate.editAction === EditActions.DRAG_POINT_FINISH) {console.log(editUpdate.points); // point = position with idconsole.log(editUpdate.positions); // or just positionconsole.log(editUpdate.updatedPosition); // added position}// Enable/disable geometry editingthis.editing$.enable();this.editing$.disable();​// Get current postionsconst cartesian3Positions = this.editing$.getCurrentPoints();​// Update your positions manually (in edit mode only)this.editing$.setManually(newCartesian3s);​// Update the the first point (in edit mode only)const polygonPoints = this.editing$.getCurrentPoints();polygonPoints[0].setPosition(Cesium.Cartesian3.fromDegrees(20, 20));const newUpdatedPoints = polygonPoints.map(p => ({position: p.getPosition(),pointProps: p.props,}));this.editing$.setManually(newUpdatedPoints);​// Add new position manually (in edit mode only)const polygonPositions = this.editing$.getCurrentPoints().map(p => p.getPosition());polygonPositions.push( Cesium.Cartesian3.fromDegrees(30, 24));this.editing$.setManually(polygonPositions); // accepts Cartesian3 or Point Obj​
All editors appearance is customisable, each editor has it own configuration to change the material, size, and behaviour. Each have it's own default configuration, but you can pass your own settings.
In the following example we create a transparent polygon with a dashed outline:
// create accepts PolygonEditOptions objectconst editing$ = this.polygonsEditor.create({pointProps: {color: Cesium.Color.WHITE,pixelSize: 10,},polygonProps: {material: Cesium.Color.TRANSPARENT,},polylineProps: {material: () => new Cesium.PolylineDashMaterialProperty()}});
The editors allows you to draw labels over a shape that is being edited with one of the editors.
To add label drawing logic to your editor use the function setLabelsRenderFn()
.
setLabelsRenderFn(callback)
- receives a callback that is called every time the shape is redrawn (except when the shape is being dragged).
callback: (update: T, labels: LabelProps[]) => LabelProps[]
The callback is called with the last shape state and with an array of the current labels.
Return type: LabelProps[].
You can also use updateLabels()
to pass an array of labels of type LabelProps[]
to be drawn.
this.editing$ = this.polygonsEditor.create();​this.editing$.setLabelsRenderFn((update: PolygonEditUpdate) => {let counter = 0;const newLabels: LabelProps[] = [];update.positions.forEach(position => newLabels.push({text: `Point ${counter++}`,scale: 0.6,eyeOffset: new Cesium.Cartesian3(10, 10, -1000),fillColor: Cesium.Color.BLUE,}));return newLabels;});
You can draw over 3dTiles and terrain, the editor will clamp to the relevant 3D object. By default the the 3D drawing is false, so you must enable it:
// Enable clamp to 3dTilesthis.editing$ = this.polygonsEditor.create({clampHeightTo3D: true});​// Enbale clamp to terrainthis.editing$ = this.polygonsEditor.create({clampHeightTo3D: true,clampHeightTo3DOptions: {clampToTerrain: true, // Default: false (if true will only clamp to terrain)clampMostDetailed: true, // Fix height after finish editingclampToHeightPickWidth: 1 // scene.clampToHeight() width , 3dTiles only}});
currently supported : PolylineEditorService
, PolygonEditorService
Behind the scene the editor is using scene.pickPosition
and scene.clampToGround
for 3dTiles and camera.getPickRay()
for terrain, to set the correct height of the shape.
So the shape positions will accurate as much as the rendered model is.
Please notice, according to cesium issue, using scene.pick()
simultaneously with pickPosition()
can make the pickPosition()
return wrong height values, so try to avoid it.