UNPKG

@omnedia/ngx-globe

Version:

A simple component library to create a container with an animated and interactive globe.

215 lines (210 loc) 11.1 kB
import * as i1 from '@angular/common'; import { isPlatformBrowser, CommonModule } from '@angular/common'; import * as i0 from '@angular/core'; import { PLATFORM_ID, Input, ViewChild, Inject, ChangeDetectionStrategy, Component } from '@angular/core'; import createGlobe from 'cobe'; class NgxGlobeComponent { cdr; platformId; globeWrapperElement; globeCanvas; styleClass; rotationSpeed = 0.005; set globeOptions(options) { this.globeSize = options.width ?? this.globeSize; this.style["--globe-size"] = this.globeSize + "px"; this.setGlobeOptions(options); if (this.globeInitialized) { this.setCanvasSize(); this.initGlobe(); } } set globeCanvasSize(size) { this.globeSize = size; this.cobeOptions.width = this.globeSize; this.cobeOptions.height = this.globeSize; this.style["--globe-size"] = size + "px"; if (this.globeInitialized) { this.setCanvasSize(); this.initGlobe(); } } style = {}; globeSize; globeInitialized = false; globe; cobeOptions = { devicePixelRatio: 2, width: this.globeSize ?? 600, height: this.globeSize ?? 600, phi: 0, theta: 0.3, dark: 0, diffuse: 0.4, scale: 1, mapSamples: 16000, mapBrightness: 1.2, baseColor: [1, 1, 1], markerColor: [251 / 255, 100 / 255, 21 / 255], glowColor: [1, 1, 1], offset: [0, 0], markers: [ { location: [14.5995, 120.9842], size: 0.03 }, { location: [19.076, 72.8777], size: 0.1 }, { location: [23.8103, 90.4125], size: 0.05 }, { location: [30.0444, 31.2357], size: 0.07 }, { location: [39.9042, 116.4074], size: 0.08 }, { location: [-23.5505, -46.6333], size: 0.1 }, { location: [19.4326, -99.1332], size: 0.1 }, { location: [40.7128, -74.006], size: 0.1 }, { location: [34.6937, 135.5022], size: 0.05 }, { location: [41.0082, 28.9784], size: 0.06 }, ], }; pointerInteracting = null; pointerInteractionMovement = 0; globeRotation = 0; intersectionObserver; isAnimating = false; constructor(cdr, platformId) { this.cdr = cdr; this.platformId = platformId; } ngAfterViewInit() { this.initCanvas(); if (isPlatformBrowser(this.platformId)) { this.intersectionObserver = new IntersectionObserver(([entry]) => { this.renderContents(entry.isIntersecting); }); this.intersectionObserver.observe(this.globeCanvas.nativeElement); } } ngOnDestroy() { this.globe?.destroy(); window.removeEventListener("resize", () => this.setCanvasSize()); } initCanvas() { if (!this.globeSize) { let width = 600; let height = 600; if (this.globeWrapperElement.nativeElement.parentElement?.parentElement) { const domRect = this.globeWrapperElement.nativeElement.parentElement.parentElement.getBoundingClientRect(); width = domRect.width; height = domRect.height; } this.globeSize = width < height ? width : height; this.cobeOptions.width = this.globeSize; this.cobeOptions.height = this.globeSize; this.style["--globe-size"] = this.globeSize + "px"; } this.cobeOptions.width = this.globeSize; this.cobeOptions.height = this.globeSize; this.setCanvasSize(); this.initGlobe(); } setCanvasSize() { this.globeCanvas.nativeElement.width = this.globeSize ?? 600; this.globeCanvas.nativeElement.height = this.globeSize ?? 600; this.cdr.detectChanges(); } renderContents(isIntersecting) { if (isIntersecting && !this.isAnimating) { this.isAnimating = true; this.globe?.toggle(true); } else if (!isIntersecting && this.isAnimating) { this.isAnimating = false; this.globe?.toggle(false); } } initGlobe() { let phi = this.cobeOptions.phi; let cobeOptions = { ...this.cobeOptions, onRender: (state) => { if (!this.pointerInteracting) { phi += this.rotationSpeed; } state.phi = phi + this.globeRotation; }, }; this.globe = createGlobe(this.globeCanvas.nativeElement, cobeOptions); this.globeInitialized = true; window.addEventListener("resize", () => this.setCanvasSize()); this.globeCanvas.nativeElement.width = this.globeSize ?? 600; this.globeCanvas.nativeElement.height = this.globeSize ?? 600; } updatePointerInteraction(value) { this.pointerInteracting = value; this.globeCanvas.nativeElement.style.cursor = value ? "grabbing" : "grab"; } updateMovement(clientX) { if (this.pointerInteracting !== null) { const delta = clientX - this.pointerInteracting; this.pointerInteractionMovement = delta; this.globeRotation = delta / 200; } } setGlobeOptions(options) { this.cobeOptions.width = options.width ?? this.cobeOptions.width; this.cobeOptions.height = options.height ?? this.cobeOptions.height; this.cobeOptions.phi = options.phi ?? this.cobeOptions.phi; this.cobeOptions.theta = options.theta ?? this.cobeOptions.theta; this.cobeOptions.mapSamples = options.mapSamples ?? this.cobeOptions.mapSamples; this.cobeOptions.mapBrightness = options.mapBrightness ?? this.cobeOptions.mapBrightness; this.cobeOptions.mapBaseBrightness = options.mapBaseBrightness ?? this.cobeOptions.mapBaseBrightness; this.cobeOptions.baseColor = options.baseColor ?? this.cobeOptions.baseColor; this.cobeOptions.markerColor = options.markerColor ?? this.cobeOptions.markerColor; this.cobeOptions.glowColor = options.glowColor ?? this.cobeOptions.glowColor; this.cobeOptions.markers = options.markers ?? this.cobeOptions.markers; this.cobeOptions.diffuse = options.diffuse ?? this.cobeOptions.diffuse; this.cobeOptions.devicePixelRatio = options.devicePixelRatio ?? this.cobeOptions.devicePixelRatio; this.cobeOptions.dark = options.dark ?? this.cobeOptions.dark; this.cobeOptions.opacity = options.opacity ?? this.cobeOptions.opacity; this.cobeOptions.offset = options.offset ?? this.cobeOptions.offset; this.cobeOptions.scale = options.scale ?? this.cobeOptions.scale; this.cobeOptions.context = options.context ?? this.cobeOptions.context; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: NgxGlobeComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.2", type: NgxGlobeComponent, isStandalone: true, selector: "om-globe", inputs: { styleClass: "styleClass", rotationSpeed: "rotationSpeed", globeOptions: "globeOptions", globeCanvasSize: ["globeSize", "globeCanvasSize"] }, viewQueries: [{ propertyName: "globeWrapperElement", first: true, predicate: ["OmGlobeWrapper"], descendants: true }, { propertyName: "globeCanvas", first: true, predicate: ["globeCanvas"], descendants: true }], ngImport: i0, template: "<div class=\"om-globe\" [ngStyle]=\"style\" #OmGlobeWrapper>\r\n <div class=\"om-globe-background\">\r\n <canvas (pointerdown)=\"updatePointerInteraction($event.clientX - pointerInteractionMovement)\"\r\n (pointerup)=\"updatePointerInteraction(null)\" (pointerout)=\"updatePointerInteraction(null)\"\r\n (mousemove)=\"updateMovement($event.clientX)\" (touchmove)=\"updateMovement($event.touches[0].clientX)\"\r\n width=\"1000\" height=\"1000\" #globeCanvas></canvas>\r\n </div>\r\n</div>\r\n", styles: [".om-globe{--globe-size: 600px;position:relative;width:var(--globe-size);height:var(--globe-size);overflow:hidden}.om-globe .om-globe-background{position:absolute;width:100%;max-width:var(--globe-size);aspect-ratio:1/1;margin-left:auto;margin-right:auto;inset:0}.om-globe .om-globe-background canvas{width:100%;height:100%;contain:layout paint size;opacity:1;cursor:grab}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.2", ngImport: i0, type: NgxGlobeComponent, decorators: [{ type: Component, args: [{ selector: "om-globe", standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"om-globe\" [ngStyle]=\"style\" #OmGlobeWrapper>\r\n <div class=\"om-globe-background\">\r\n <canvas (pointerdown)=\"updatePointerInteraction($event.clientX - pointerInteractionMovement)\"\r\n (pointerup)=\"updatePointerInteraction(null)\" (pointerout)=\"updatePointerInteraction(null)\"\r\n (mousemove)=\"updateMovement($event.clientX)\" (touchmove)=\"updateMovement($event.touches[0].clientX)\"\r\n width=\"1000\" height=\"1000\" #globeCanvas></canvas>\r\n </div>\r\n</div>\r\n", styles: [".om-globe{--globe-size: 600px;position:relative;width:var(--globe-size);height:var(--globe-size);overflow:hidden}.om-globe .om-globe-background{position:absolute;width:100%;max-width:var(--globe-size);aspect-ratio:1/1;margin-left:auto;margin-right:auto;inset:0}.om-globe .om-globe-background canvas{width:100%;height:100%;contain:layout paint size;opacity:1;cursor:grab}\n"] }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }], propDecorators: { globeWrapperElement: [{ type: ViewChild, args: ["OmGlobeWrapper"] }], globeCanvas: [{ type: ViewChild, args: ["globeCanvas"] }], styleClass: [{ type: Input, args: ["styleClass"] }], rotationSpeed: [{ type: Input, args: ["rotationSpeed"] }], globeOptions: [{ type: Input, args: ["globeOptions"] }], globeCanvasSize: [{ type: Input, args: ["globeSize"] }] } }); /* * Public API Surface of ngx-globe */ /** * Generated bundle index. Do not edit. */ export { NgxGlobeComponent }; //# sourceMappingURL=omnedia-ngx-globe.mjs.map