UNPKG

mapillary-js

Version:

WebGL JavaScript library for displaying street level imagery from mapillary.com

209 lines (188 loc) 7.97 kB
import { concat as observableConcat, empty as observableEmpty, combineLatest as observableCombineLatest, of as observableOf, merge as observableMerge, from as observableFrom, Observable, Subscription, } from "rxjs"; import { distinctUntilChanged, share, switchMap, filter, withLatestFrom, first, map, mergeMap, } from "rxjs/operators"; import { Component, TagHandlerBase, Geometry, IInteraction, InteractionCursor, ITagConfiguration, RenderTag, Tag, TagOperation, TagSet, VertexGeometry, } from "../../../Component"; import { Transform, ViewportCoords, } from "../../../Geo"; import {RenderCamera} from "../../../Render"; import { Container, Navigator, } from "../../../Viewer"; export class EditVertexHandler extends TagHandlerBase { private _tagSet: TagSet; private _claimMouseSubscription: Subscription; private _cursorSubscription: Subscription; private _preventDefaultSubscription: Subscription; private _unclaimMouseSubscription: Subscription; private _updateGeometrySubscription: Subscription; constructor( component: Component<ITagConfiguration>, container: Container, navigator: Navigator, viewportCoords: ViewportCoords, tagSet: TagSet) { super(component, container, navigator, viewportCoords); this._tagSet = tagSet; } protected _enable(): void { const interaction$: Observable<IInteraction> = this._tagSet.changed$.pipe( map( (tagSet: TagSet): RenderTag<Tag>[] => { return tagSet.getAll(); }), switchMap( (tags: RenderTag<Tag>[]): Observable<IInteraction> => { return observableFrom(tags).pipe( mergeMap( (tag: RenderTag<Tag>): Observable<IInteraction> => { return tag.interact$; })); }), switchMap( (interaction: IInteraction): Observable<IInteraction> => { return observableConcat( observableOf(interaction), this._container.mouseService.documentMouseUp$.pipe( map( (): IInteraction => { return { offsetX: 0, offsetY: 0, operation: TagOperation.None, tag: null }; }), first())); }), share()); const mouseMove$: Observable<MouseEvent> = observableMerge( this._container.mouseService.mouseMove$, this._container.mouseService.domMouseMove$).pipe( share()); this._claimMouseSubscription = interaction$.pipe( switchMap( (interaction: IInteraction): Observable<MouseEvent> => { return !!interaction.tag ? this._container.mouseService.domMouseDragStart$ : observableEmpty(); })) .subscribe( (): void => { this._container.mouseService.claimMouse(this._name, 3); }); this._cursorSubscription = interaction$.pipe( map( (interaction: IInteraction): string => { return interaction.cursor; }), distinctUntilChanged()) .subscribe( (cursor: string): void => { const interactionCursors: InteractionCursor[] = ["crosshair", "move", "nesw-resize", "nwse-resize"]; for (const interactionCursor of interactionCursors) { this._container.element.classList.remove(`component-tag-edit-${interactionCursor}`); } if (!!cursor) { this._container.element.classList.add(`component-tag-edit-${cursor}`); } }); this._unclaimMouseSubscription = this._container.mouseService .filtered$(this._name, this._container.mouseService.domMouseDragEnd$) .subscribe( (e: MouseEvent): void => { this._container.mouseService.unclaimMouse(this._name); }); this._preventDefaultSubscription = interaction$.pipe( switchMap( (interaction: IInteraction): Observable<MouseEvent> => { return !!interaction.tag ? this._container.mouseService.documentMouseMove$ : observableEmpty(); })) .subscribe( (event: MouseEvent): void => { event.preventDefault(); // prevent selection of content outside the viewer }); this._updateGeometrySubscription = interaction$.pipe( switchMap( (interaction: IInteraction): Observable<[MouseEvent, RenderCamera, IInteraction, Transform]> => { if (interaction.operation === TagOperation.None || !interaction.tag) { return observableEmpty(); } const mouseDrag$: Observable<MouseEvent> = this._container.mouseService .filtered$( this._name, this._container.mouseService.domMouseDrag$).pipe( filter( (event: MouseEvent): boolean => { return this._viewportCoords.insideElement(event, this._container.element); })); return observableCombineLatest( mouseDrag$, this._container.renderService.renderCamera$).pipe( withLatestFrom( observableOf(interaction), this._navigator.stateService.currentTransform$, ( [event, render]: [MouseEvent, RenderCamera], i: IInteraction, transform: Transform): [MouseEvent, RenderCamera, IInteraction, Transform] => { return [event, render, i, transform]; })); })) .subscribe( ([mouseEvent, renderCamera, interaction, transform]: [MouseEvent, RenderCamera, IInteraction, Transform]): void => { const basic: number[] = this._mouseEventToBasic( mouseEvent, this._container.element, renderCamera, transform, interaction.offsetX, interaction.offsetY); const geometry: Geometry = interaction.tag.geometry; if (interaction.operation === TagOperation.Centroid) { geometry.setCentroid2d(basic, transform); } else if (interaction.operation === TagOperation.Vertex) { (<VertexGeometry>geometry).setVertex2d(interaction.vertexIndex, basic, transform); } }); } protected _disable(): void { this._claimMouseSubscription.unsubscribe(); this._cursorSubscription.unsubscribe(); this._preventDefaultSubscription.unsubscribe(); this._unclaimMouseSubscription.unsubscribe(); this._updateGeometrySubscription.unsubscribe(); } protected _getNameExtension(): string { return "edit-vertex"; } } export default EditVertexHandler;