1996 lines
69 KiB
JavaScript
1996 lines
69 KiB
JavaScript
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('three'), require('@photo-sphere-viewer/core')) :
|
|
typeof define === 'function' && define.amd ? define(['exports', 'three', '@photo-sphere-viewer/core'], factory) :
|
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.PhotoSphereViewer = global.PhotoSphereViewer || {}, global.PhotoSphereViewer.MarkersPlugin = {}), global.THREE, global.PhotoSphereViewer));
|
|
})(this, (function (exports, THREE, PhotoSphereViewer) {
|
|
|
|
console.warn('PhotoSphereViewer "index.js" scripts are deprecated and will be removed in a future version. Please use ES Modules: https://photo-sphere-viewer.js.org/guide/#your-first-viewer');
|
|
|
|
/*!
|
|
* PhotoSphereViewer.MarkersPlugin 5.7.3
|
|
* @copyright 2024 Damien "Mistic" Sorel
|
|
* @licence MIT (https://opensource.org/licenses/MIT)
|
|
*/
|
|
"use strict";
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __export = (target, all) => {
|
|
for (var name in all)
|
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
};
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
|
|
// @photo-sphere-viewer/core
|
|
var require_core = () => PhotoSphereViewer;
|
|
|
|
// three
|
|
var require_three = () => THREE;
|
|
|
|
// src/index.ts
|
|
var src_exports = {};
|
|
__export(src_exports, {
|
|
MarkersPlugin: () => MarkersPlugin,
|
|
events: () => events_exports
|
|
});
|
|
var import_core15 = require_core();
|
|
|
|
// src/events.ts
|
|
var events_exports = {};
|
|
__export(events_exports, {
|
|
EnterMarkerEvent: () => EnterMarkerEvent,
|
|
GotoMarkerDoneEvent: () => GotoMarkerDoneEvent,
|
|
HideMarkersEvent: () => HideMarkersEvent,
|
|
LeaveMarkerEvent: () => LeaveMarkerEvent,
|
|
MarkerVisibilityEvent: () => MarkerVisibilityEvent,
|
|
MarkersPluginEvent: () => MarkersPluginEvent,
|
|
RenderMarkersListEvent: () => RenderMarkersListEvent,
|
|
SelectMarkerEvent: () => SelectMarkerEvent,
|
|
SelectMarkerListEvent: () => SelectMarkerListEvent,
|
|
SetMarkersEvent: () => SetMarkersEvent,
|
|
ShowMarkersEvent: () => ShowMarkersEvent,
|
|
UnselectMarkerEvent: () => UnselectMarkerEvent
|
|
});
|
|
var import_core = require_core();
|
|
var MarkersPluginEvent = class extends import_core.TypedEvent {
|
|
};
|
|
var _MarkerVisibilityEvent = class _MarkerVisibilityEvent extends MarkersPluginEvent {
|
|
/** @internal */
|
|
constructor(marker, visible) {
|
|
super(_MarkerVisibilityEvent.type);
|
|
this.marker = marker;
|
|
this.visible = visible;
|
|
}
|
|
};
|
|
_MarkerVisibilityEvent.type = "marker-visibility";
|
|
var MarkerVisibilityEvent = _MarkerVisibilityEvent;
|
|
var _GotoMarkerDoneEvent = class _GotoMarkerDoneEvent extends MarkersPluginEvent {
|
|
/** @internal */
|
|
constructor(marker) {
|
|
super(_GotoMarkerDoneEvent.type);
|
|
this.marker = marker;
|
|
}
|
|
};
|
|
_GotoMarkerDoneEvent.type = "goto-marker-done";
|
|
var GotoMarkerDoneEvent = _GotoMarkerDoneEvent;
|
|
var _LeaveMarkerEvent = class _LeaveMarkerEvent extends MarkersPluginEvent {
|
|
/** @internal */
|
|
constructor(marker) {
|
|
super(_LeaveMarkerEvent.type);
|
|
this.marker = marker;
|
|
}
|
|
};
|
|
_LeaveMarkerEvent.type = "leave-marker";
|
|
var LeaveMarkerEvent = _LeaveMarkerEvent;
|
|
var _EnterMarkerEvent = class _EnterMarkerEvent extends MarkersPluginEvent {
|
|
/** @internal */
|
|
constructor(marker) {
|
|
super(_EnterMarkerEvent.type);
|
|
this.marker = marker;
|
|
}
|
|
};
|
|
_EnterMarkerEvent.type = "enter-marker";
|
|
var EnterMarkerEvent = _EnterMarkerEvent;
|
|
var _SelectMarkerEvent = class _SelectMarkerEvent extends MarkersPluginEvent {
|
|
/** @internal */
|
|
constructor(marker, doubleClick, rightClick) {
|
|
super(_SelectMarkerEvent.type);
|
|
this.marker = marker;
|
|
this.doubleClick = doubleClick;
|
|
this.rightClick = rightClick;
|
|
}
|
|
};
|
|
_SelectMarkerEvent.type = "select-marker";
|
|
var SelectMarkerEvent = _SelectMarkerEvent;
|
|
var _SelectMarkerListEvent = class _SelectMarkerListEvent extends MarkersPluginEvent {
|
|
/** @internal */
|
|
constructor(marker) {
|
|
super(_SelectMarkerListEvent.type);
|
|
this.marker = marker;
|
|
}
|
|
};
|
|
_SelectMarkerListEvent.type = "select-marker-list";
|
|
var SelectMarkerListEvent = _SelectMarkerListEvent;
|
|
var _UnselectMarkerEvent = class _UnselectMarkerEvent extends MarkersPluginEvent {
|
|
/** @internal */
|
|
constructor(marker) {
|
|
super(_UnselectMarkerEvent.type);
|
|
this.marker = marker;
|
|
}
|
|
};
|
|
_UnselectMarkerEvent.type = "unselect-marker";
|
|
var UnselectMarkerEvent = _UnselectMarkerEvent;
|
|
var _HideMarkersEvent = class _HideMarkersEvent extends MarkersPluginEvent {
|
|
/** @internal */
|
|
constructor() {
|
|
super(_HideMarkersEvent.type);
|
|
}
|
|
};
|
|
_HideMarkersEvent.type = "hide-markers";
|
|
var HideMarkersEvent = _HideMarkersEvent;
|
|
var _SetMarkersEvent = class _SetMarkersEvent extends MarkersPluginEvent {
|
|
/** @internal */
|
|
constructor(markers) {
|
|
super(_SetMarkersEvent.type);
|
|
this.markers = markers;
|
|
}
|
|
};
|
|
_SetMarkersEvent.type = "set-markers";
|
|
var SetMarkersEvent = _SetMarkersEvent;
|
|
var _ShowMarkersEvent = class _ShowMarkersEvent extends MarkersPluginEvent {
|
|
/** @internal */
|
|
constructor() {
|
|
super(_ShowMarkersEvent.type);
|
|
}
|
|
};
|
|
_ShowMarkersEvent.type = "show-markers";
|
|
var ShowMarkersEvent = _ShowMarkersEvent;
|
|
var _RenderMarkersListEvent = class _RenderMarkersListEvent extends MarkersPluginEvent {
|
|
/** @internal */
|
|
constructor(markers) {
|
|
super(_RenderMarkersListEvent.type);
|
|
this.markers = markers;
|
|
}
|
|
};
|
|
_RenderMarkersListEvent.type = "render-markers-list";
|
|
var RenderMarkersListEvent = _RenderMarkersListEvent;
|
|
|
|
// src/MarkersButton.ts
|
|
var import_core2 = require_core();
|
|
|
|
// src/icons/pin.svg
|
|
var pin_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="10 9 81 81"><path fill="currentColor" d="M50.5 90S22.9 51.9 22.9 36.6 35.2 9 50.5 9s27.6 12.4 27.6 27.6S50.5 90 50.5 90zm0-66.3c-6.1 0-11 4.9-11 11s4.9 11 11 11 11-4.9 11-11-4.9-11-11-11z"/><!--Created by Rohith M S from the Noun Project--></svg>\n';
|
|
|
|
// src/MarkersButton.ts
|
|
var MarkersButton = class extends import_core2.AbstractButton {
|
|
constructor(navbar) {
|
|
super(navbar, {
|
|
className: "psv-markers-button",
|
|
icon: pin_default,
|
|
hoverScale: true,
|
|
collapsable: true,
|
|
tabbable: true
|
|
});
|
|
this.plugin = this.viewer.getPlugin("markers");
|
|
if (this.plugin) {
|
|
this.plugin.addEventListener(ShowMarkersEvent.type, this);
|
|
this.plugin.addEventListener(HideMarkersEvent.type, this);
|
|
this.toggleActive(true);
|
|
}
|
|
}
|
|
destroy() {
|
|
if (this.plugin) {
|
|
this.plugin.removeEventListener(ShowMarkersEvent.type, this);
|
|
this.plugin.removeEventListener(HideMarkersEvent.type, this);
|
|
}
|
|
super.destroy();
|
|
}
|
|
isSupported() {
|
|
return !!this.plugin;
|
|
}
|
|
handleEvent(e) {
|
|
if (e instanceof ShowMarkersEvent) {
|
|
this.toggleActive(true);
|
|
} else if (e instanceof HideMarkersEvent) {
|
|
this.toggleActive(false);
|
|
}
|
|
}
|
|
onClick() {
|
|
this.plugin.toggleAllMarkers();
|
|
}
|
|
};
|
|
MarkersButton.id = "markers";
|
|
|
|
// src/MarkersListButton.ts
|
|
var import_core4 = require_core();
|
|
|
|
// src/constants.ts
|
|
var import_core3 = require_core();
|
|
|
|
// src/icons/pin-list.svg
|
|
var pin_list_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="9 9 81 81"><path fill="currentColor" d="M37.5 90S9.9 51.9 9.9 36.6 22.2 9 37.5 9s27.6 12.4 27.6 27.6S37.5 90 37.5 90zm0-66.3c-6.1 0-11 4.9-11 11s4.9 11 11 11 11-4.9 11-11-4.9-11-11-11zM86.7 55H70c-1.8 0-3.3-1.5-3.3-3.3s1.5-3.3 3.3-3.3h16.7c1.8 0 3.3 1.5 3.3 3.3S88.5 55 86.7 55zm0-25h-15a3.3 3.3 0 0 1-3.3-3.3c0-1.8 1.5-3.3 3.3-3.3h15c1.8 0 3.3 1.5 3.3 3.3 0 1.8-1.5 3.3-3.3 3.3zM56.5 73h30c1.8 0 3.3 1.5 3.3 3.3 0 1.8-1.5 3.3-3.3 3.3h-30a3.3 3.3 0 0 1-3.3-3.3 3.2 3.2 0 0 1 3.3-3.3z"/><!--Created by Rohith M S from the Noun Project--></svg>\n';
|
|
|
|
// src/constants.ts
|
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
var MARKER_DATA = "psvMarker";
|
|
var MARKER_DATA_KEY = import_core3.utils.dasherize(MARKER_DATA);
|
|
var ID_PANEL_MARKER = "marker";
|
|
var ID_PANEL_MARKERS_LIST = "markersList";
|
|
var DEFAULT_HOVER_SCALE = {
|
|
amount: 2,
|
|
duration: 100,
|
|
easing: "linear"
|
|
};
|
|
var MARKERS_LIST_TEMPLATE = (markers, title) => `
|
|
<div class="psv-panel-menu psv-panel-menu--stripped">
|
|
<h1 class="psv-panel-menu-title">${pin_list_default} ${title}</h1>
|
|
<ul class="psv-panel-menu-list">
|
|
${markers.map(
|
|
(marker) => `
|
|
<li data-${MARKER_DATA_KEY}="${marker.id}" class="psv-panel-menu-item" tabindex="0">
|
|
${marker.type === "image" ? `<span class="psv-panel-menu-item-icon"><img src="${marker.definition}"/></span>` : ""}
|
|
<span class="psv-panel-menu-item-label">${marker.getListContent()}</span>
|
|
</li>
|
|
`
|
|
).join("")}
|
|
</ul>
|
|
</div>
|
|
`;
|
|
|
|
// src/MarkersListButton.ts
|
|
var MarkersListButton = class extends import_core4.AbstractButton {
|
|
constructor(navbar) {
|
|
super(navbar, {
|
|
className: " psv-markers-list-button",
|
|
icon: pin_list_default,
|
|
hoverScale: true,
|
|
collapsable: true,
|
|
tabbable: true
|
|
});
|
|
this.plugin = this.viewer.getPlugin("markers");
|
|
if (this.plugin) {
|
|
this.viewer.addEventListener(import_core4.events.ShowPanelEvent.type, this);
|
|
this.viewer.addEventListener(import_core4.events.HidePanelEvent.type, this);
|
|
}
|
|
}
|
|
destroy() {
|
|
this.viewer.removeEventListener(import_core4.events.ShowPanelEvent.type, this);
|
|
this.viewer.removeEventListener(import_core4.events.HidePanelEvent.type, this);
|
|
super.destroy();
|
|
}
|
|
isSupported() {
|
|
return !!this.plugin;
|
|
}
|
|
handleEvent(e) {
|
|
if (e instanceof import_core4.events.ShowPanelEvent) {
|
|
this.toggleActive(e.panelId === ID_PANEL_MARKERS_LIST);
|
|
} else if (e instanceof import_core4.events.HidePanelEvent) {
|
|
this.toggleActive(false);
|
|
}
|
|
}
|
|
onClick() {
|
|
this.plugin.toggleMarkersList();
|
|
}
|
|
};
|
|
MarkersListButton.id = "markersList";
|
|
|
|
// src/MarkersPlugin.ts
|
|
var import_core14 = require_core();
|
|
|
|
// src/markers/AbstractStandardMarker.ts
|
|
var import_core8 = require_core();
|
|
var import_three = require_three();
|
|
|
|
// src/MarkerType.ts
|
|
var import_core5 = require_core();
|
|
var MarkerType = /* @__PURE__ */ ((MarkerType3) => {
|
|
MarkerType3["image"] = "image";
|
|
MarkerType3["html"] = "html";
|
|
MarkerType3["element"] = "element";
|
|
MarkerType3["imageLayer"] = "imageLayer";
|
|
MarkerType3["videoLayer"] = "videoLayer";
|
|
MarkerType3["polygon"] = "polygon";
|
|
MarkerType3["polygonPixels"] = "polygonPixels";
|
|
MarkerType3["polyline"] = "polyline";
|
|
MarkerType3["polylinePixels"] = "polylinePixels";
|
|
MarkerType3["square"] = "square";
|
|
MarkerType3["rect"] = "rect";
|
|
MarkerType3["circle"] = "circle";
|
|
MarkerType3["ellipse"] = "ellipse";
|
|
MarkerType3["path"] = "path";
|
|
return MarkerType3;
|
|
})(MarkerType || {});
|
|
function getMarkerType(config, allowNone = false) {
|
|
const found = [];
|
|
Object.keys(MarkerType).forEach((type) => {
|
|
if (config[type]) {
|
|
found.push(type);
|
|
}
|
|
});
|
|
if (found.length === 0 && !allowNone) {
|
|
throw new import_core5.PSVError(`missing marker content, either ${Object.keys(MarkerType).join(", ")}`);
|
|
} else if (found.length > 1) {
|
|
throw new import_core5.PSVError(`multiple marker content, either ${Object.keys(MarkerType).join(", ")}`);
|
|
}
|
|
return found[0];
|
|
}
|
|
|
|
// src/markers/AbstractDomMarker.ts
|
|
var import_core7 = require_core();
|
|
|
|
// src/markers/Marker.ts
|
|
var import_core6 = require_core();
|
|
var Marker = class {
|
|
constructor(viewer, plugin, config) {
|
|
this.viewer = viewer;
|
|
this.plugin = plugin;
|
|
/** @internal */
|
|
this.state = {
|
|
dynamicSize: false,
|
|
anchor: null,
|
|
visible: false,
|
|
staticTooltip: false,
|
|
position: null,
|
|
position2D: null,
|
|
positions3D: null,
|
|
size: null
|
|
};
|
|
if (!config.id) {
|
|
throw new import_core6.PSVError("missing marker id");
|
|
}
|
|
this.type = getMarkerType(config);
|
|
this.createElement();
|
|
this.update(config);
|
|
}
|
|
get id() {
|
|
return this.config.id;
|
|
}
|
|
get data() {
|
|
return this.config.data;
|
|
}
|
|
get domElement() {
|
|
return null;
|
|
}
|
|
get threeElement() {
|
|
return null;
|
|
}
|
|
get video() {
|
|
return null;
|
|
}
|
|
/**
|
|
* @internal
|
|
*/
|
|
destroy() {
|
|
delete this.viewer;
|
|
delete this.plugin;
|
|
this.hideTooltip();
|
|
}
|
|
/**
|
|
* Checks if it is a 3D marker (imageLayer, videoLayer)
|
|
*/
|
|
is3d() {
|
|
return false;
|
|
}
|
|
/**
|
|
* Checks if it is a normal marker (image, html, element)
|
|
*/
|
|
isNormal() {
|
|
return false;
|
|
}
|
|
/**
|
|
* Checks if it is a polygon/polyline marker
|
|
*/
|
|
isPoly() {
|
|
return false;
|
|
}
|
|
/**
|
|
* Checks if it is an SVG marker
|
|
*/
|
|
isSvg() {
|
|
return false;
|
|
}
|
|
/**
|
|
* Updates the marker with new properties
|
|
* @throws {@link PSVError} if the configuration is invalid
|
|
* @internal
|
|
*/
|
|
update(config) {
|
|
const newType = getMarkerType(config, true);
|
|
if (newType !== void 0 && newType !== this.type) {
|
|
throw new import_core6.PSVError("cannot change marker type");
|
|
}
|
|
if (import_core6.utils.isExtendedPosition(config)) {
|
|
import_core6.utils.logWarn('Use the "position" property to configure the position of a marker');
|
|
config.position = this.viewer.dataHelper.cleanPosition(config);
|
|
}
|
|
if ("width" in config && "height" in config) {
|
|
import_core6.utils.logWarn('Use the "size" property to configure the size of a marker');
|
|
config.size = { width: config["width"], height: config["height"] };
|
|
}
|
|
this.config = import_core6.utils.deepmerge(this.config, config);
|
|
if (typeof this.config.tooltip === "string") {
|
|
this.config.tooltip = { content: this.config.tooltip };
|
|
}
|
|
if (this.config.tooltip && !this.config.tooltip.trigger) {
|
|
this.config.tooltip.trigger = "hover";
|
|
}
|
|
if (import_core6.utils.isNil(this.config.visible)) {
|
|
this.config.visible = true;
|
|
}
|
|
if (import_core6.utils.isNil(this.config.zIndex)) {
|
|
this.config.zIndex = 1;
|
|
}
|
|
if (import_core6.utils.isNil(this.config.opacity)) {
|
|
this.config.opacity = 1;
|
|
}
|
|
try {
|
|
this.config.rotation = import_core6.utils.parseAngle(this.config.rotation ?? 0);
|
|
} catch (e) {
|
|
import_core6.utils.logWarn(e.message);
|
|
this.config.rotation = 0;
|
|
}
|
|
this.state.anchor = import_core6.utils.parsePoint(this.config.anchor);
|
|
}
|
|
/**
|
|
* Returns the markers list content for the marker, it can be either :
|
|
* - the `listContent`
|
|
* - the `tooltip`
|
|
* - the `html`
|
|
* - the `id`
|
|
* @internal
|
|
*/
|
|
getListContent() {
|
|
if (this.config.listContent) {
|
|
return this.config.listContent;
|
|
} else if (this.config.tooltip?.content) {
|
|
return this.config.tooltip.content;
|
|
} else if (this.config.html) {
|
|
return this.config.html;
|
|
} else {
|
|
return this.id;
|
|
}
|
|
}
|
|
/**
|
|
* Display the tooltip of this marker
|
|
* @internal
|
|
*/
|
|
showTooltip(clientX, clientY) {
|
|
if (this.state.visible && this.config.tooltip?.content && this.state.position2D) {
|
|
const config = {
|
|
...this.config.tooltip,
|
|
style: {
|
|
// prevents conflicts with tooltip tracking
|
|
pointerEvents: this.state.staticTooltip ? "auto" : "none"
|
|
},
|
|
data: this,
|
|
top: 0,
|
|
left: 0
|
|
};
|
|
if (this.isPoly() || this.is3d()) {
|
|
if (clientX || clientY) {
|
|
const viewerPos = import_core6.utils.getPosition(this.viewer.container);
|
|
config.top = clientY - viewerPos.y;
|
|
config.left = clientX - viewerPos.x;
|
|
config.box = {
|
|
// separate the tooltip from the cursor
|
|
width: 20,
|
|
height: 20
|
|
};
|
|
} else {
|
|
config.top = this.state.position2D.y;
|
|
config.left = this.state.position2D.x;
|
|
}
|
|
} else {
|
|
const position = this.viewer.dataHelper.vector3ToViewerCoords(this.state.positions3D[0]);
|
|
let width = this.state.size.width;
|
|
let height = this.state.size.height;
|
|
if (this.config.hoverScale && !this.state.staticTooltip) {
|
|
width *= this.config.hoverScale.amount;
|
|
height *= this.config.hoverScale.amount;
|
|
}
|
|
config.top = position.y - height * this.state.anchor.y + height / 2;
|
|
config.left = position.x - width * this.state.anchor.x + width / 2;
|
|
config.box = { width, height };
|
|
}
|
|
if (this.tooltip) {
|
|
this.tooltip.update(this.config.tooltip.content, config);
|
|
} else {
|
|
this.tooltip = this.viewer.createTooltip(config);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Hides the tooltip of this marker
|
|
* @internal
|
|
*/
|
|
hideTooltip() {
|
|
if (this.tooltip) {
|
|
this.tooltip.hide();
|
|
this.tooltip = null;
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/markers/AbstractDomMarker.ts
|
|
var AbstractDomMarker = class extends Marker {
|
|
get domElement() {
|
|
return this.element;
|
|
}
|
|
constructor(viewer, plugin, config) {
|
|
super(viewer, plugin, config);
|
|
}
|
|
destroy() {
|
|
delete this.element[MARKER_DATA];
|
|
super.destroy();
|
|
}
|
|
update(config) {
|
|
super.update(config);
|
|
const element = this.domElement;
|
|
element.id = `psv-marker-${this.config.id}`;
|
|
element.setAttribute("class", "psv-marker");
|
|
if (this.state.visible) {
|
|
element.classList.add("psv-marker--visible");
|
|
}
|
|
if (this.config.tooltip) {
|
|
element.classList.add("psv-marker--has-tooltip");
|
|
}
|
|
if (this.config.content) {
|
|
element.classList.add("psv-marker--has-content");
|
|
}
|
|
if (this.config.className) {
|
|
import_core7.utils.addClasses(element, this.config.className);
|
|
}
|
|
element.style.opacity = `${this.config.opacity}`;
|
|
element.style.zIndex = `${30 + this.config.zIndex}`;
|
|
if (this.config.style) {
|
|
Object.assign(element.style, this.config.style);
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/markers/AbstractStandardMarker.ts
|
|
var AbstractStandardMarker = class extends AbstractDomMarker {
|
|
constructor(viewer, plugin, config) {
|
|
super(viewer, plugin, config);
|
|
}
|
|
createElement() {
|
|
this.element[MARKER_DATA] = this;
|
|
this.domElement.addEventListener("transitionend", () => {
|
|
this.domElement.style.transition = "";
|
|
});
|
|
}
|
|
render({
|
|
viewerPosition,
|
|
zoomLevel,
|
|
hoveringMarker
|
|
}) {
|
|
this.__updateSize();
|
|
const position = this.viewer.dataHelper.vector3ToViewerCoords(this.state.positions3D[0]);
|
|
position.x -= this.state.size.width * this.state.anchor.x;
|
|
position.y -= this.state.size.height * this.state.anchor.y;
|
|
const isVisible = this.state.positions3D[0].dot(this.viewer.state.direction) > 0 && position.x + this.state.size.width >= 0 && position.x - this.state.size.width <= this.viewer.state.size.width && position.y + this.state.size.height >= 0 && position.y - this.state.size.height <= this.viewer.state.size.height;
|
|
if (isVisible) {
|
|
this.domElement.style.transform = `translate(${position.x}px,${position.y}px)`;
|
|
this.applyScale({
|
|
zoomLevel,
|
|
viewerPosition,
|
|
mouseover: this === hoveringMarker
|
|
});
|
|
if (this.type === "element" /* element */) {
|
|
this.config.element.updateMarker?.({
|
|
marker: this,
|
|
position,
|
|
viewerPosition,
|
|
zoomLevel,
|
|
viewerSize: this.viewer.state.size
|
|
});
|
|
}
|
|
return position;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
update(config) {
|
|
super.update(config);
|
|
const element = this.domElement;
|
|
element.classList.add("psv-marker--normal");
|
|
if (this.config.scale && Array.isArray(this.config.scale)) {
|
|
this.config.scale = { zoom: this.config.scale };
|
|
}
|
|
if (typeof this.config.hoverScale === "boolean") {
|
|
this.config.hoverScale = this.config.hoverScale ? this.plugin.config.defaultHoverScale || DEFAULT_HOVER_SCALE : null;
|
|
} else if (typeof this.config.hoverScale === "number") {
|
|
this.config.hoverScale = { amount: this.config.hoverScale };
|
|
} else if (!this.config.hoverScale) {
|
|
this.config.hoverScale = this.plugin.config.defaultHoverScale;
|
|
}
|
|
if (this.config.hoverScale) {
|
|
this.config.hoverScale = {
|
|
...DEFAULT_HOVER_SCALE,
|
|
...this.plugin.config.defaultHoverScale,
|
|
...this.config.hoverScale
|
|
};
|
|
}
|
|
element.style.rotate = this.config.rotation !== 0 ? import_three.MathUtils.radToDeg(this.config.rotation) + "deg" : null;
|
|
}
|
|
/**
|
|
* Computes the real size of a marker
|
|
* @description This is done by removing all it's transformations (if any) and making it visible
|
|
* before querying its bounding rect
|
|
*/
|
|
__updateSize() {
|
|
if (!this.state.dynamicSize) {
|
|
return;
|
|
}
|
|
const element = this.domElement;
|
|
const init = !this.state.size;
|
|
if (init) {
|
|
element.classList.add("psv-marker--transparent");
|
|
}
|
|
if (this.isSvg()) {
|
|
const rect = element.firstElementChild.getBoundingClientRect();
|
|
this.state.size = {
|
|
width: rect.width,
|
|
height: rect.height
|
|
};
|
|
} else if (this.isNormal()) {
|
|
this.state.size = {
|
|
width: element.offsetWidth,
|
|
height: element.offsetHeight
|
|
};
|
|
}
|
|
if (init) {
|
|
element.classList.remove("psv-marker--transparent");
|
|
}
|
|
if (this.isSvg()) {
|
|
element.style.width = this.state.size.width + "px";
|
|
element.style.height = this.state.size.height + "px";
|
|
}
|
|
if (this.type !== "element" /* element */) {
|
|
this.state.dynamicSize = false;
|
|
}
|
|
}
|
|
/**
|
|
* Computes and applies the scale to the marker
|
|
*/
|
|
applyScale({
|
|
zoomLevel,
|
|
viewerPosition,
|
|
mouseover
|
|
}) {
|
|
if (mouseover !== null && this.config.hoverScale) {
|
|
this.domElement.style.transition = `scale ${this.config.hoverScale.duration}ms ${this.config.hoverScale.easing}`;
|
|
}
|
|
let scale = 1;
|
|
if (typeof this.config.scale === "function") {
|
|
scale = this.config.scale(zoomLevel, viewerPosition);
|
|
} else if (this.config.scale) {
|
|
if (Array.isArray(this.config.scale.zoom)) {
|
|
const [min, max] = this.config.scale.zoom;
|
|
scale *= min + (max - min) * import_core8.CONSTANTS.EASINGS.inQuad(zoomLevel / 100);
|
|
}
|
|
if (Array.isArray(this.config.scale.yaw)) {
|
|
const [min, max] = this.config.scale.yaw;
|
|
const halfFov = import_three.MathUtils.degToRad(this.viewer.state.hFov) / 2;
|
|
const arc = Math.abs(import_core8.utils.getShortestArc(this.state.position.yaw, viewerPosition.yaw));
|
|
scale *= max + (min - max) * import_core8.CONSTANTS.EASINGS.outQuad(Math.max(0, (halfFov - arc) / halfFov));
|
|
}
|
|
}
|
|
if (mouseover && this.config.hoverScale) {
|
|
scale *= this.config.hoverScale.amount;
|
|
}
|
|
let child = this.domElement.children[0]
|
|
child && (child.style.transform = `scale(${scale})`);
|
|
}
|
|
};
|
|
|
|
// src/markers/MarkerNormal.ts
|
|
var import_core9 = require_core();
|
|
var MarkerNormal = class extends AbstractStandardMarker {
|
|
constructor(viewer, plugin, config) {
|
|
super(viewer, plugin, config);
|
|
}
|
|
isNormal() {
|
|
return true;
|
|
}
|
|
createElement() {
|
|
this.element = document.createElement("div");
|
|
super.createElement();
|
|
}
|
|
update(config) {
|
|
super.update(config);
|
|
const element = this.domElement;
|
|
if (!import_core9.utils.isExtendedPosition(this.config.position)) {
|
|
throw new import_core9.PSVError("missing marker position");
|
|
}
|
|
if (this.config.image && !this.config.size) {
|
|
throw new import_core9.PSVError("missing marker size");
|
|
}
|
|
if (this.config.size) {
|
|
this.state.dynamicSize = false;
|
|
this.state.size = this.config.size;
|
|
element.style.width = this.config.size.width + "px";
|
|
element.style.height = this.config.size.height + "px";
|
|
} else {
|
|
this.state.dynamicSize = true;
|
|
}
|
|
switch (this.type) {
|
|
case "image" /* image */:
|
|
this.definition = this.config.image;
|
|
element.style.backgroundImage = `url("${this.config.image}")`;
|
|
break;
|
|
case "html" /* html */:
|
|
this.definition = this.config.html;
|
|
element.innerHTML = this.config.html;
|
|
break;
|
|
case "element" /* element */:
|
|
if (this.definition !== this.config.element) {
|
|
this.definition = this.config.element;
|
|
element.childNodes.forEach((n) => n.remove());
|
|
element.appendChild(this.config.element);
|
|
this.config.element.style.display = "block";
|
|
}
|
|
break;
|
|
}
|
|
element.style.transformOrigin = `${this.state.anchor.x * 100}% ${this.state.anchor.y * 100}%`;
|
|
this.state.position = this.viewer.dataHelper.cleanPosition(this.config.position);
|
|
this.state.positions3D = [this.viewer.dataHelper.sphericalCoordsToVector3(this.state.position)];
|
|
}
|
|
};
|
|
|
|
// src/markers/Marker3D.ts
|
|
var import_core11 = require_core();
|
|
var import_three4 = require_three();
|
|
|
|
// ../shared/ChromaKeyMaterial.ts
|
|
var import_three2 = require_three();
|
|
|
|
// ../shared/shaders/chromaKey.fragment.glsl
|
|
var chromaKey_fragment_default = "// https://www.8thwall.com/playground/chromakey-threejs\n\nuniform sampler2D map;\nuniform float alpha;\nuniform bool keying;\nuniform vec3 color;\nuniform float similarity;\nuniform float smoothness;\nuniform float spill;\n\nvarying vec2 vUv;\n\nvec2 RGBtoUV(vec3 rgb) {\n return vec2(\n rgb.r * -0.169 + rgb.g * -0.331 + rgb.b * 0.5 + 0.5,\n rgb.r * 0.5 + rgb.g * -0.419 + rgb.b * -0.081 + 0.5\n );\n}\n\nvoid main(void) {\n gl_FragColor = texture2D(map, vUv);\n\n if (keying) {\n float chromaDist = distance(RGBtoUV(gl_FragColor.rgb), RGBtoUV(color));\n\n float baseMask = chromaDist - similarity;\n float fullMask = pow(clamp(baseMask / smoothness, 0., 1.), 1.5);\n gl_FragColor.a *= fullMask * alpha;\n\n float spillVal = pow(clamp(baseMask / spill, 0., 1.), 1.5);\n float desat = clamp(gl_FragColor.r * 0.2126 + gl_FragColor.g * 0.7152 + gl_FragColor.b * 0.0722, 0., 1.);\n gl_FragColor.rgb = mix(vec3(desat, desat, desat), gl_FragColor.rgb, spillVal);\n } else {\n gl_FragColor.a *= alpha;\n }\n}\n";
|
|
|
|
// ../shared/shaders/chromaKey.vertex.glsl
|
|
var chromaKey_vertex_default = "varying vec2 vUv;\nuniform vec2 repeat;\nuniform vec2 offset;\n\nvoid main() {\n vUv = uv * repeat + offset;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}\n";
|
|
|
|
// ../shared/ChromaKeyMaterial.ts
|
|
var ChromaKeyMaterial = class extends import_three2.ShaderMaterial {
|
|
constructor(params) {
|
|
super({
|
|
transparent: true,
|
|
depthTest: false,
|
|
uniforms: {
|
|
map: { value: params?.map },
|
|
repeat: { value: new import_three2.Vector2(1, 1) },
|
|
offset: { value: new import_three2.Vector2(0, 0) },
|
|
alpha: { value: params?.alpha ?? 1 },
|
|
keying: { value: false },
|
|
color: { value: new import_three2.Color(65280) },
|
|
similarity: { value: 0.2 },
|
|
smoothness: { value: 0.2 },
|
|
spill: { value: 0.1 }
|
|
},
|
|
vertexShader: chromaKey_vertex_default,
|
|
fragmentShader: chromaKey_fragment_default
|
|
});
|
|
this.chromaKey = params?.chromaKey;
|
|
}
|
|
get map() {
|
|
return this.uniforms.map.value;
|
|
}
|
|
set map(map) {
|
|
this.uniforms.map.value = map;
|
|
}
|
|
set alpha(alpha) {
|
|
this.uniforms.alpha.value = alpha;
|
|
}
|
|
get offset() {
|
|
return this.uniforms.offset.value;
|
|
}
|
|
get repeat() {
|
|
return this.uniforms.repeat.value;
|
|
}
|
|
set chromaKey(chromaKey) {
|
|
this.uniforms.keying.value = chromaKey?.enabled === true;
|
|
if (chromaKey?.enabled) {
|
|
if (typeof chromaKey.color === "object" && "r" in chromaKey.color) {
|
|
this.uniforms.color.value.set(
|
|
chromaKey.color.r / 255,
|
|
chromaKey.color.g / 255,
|
|
chromaKey.color.b / 255
|
|
);
|
|
} else {
|
|
this.uniforms.color.value.set(chromaKey.color ?? 65280);
|
|
}
|
|
this.uniforms.similarity.value = chromaKey.similarity ?? 0.2;
|
|
this.uniforms.smoothness.value = chromaKey.smoothness ?? 0.2;
|
|
}
|
|
}
|
|
};
|
|
|
|
// ../shared/video-utils.ts
|
|
function createVideo({
|
|
src,
|
|
withCredentials,
|
|
muted,
|
|
autoplay
|
|
}) {
|
|
const video = document.createElement("video");
|
|
video.crossOrigin = withCredentials ? "use-credentials" : "anonymous";
|
|
video.loop = true;
|
|
video.playsInline = true;
|
|
video.autoplay = autoplay;
|
|
video.muted = muted;
|
|
video.preload = "metadata";
|
|
video.src = src;
|
|
return video;
|
|
}
|
|
|
|
// src/utils.ts
|
|
var import_core10 = require_core();
|
|
var import_three3 = require_three();
|
|
function greatArcIntermediaryPoint(p1, p2, f) {
|
|
const [\u03BB1, \u03C61] = p1;
|
|
const [\u03BB2, \u03C62] = p2;
|
|
const r = import_core10.utils.greatArcDistance(p1, p2);
|
|
const a = Math.sin((1 - f) * r) / Math.sin(r);
|
|
const b = Math.sin(f * r) / Math.sin(r);
|
|
const x = a * Math.cos(\u03C61) * Math.cos(\u03BB1) + b * Math.cos(\u03C62) * Math.cos(\u03BB2);
|
|
const y = a * Math.cos(\u03C61) * Math.sin(\u03BB1) + b * Math.cos(\u03C62) * Math.sin(\u03BB2);
|
|
const z = a * Math.sin(\u03C61) + b * Math.sin(\u03C62);
|
|
return [Math.atan2(y, x), Math.atan2(z, Math.sqrt(x * x + y * y))];
|
|
}
|
|
function getPolygonCoherentPoints(points) {
|
|
const workPoints = [points[0]];
|
|
let k = 0;
|
|
for (let i = 1; i < points.length; i++) {
|
|
const d = points[i - 1][0] - points[i][0];
|
|
if (d > Math.PI) {
|
|
k += 1;
|
|
} else if (d < -Math.PI) {
|
|
k -= 1;
|
|
}
|
|
workPoints.push([points[i][0] + k * 2 * Math.PI, points[i][1]]);
|
|
}
|
|
return workPoints;
|
|
}
|
|
function getPolygonCenter(polygon) {
|
|
const points = getPolygonCoherentPoints(polygon);
|
|
const sum = points.reduce((intermediary, point) => [intermediary[0] + point[0], intermediary[1] + point[1]]);
|
|
return [import_core10.utils.parseAngle(sum[0] / polygon.length), sum[1] / polygon.length];
|
|
}
|
|
function getPolylineCenter(polyline) {
|
|
const points = getPolygonCoherentPoints(polyline);
|
|
let length = 0;
|
|
const lengths = [];
|
|
for (let i = 0; i < points.length - 1; i++) {
|
|
const l = import_core10.utils.greatArcDistance(points[i], points[i + 1]) * import_core10.CONSTANTS.SPHERE_RADIUS;
|
|
lengths.push(l);
|
|
length += l;
|
|
}
|
|
let consumed = 0;
|
|
for (let j = 0; j < points.length - 1; j++) {
|
|
if (consumed + lengths[j] > length / 2) {
|
|
const r = (length / 2 - consumed) / lengths[j];
|
|
return greatArcIntermediaryPoint(points[j], points[j + 1], r);
|
|
}
|
|
consumed += lengths[j];
|
|
}
|
|
return points[Math.round(points.length / 2)];
|
|
}
|
|
var C = new import_three3.Vector3();
|
|
var N = new import_three3.Vector3();
|
|
var V = new import_three3.Vector3();
|
|
var X = new import_three3.Vector3();
|
|
var Y = new import_three3.Vector3();
|
|
var A = new import_three3.Vector3();
|
|
function getGreatCircleIntersection(P1, P2, direction) {
|
|
C.copy(direction).normalize();
|
|
N.crossVectors(P1, P2).normalize();
|
|
V.crossVectors(N, P1).normalize();
|
|
X.copy(P1).multiplyScalar(-C.dot(V));
|
|
Y.copy(V).multiplyScalar(C.dot(P1));
|
|
const H = new import_three3.Vector3().addVectors(X, Y).normalize();
|
|
A.crossVectors(H, C);
|
|
return H.applyAxisAngle(A, 0.01).multiplyScalar(import_core10.CONSTANTS.SPHERE_RADIUS);
|
|
}
|
|
|
|
// src/markers/Marker3D.ts
|
|
var Marker3D = class extends Marker {
|
|
get threeElement() {
|
|
return this.element;
|
|
}
|
|
get threeMesh() {
|
|
return this.threeElement.children[0];
|
|
}
|
|
get video() {
|
|
if (this.type === "videoLayer" /* videoLayer */) {
|
|
return this.threeMesh.material.map.image;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
constructor(viewer, plugin, config) {
|
|
super(viewer, plugin, config);
|
|
}
|
|
is3d() {
|
|
return true;
|
|
}
|
|
createElement() {
|
|
const material = new ChromaKeyMaterial({ alpha: 0 });
|
|
const geometry = new import_three4.PlaneGeometry(1, 1);
|
|
const mesh = new import_three4.Mesh(geometry, material);
|
|
mesh.userData = { [MARKER_DATA]: this };
|
|
Object.defineProperty(mesh, "visible", {
|
|
enumerable: true,
|
|
get: function() {
|
|
return this.userData[MARKER_DATA].state.visible;
|
|
},
|
|
set: function(visible) {
|
|
this.userData[MARKER_DATA].state.visible = visible;
|
|
}
|
|
});
|
|
this.element = new import_three4.Group().add(mesh);
|
|
if (this.type === "videoLayer" /* videoLayer */) {
|
|
this.viewer.needsContinuousUpdate(true);
|
|
}
|
|
}
|
|
destroy() {
|
|
delete this.threeMesh.userData[MARKER_DATA];
|
|
if (this.type === "videoLayer" /* videoLayer */) {
|
|
this.video.pause();
|
|
this.viewer.needsContinuousUpdate(false);
|
|
}
|
|
super.destroy();
|
|
}
|
|
render() {
|
|
if (this.viewer.renderer.isObjectVisible(this.threeMesh)) {
|
|
return this.viewer.dataHelper.sphericalCoordsToViewerCoords(this.state.position);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
update(config) {
|
|
super.update(config);
|
|
const mesh = this.threeMesh;
|
|
const group = mesh.parent;
|
|
const material = mesh.material;
|
|
this.state.dynamicSize = false;
|
|
if (import_core11.utils.isExtendedPosition(this.config.position)) {
|
|
if (!this.config.size) {
|
|
throw new import_core11.PSVError("missing marker size");
|
|
}
|
|
this.state.position = this.viewer.dataHelper.cleanPosition(this.config.position);
|
|
this.state.size = this.config.size;
|
|
mesh.scale.set(this.config.size.width / 100, this.config.size.height / 100, 1);
|
|
mesh.position.set(mesh.scale.x * (0.5 - this.state.anchor.x), mesh.scale.y * (this.state.anchor.y - 0.5), 0);
|
|
mesh.rotation.set(0, 0, -this.config.rotation);
|
|
this.viewer.dataHelper.sphericalCoordsToVector3(this.state.position, group.position);
|
|
group.lookAt(0, group.position.y, 0);
|
|
switch (this.config.orientation) {
|
|
case "horizontal":
|
|
group.rotateX(this.state.position.pitch < 0 ? -Math.PI / 2 : Math.PI / 2);
|
|
break;
|
|
case "vertical-left":
|
|
group.rotateY(-Math.PI * 0.4);
|
|
break;
|
|
case "vertical-right":
|
|
group.rotateY(Math.PI * 0.4);
|
|
break;
|
|
}
|
|
const p = mesh.geometry.getAttribute("position");
|
|
this.state.positions3D = [0, 1, 3, 2].map((i) => {
|
|
const v3 = new import_three4.Vector3();
|
|
v3.fromBufferAttribute(p, i);
|
|
return mesh.localToWorld(v3);
|
|
});
|
|
} else {
|
|
if (this.config.position?.length !== 4) {
|
|
throw new import_core11.PSVError("missing marker position");
|
|
}
|
|
const positions = this.config.position.map((p2) => this.viewer.dataHelper.cleanPosition(p2));
|
|
const positions3D = positions.map((p2) => this.viewer.dataHelper.sphericalCoordsToVector3(p2));
|
|
const centroid = getPolygonCenter(positions.map(({ yaw, pitch }) => [yaw, pitch]));
|
|
this.state.position = { yaw: centroid[0], pitch: centroid[1] };
|
|
this.state.positions3D = positions3D;
|
|
const p = mesh.geometry.getAttribute("position");
|
|
[
|
|
positions3D[0],
|
|
positions3D[1],
|
|
positions3D[3],
|
|
// not a mistake!
|
|
positions3D[2]
|
|
].forEach((v, i) => {
|
|
p.setX(i, v.x);
|
|
p.setY(i, v.y);
|
|
p.setZ(i, v.z);
|
|
});
|
|
p.needsUpdate = true;
|
|
this.__setTextureWrap(material);
|
|
}
|
|
switch (this.type) {
|
|
case "videoLayer" /* videoLayer */:
|
|
if (this.definition !== this.config.videoLayer) {
|
|
material.map?.dispose();
|
|
const video = createVideo({
|
|
src: this.config.videoLayer,
|
|
withCredentials: this.viewer.config.withCredentials,
|
|
muted: true,
|
|
autoplay: this.config.autoplay ?? true
|
|
});
|
|
const texture = new import_three4.VideoTexture(video);
|
|
material.map = texture;
|
|
material.alpha = 0;
|
|
video.addEventListener("loadedmetadata", () => {
|
|
if (!this.viewer) {
|
|
return;
|
|
}
|
|
material.alpha = this.config.opacity;
|
|
if (!import_core11.utils.isExtendedPosition(this.config.position)) {
|
|
mesh.material.userData[MARKER_DATA] = { width: video.videoWidth, height: video.videoHeight };
|
|
this.__setTextureWrap(material);
|
|
}
|
|
}, { once: true });
|
|
this.definition = this.config.videoLayer;
|
|
} else {
|
|
material.alpha = this.config.opacity;
|
|
}
|
|
break;
|
|
case "imageLayer" /* imageLayer */:
|
|
if (this.definition !== this.config.imageLayer) {
|
|
material.map?.dispose();
|
|
const texture = new import_three4.Texture();
|
|
material.map = texture;
|
|
material.alpha = 0;
|
|
this.viewer.textureLoader.loadImage(this.config.imageLayer).then((image) => {
|
|
if (!this.viewer) {
|
|
return;
|
|
}
|
|
if (!import_core11.utils.isExtendedPosition(this.config.position)) {
|
|
mesh.material.userData[MARKER_DATA] = { width: image.width, height: image.height };
|
|
this.__setTextureWrap(material);
|
|
}
|
|
texture.image = image;
|
|
texture.anisotropy = 4;
|
|
texture.needsUpdate = true;
|
|
material.alpha = this.config.opacity;
|
|
this.viewer.needsUpdate();
|
|
});
|
|
this.definition = this.config.imageLayer;
|
|
} else {
|
|
material.alpha = this.config.opacity;
|
|
}
|
|
break;
|
|
}
|
|
material.chromaKey = this.config.chromaKey;
|
|
mesh.renderOrder = 1e3 + this.config.zIndex;
|
|
mesh.geometry.boundingBox = null;
|
|
}
|
|
/**
|
|
* For layers positionned by corners, applies offset to the texture in order to keep its proportions
|
|
*/
|
|
__setTextureWrap(material) {
|
|
const imageSize = material.userData[MARKER_DATA];
|
|
if (!imageSize || !imageSize.height || !imageSize.width) {
|
|
material.repeat.set(1, 1);
|
|
material.offset.set(0, 0);
|
|
return;
|
|
}
|
|
const positions = this.config.position.map((p) => {
|
|
return this.viewer.dataHelper.cleanPosition(p);
|
|
});
|
|
const w1 = import_core11.utils.greatArcDistance(
|
|
[positions[0].yaw, positions[0].pitch],
|
|
[positions[1].yaw, positions[1].pitch]
|
|
);
|
|
const w2 = import_core11.utils.greatArcDistance(
|
|
[positions[3].yaw, positions[3].pitch],
|
|
[positions[2].yaw, positions[2].pitch]
|
|
);
|
|
const h1 = import_core11.utils.greatArcDistance(
|
|
[positions[1].yaw, positions[1].pitch],
|
|
[positions[2].yaw, positions[2].pitch]
|
|
);
|
|
const h2 = import_core11.utils.greatArcDistance(
|
|
[positions[0].yaw, positions[0].pitch],
|
|
[positions[3].yaw, positions[3].pitch]
|
|
);
|
|
const layerRatio = (w1 + w2) / (h1 + h2);
|
|
const imageRatio = imageSize.width / imageSize.height;
|
|
let hMargin = 0;
|
|
let vMargin = 0;
|
|
if (layerRatio < imageRatio) {
|
|
hMargin = imageRatio - layerRatio;
|
|
} else {
|
|
vMargin = 1 / imageRatio - 1 / layerRatio;
|
|
}
|
|
material.repeat.set(1 - hMargin, 1 - vMargin);
|
|
material.offset.set(hMargin / 2, vMargin / 2);
|
|
}
|
|
};
|
|
|
|
// src/markers/MarkerPolygon.ts
|
|
var import_core12 = require_core();
|
|
var MarkerPolygon = class extends AbstractDomMarker {
|
|
constructor(viewer, plugin, config) {
|
|
super(viewer, plugin, config);
|
|
}
|
|
createElement() {
|
|
this.element = document.createElementNS(SVG_NS, this.isPolygon ? "polygon" : "polyline");
|
|
this.element[MARKER_DATA] = this;
|
|
}
|
|
isPoly() {
|
|
return true;
|
|
}
|
|
/**
|
|
* Checks if it is a polygon/polyline using pixel coordinates
|
|
*/
|
|
get isPixels() {
|
|
return this.type === "polygonPixels" /* polygonPixels */ || this.type === "polylinePixels" /* polylinePixels */;
|
|
}
|
|
/**
|
|
* Checks if it is a polygon marker
|
|
*/
|
|
get isPolygon() {
|
|
return this.type === "polygon" /* polygon */ || this.type === "polygonPixels" /* polygonPixels */;
|
|
}
|
|
/**
|
|
* Checks if it is a polyline marker
|
|
*/
|
|
get isPolyline() {
|
|
return this.type === "polyline" /* polyline */ || this.type === "polylinePixels" /* polylinePixels */;
|
|
}
|
|
render() {
|
|
const positions = this.__getPolyPositions();
|
|
const isVisible = positions.length > (this.isPolygon ? 2 : 1);
|
|
if (isVisible) {
|
|
const position = this.viewer.dataHelper.sphericalCoordsToViewerCoords(this.state.position);
|
|
const points = positions.map((pos) => pos.x - position.x + "," + (pos.y - position.y)).join(" ");
|
|
this.domElement.setAttributeNS(null, "points", points);
|
|
this.domElement.setAttributeNS(null, "transform", `translate(${position.x} ${position.y})`);
|
|
return position;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
update(config) {
|
|
super.update(config);
|
|
const element = this.domElement;
|
|
element.classList.add("psv-marker--poly");
|
|
this.state.dynamicSize = true;
|
|
if (this.config.svgStyle) {
|
|
Object.entries(this.config.svgStyle).forEach(([prop, value]) => {
|
|
element.setAttributeNS(null, import_core12.utils.dasherize(prop), value);
|
|
});
|
|
if (this.isPolyline && !this.config.svgStyle.fill) {
|
|
element.setAttributeNS(null, "fill", "none");
|
|
}
|
|
} else if (this.isPolygon) {
|
|
element.setAttributeNS(null, "fill", "rgba(0,0,0,0.5)");
|
|
} else if (this.isPolyline) {
|
|
element.setAttributeNS(null, "fill", "none");
|
|
element.setAttributeNS(null, "stroke", "rgb(0,0,0)");
|
|
}
|
|
const actualPoly = this.config[this.type];
|
|
if (!Array.isArray(actualPoly[0])) {
|
|
for (let i = 0; i < actualPoly.length; i++) {
|
|
actualPoly.splice(i, 2, [actualPoly[i], actualPoly[i + 1]]);
|
|
}
|
|
}
|
|
if (this.isPixels) {
|
|
this.definition = actualPoly.map((coord) => {
|
|
const sphericalCoords = this.viewer.dataHelper.textureCoordsToSphericalCoords({
|
|
textureX: coord[0],
|
|
textureY: coord[1]
|
|
});
|
|
return [sphericalCoords.yaw, sphericalCoords.pitch];
|
|
});
|
|
} else {
|
|
this.definition = actualPoly.map((coord) => {
|
|
return [import_core12.utils.parseAngle(coord[0]), import_core12.utils.parseAngle(coord[1], true)];
|
|
});
|
|
}
|
|
const centroid = this.isPolygon ? getPolygonCenter(this.definition) : getPolylineCenter(this.definition);
|
|
this.state.position = { yaw: centroid[0], pitch: centroid[1] };
|
|
this.state.positions3D = this.definition.map((coord) => {
|
|
return this.viewer.dataHelper.sphericalCoordsToVector3({ yaw: coord[0], pitch: coord[1] });
|
|
});
|
|
}
|
|
/**
|
|
* Computes viewer coordinates of each point of a polygon/polyline<br>
|
|
* It handles points behind the camera by creating intermediary points suitable for the projector
|
|
*/
|
|
__getPolyPositions() {
|
|
const nbVectors = this.state.positions3D.length;
|
|
const positions3D = this.state.positions3D.map((vector) => {
|
|
return {
|
|
vector,
|
|
visible: vector.dot(this.viewer.state.direction) > 0
|
|
};
|
|
});
|
|
const toBeComputed = [];
|
|
positions3D.forEach((pos, i) => {
|
|
if (!pos.visible) {
|
|
const neighbours = [
|
|
i === 0 ? positions3D[nbVectors - 1] : positions3D[i - 1],
|
|
i === nbVectors - 1 ? positions3D[0] : positions3D[i + 1]
|
|
];
|
|
neighbours.forEach((neighbour) => {
|
|
if (neighbour.visible) {
|
|
toBeComputed.push({
|
|
visible: neighbour.vector,
|
|
invisible: pos.vector,
|
|
index: i
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
toBeComputed.reverse().forEach((pair) => {
|
|
positions3D.splice(pair.index, 0, {
|
|
vector: getGreatCircleIntersection(pair.visible, pair.invisible, this.viewer.state.direction),
|
|
visible: true
|
|
});
|
|
});
|
|
return positions3D.filter((pos) => pos.visible).map((pos) => this.viewer.dataHelper.vector3ToViewerCoords(pos.vector));
|
|
}
|
|
};
|
|
|
|
// src/markers/MarkerSvg.ts
|
|
var import_core13 = require_core();
|
|
var MarkerSvg = class extends AbstractStandardMarker {
|
|
constructor(viewer, plugin, config) {
|
|
super(viewer, plugin, config);
|
|
}
|
|
isSvg() {
|
|
return true;
|
|
}
|
|
createElement() {
|
|
const svgType = this.type === "square" /* square */ ? "rect" : this.type;
|
|
const elt = document.createElementNS(SVG_NS, svgType);
|
|
this.element = document.createElementNS(SVG_NS, "svg");
|
|
this.element.appendChild(elt);
|
|
super.createElement();
|
|
}
|
|
update(config) {
|
|
super.update(config);
|
|
const svgElement = this.domElement.firstElementChild;
|
|
if (!import_core13.utils.isExtendedPosition(this.config.position)) {
|
|
throw new import_core13.PSVError("missing marker position");
|
|
}
|
|
this.state.dynamicSize = true;
|
|
switch (this.type) {
|
|
case "square" /* square */:
|
|
this.definition = {
|
|
x: 0,
|
|
y: 0,
|
|
width: this.config.square,
|
|
height: this.config.square
|
|
};
|
|
break;
|
|
case "rect" /* rect */:
|
|
if (Array.isArray(this.config.rect)) {
|
|
this.definition = {
|
|
x: 0,
|
|
y: 0,
|
|
width: this.config.rect[0],
|
|
height: this.config.rect[1]
|
|
};
|
|
} else {
|
|
this.definition = {
|
|
x: 0,
|
|
y: 0,
|
|
width: this.config.rect.width,
|
|
height: this.config.rect.height
|
|
};
|
|
}
|
|
break;
|
|
case "circle" /* circle */:
|
|
this.definition = {
|
|
cx: this.config.circle,
|
|
cy: this.config.circle,
|
|
r: this.config.circle
|
|
};
|
|
break;
|
|
case "ellipse" /* ellipse */:
|
|
if (Array.isArray(this.config.ellipse)) {
|
|
this.definition = {
|
|
cx: this.config.ellipse[0],
|
|
cy: this.config.ellipse[1],
|
|
rx: this.config.ellipse[0],
|
|
ry: this.config.ellipse[1]
|
|
};
|
|
} else {
|
|
this.definition = {
|
|
cx: this.config.ellipse.rx,
|
|
cy: this.config.ellipse.ry,
|
|
rx: this.config.ellipse.rx,
|
|
ry: this.config.ellipse.ry
|
|
};
|
|
}
|
|
break;
|
|
case "path" /* path */:
|
|
this.definition = {
|
|
d: this.config.path
|
|
};
|
|
break;
|
|
}
|
|
Object.entries(this.definition).forEach(([prop, value]) => {
|
|
svgElement.setAttributeNS(null, prop, value);
|
|
});
|
|
if (this.config.svgStyle) {
|
|
Object.entries(this.config.svgStyle).forEach(([prop, value]) => {
|
|
svgElement.setAttributeNS(null, import_core13.utils.dasherize(prop), value);
|
|
});
|
|
} else {
|
|
svgElement.setAttributeNS(null, "fill", "rgba(0,0,0,0.5)");
|
|
}
|
|
this.domElement.style.transformOrigin = `${this.state.anchor.x * 100}% ${this.state.anchor.y * 100}%`;
|
|
this.state.position = this.viewer.dataHelper.cleanPosition(this.config.position);
|
|
this.state.positions3D = [this.viewer.dataHelper.sphericalCoordsToVector3(this.state.position)];
|
|
}
|
|
};
|
|
|
|
// src/MarkersPlugin.ts
|
|
var getConfig = import_core14.utils.getConfigParser(
|
|
{
|
|
clickEventOnMarker: false,
|
|
gotoMarkerSpeed: "8rpm",
|
|
markers: null,
|
|
defaultHoverScale: null
|
|
},
|
|
{
|
|
defaultHoverScale(defaultHoverScale) {
|
|
if (!defaultHoverScale) {
|
|
return null;
|
|
}
|
|
if (defaultHoverScale === true) {
|
|
defaultHoverScale = DEFAULT_HOVER_SCALE;
|
|
}
|
|
if (typeof defaultHoverScale === "number") {
|
|
defaultHoverScale = { amount: defaultHoverScale };
|
|
}
|
|
return {
|
|
...DEFAULT_HOVER_SCALE,
|
|
...defaultHoverScale
|
|
};
|
|
}
|
|
}
|
|
);
|
|
function getMarkerCtor(config) {
|
|
const type = getMarkerType(config, false);
|
|
switch (type) {
|
|
case "image":
|
|
case "html":
|
|
case "element":
|
|
return MarkerNormal;
|
|
case "imageLayer":
|
|
case "videoLayer":
|
|
return Marker3D;
|
|
case "polygon":
|
|
case "polyline":
|
|
case "polygonPixels":
|
|
case "polylinePixels":
|
|
return MarkerPolygon;
|
|
case "square":
|
|
case "rect":
|
|
case "circle":
|
|
case "ellipse":
|
|
case "path":
|
|
return MarkerSvg;
|
|
default:
|
|
throw new import_core14.PSVError("invalid marker type");
|
|
}
|
|
}
|
|
var MarkersPlugin = class extends import_core14.AbstractConfigurablePlugin {
|
|
constructor(viewer, config) {
|
|
super(viewer, config);
|
|
this.markers = {};
|
|
this.state = {
|
|
visible: true,
|
|
showAllTooltips: false,
|
|
currentMarker: null,
|
|
hoveringMarker: null,
|
|
// require a 2nd render (only the scene) when 3d markers visibility changes
|
|
needsReRender: false
|
|
};
|
|
this.container = document.createElement("div");
|
|
this.container.className = "psv-markers";
|
|
this.viewer.container.appendChild(this.container);
|
|
this.svgContainer = document.createElementNS(SVG_NS, "svg");
|
|
this.svgContainer.setAttribute("class", "psv-markers-svg-container");
|
|
this.container.appendChild(this.svgContainer);
|
|
this.container.addEventListener("mouseenter", this, true);
|
|
this.container.addEventListener("mouseleave", this, true);
|
|
this.container.addEventListener("mousemove", this, true);
|
|
this.container.addEventListener("contextmenu", this);
|
|
}
|
|
/**
|
|
* @internal
|
|
*/
|
|
init() {
|
|
super.init();
|
|
import_core14.utils.checkStylesheet(this.viewer.container, "markers-plugin");
|
|
this.viewer.addEventListener(import_core14.events.ClickEvent.type, this);
|
|
this.viewer.addEventListener(import_core14.events.DoubleClickEvent.type, this);
|
|
this.viewer.addEventListener(import_core14.events.RenderEvent.type, this);
|
|
this.viewer.addEventListener(import_core14.events.ConfigChangedEvent.type, this);
|
|
this.viewer.addEventListener(import_core14.events.ObjectEnterEvent.type, this);
|
|
this.viewer.addEventListener(import_core14.events.ObjectHoverEvent.type, this);
|
|
this.viewer.addEventListener(import_core14.events.ObjectLeaveEvent.type, this);
|
|
this.viewer.addEventListener(import_core14.events.ReadyEvent.type, this, { once: true });
|
|
}
|
|
/**
|
|
* @internal
|
|
*/
|
|
destroy() {
|
|
this.clearMarkers(false);
|
|
this.viewer.unobserveObjects(MARKER_DATA);
|
|
this.viewer.removeEventListener(import_core14.events.ClickEvent.type, this);
|
|
this.viewer.removeEventListener(import_core14.events.DoubleClickEvent.type, this);
|
|
this.viewer.removeEventListener(import_core14.events.RenderEvent.type, this);
|
|
this.viewer.removeEventListener(import_core14.events.ObjectEnterEvent.type, this);
|
|
this.viewer.removeEventListener(import_core14.events.ObjectHoverEvent.type, this);
|
|
this.viewer.removeEventListener(import_core14.events.ObjectLeaveEvent.type, this);
|
|
this.viewer.removeEventListener(import_core14.events.ReadyEvent.type, this);
|
|
this.viewer.container.removeChild(this.container);
|
|
super.destroy();
|
|
}
|
|
/**
|
|
* @internal
|
|
*/
|
|
handleEvent(e) {
|
|
switch (e.type) {
|
|
case import_core14.events.ReadyEvent.type:
|
|
if (this.config.markers) {
|
|
this.setMarkers(this.config.markers);
|
|
delete this.config.markers;
|
|
}
|
|
break;
|
|
case import_core14.events.RenderEvent.type:
|
|
this.renderMarkers();
|
|
break;
|
|
case import_core14.events.ClickEvent.type:
|
|
this.__onClick(e, false);
|
|
break;
|
|
case import_core14.events.DoubleClickEvent.type:
|
|
this.__onClick(e, true);
|
|
break;
|
|
case import_core14.events.ObjectEnterEvent.type:
|
|
case import_core14.events.ObjectLeaveEvent.type:
|
|
case import_core14.events.ObjectHoverEvent.type:
|
|
if (e.userDataKey === MARKER_DATA) {
|
|
const event = e.originalEvent;
|
|
const marker = e.object.userData[MARKER_DATA];
|
|
switch (e.type) {
|
|
case import_core14.events.ObjectEnterEvent.type:
|
|
if (marker.config.style?.cursor) {
|
|
this.viewer.setCursor(marker.config.style.cursor);
|
|
} else if (marker.config.tooltip || marker.config.content) {
|
|
this.viewer.setCursor("pointer");
|
|
}
|
|
this.__onEnterMarker(event, marker);
|
|
break;
|
|
case import_core14.events.ObjectLeaveEvent.type:
|
|
this.viewer.setCursor(null);
|
|
this.__onLeaveMarker(marker);
|
|
break;
|
|
case import_core14.events.ObjectHoverEvent.type:
|
|
this.__onHoverMarker(event, marker);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case "mouseenter":
|
|
this.__onEnterMarker(e, this.__getTargetMarker(e.target));
|
|
break;
|
|
case "mouseleave":
|
|
this.__onLeaveMarker(this.__getTargetMarker(e.target));
|
|
break;
|
|
case "mousemove":
|
|
this.__onHoverMarker(e, this.__getTargetMarker(e.target, true));
|
|
break;
|
|
case "contextmenu":
|
|
e.preventDefault();
|
|
break;
|
|
}
|
|
}
|
|
/**
|
|
* Toggles all markers
|
|
*/
|
|
toggleAllMarkers() {
|
|
if (this.state.visible) {
|
|
this.hideAllMarkers();
|
|
} else {
|
|
this.showAllMarkers();
|
|
}
|
|
}
|
|
/**
|
|
* Shows all markers
|
|
*/
|
|
showAllMarkers() {
|
|
this.state.visible = true;
|
|
this.renderMarkers();
|
|
this.dispatchEvent(new ShowMarkersEvent());
|
|
}
|
|
/**
|
|
* Hides all markers
|
|
*/
|
|
hideAllMarkers() {
|
|
this.state.visible = false;
|
|
this.renderMarkers();
|
|
this.dispatchEvent(new HideMarkersEvent());
|
|
}
|
|
/**
|
|
* Toggles the visibility of all tooltips
|
|
*/
|
|
toggleAllTooltips() {
|
|
if (this.state.showAllTooltips) {
|
|
this.hideAllTooltips();
|
|
} else {
|
|
this.showAllTooltips();
|
|
}
|
|
}
|
|
/**
|
|
* Displays all tooltips
|
|
*/
|
|
showAllTooltips() {
|
|
this.state.showAllTooltips = true;
|
|
Object.values(this.markers).forEach((marker) => {
|
|
marker.state.staticTooltip = true;
|
|
marker.showTooltip();
|
|
});
|
|
}
|
|
/**
|
|
* Hides all tooltips
|
|
*/
|
|
hideAllTooltips() {
|
|
this.state.showAllTooltips = false;
|
|
Object.values(this.markers).forEach((marker) => {
|
|
marker.state.staticTooltip = false;
|
|
marker.hideTooltip();
|
|
});
|
|
}
|
|
/**
|
|
* Returns the total number of markers
|
|
*/
|
|
getNbMarkers() {
|
|
return Object.keys(this.markers).length;
|
|
}
|
|
/**
|
|
* Returns all the markers
|
|
*/
|
|
getMarkers() {
|
|
return Object.values(this.markers);
|
|
}
|
|
/**
|
|
* Adds a new marker to viewer
|
|
* @throws {@link PSVError} when the marker's id is missing or already exists
|
|
*/
|
|
addMarker(config, render = true) {
|
|
if (this.markers[config.id]) {
|
|
throw new import_core14.PSVError(`marker "${config.id}" already exists`);
|
|
}
|
|
const marker = new (getMarkerCtor(config))(this.viewer, this, config);
|
|
if (marker.isPoly()) {
|
|
this.svgContainer.appendChild(marker.domElement);
|
|
} else if (marker.is3d()) {
|
|
this.viewer.renderer.addObject(marker.threeElement);
|
|
} else {
|
|
this.container.appendChild(marker.domElement);
|
|
}
|
|
this.markers[marker.id] = marker;
|
|
if (this.state.showAllTooltips) {
|
|
marker.state.staticTooltip = true;
|
|
}
|
|
if (render) {
|
|
this.__afterChangerMarkers();
|
|
}
|
|
}
|
|
/**
|
|
* Returns the internal marker object for a marker id
|
|
* @throws {@link PSVError} when the marker cannot be found
|
|
*/
|
|
getMarker(markerId) {
|
|
const id = typeof markerId === "object" ? markerId.id : markerId;
|
|
if (!this.markers[id]) {
|
|
throw new import_core14.PSVError(`cannot find marker "${id}"`);
|
|
}
|
|
return this.markers[id];
|
|
}
|
|
/**
|
|
* Returns the last marker selected by the user
|
|
*/
|
|
getCurrentMarker() {
|
|
return this.state.currentMarker;
|
|
}
|
|
/**
|
|
* Updates the existing marker with the same id
|
|
* @description Every property can be changed but you can't change its type (Eg: `image` to `html`)
|
|
*/
|
|
updateMarker(config, render = true) {
|
|
const marker = this.getMarker(config.id);
|
|
marker.update(config);
|
|
if (render) {
|
|
this.__afterChangerMarkers();
|
|
if (marker === this.state.hoveringMarker && marker.config.tooltip?.trigger === "hover" || marker.state.staticTooltip) {
|
|
marker.showTooltip();
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Removes a marker from the viewer
|
|
*/
|
|
removeMarker(markerId, render = true) {
|
|
const marker = this.getMarker(markerId);
|
|
if (marker.isPoly()) {
|
|
this.svgContainer.removeChild(marker.domElement);
|
|
} else if (marker.is3d()) {
|
|
this.viewer.renderer.removeObject(marker.threeElement);
|
|
} else {
|
|
this.container.removeChild(marker.domElement);
|
|
}
|
|
if (this.state.hoveringMarker === marker) {
|
|
this.state.hoveringMarker = null;
|
|
}
|
|
if (this.state.currentMarker === marker) {
|
|
this.state.currentMarker = null;
|
|
}
|
|
marker.destroy();
|
|
delete this.markers[marker.id];
|
|
if (render) {
|
|
this.__afterChangerMarkers();
|
|
}
|
|
}
|
|
/**
|
|
* Removes multiple markers
|
|
*/
|
|
removeMarkers(markerIds, render = true) {
|
|
markerIds.forEach((markerId) => this.removeMarker(markerId, false));
|
|
if (render) {
|
|
this.__afterChangerMarkers();
|
|
}
|
|
}
|
|
/**
|
|
* Replaces all markers
|
|
*/
|
|
setMarkers(markers, render = true) {
|
|
this.clearMarkers(false);
|
|
markers?.forEach((marker) => {
|
|
this.addMarker(marker, false);
|
|
});
|
|
if (render) {
|
|
this.__afterChangerMarkers();
|
|
}
|
|
}
|
|
/**
|
|
* Removes all markers
|
|
*/
|
|
clearMarkers(render = true) {
|
|
Object.keys(this.markers).forEach((markerId) => {
|
|
this.removeMarker(markerId, false);
|
|
});
|
|
if (render) {
|
|
this.__afterChangerMarkers();
|
|
}
|
|
}
|
|
/**
|
|
* Rotate the view to face the marker
|
|
*/
|
|
gotoMarker(markerId, speed = this.config.gotoMarkerSpeed) {
|
|
const marker = this.getMarker(markerId);
|
|
if (!speed) {
|
|
this.viewer.rotate(marker.state.position);
|
|
if (!import_core14.utils.isNil(marker.config.zoomLvl)) {
|
|
this.viewer.zoom(marker.config.zoomLvl);
|
|
}
|
|
this.dispatchEvent(new GotoMarkerDoneEvent(marker));
|
|
return Promise.resolve();
|
|
} else {
|
|
return this.viewer.animate({
|
|
...marker.state.position,
|
|
zoom: marker.config.zoomLvl,
|
|
speed
|
|
}).then(() => {
|
|
this.dispatchEvent(new GotoMarkerDoneEvent(marker));
|
|
});
|
|
}
|
|
}
|
|
/**
|
|
* Hides a marker
|
|
*/
|
|
hideMarker(markerId) {
|
|
this.toggleMarker(markerId, false);
|
|
}
|
|
/**
|
|
* Shows a marker
|
|
*/
|
|
showMarker(markerId) {
|
|
this.toggleMarker(markerId, true);
|
|
}
|
|
/**
|
|
* Forces the display of the tooltip of a marker
|
|
*/
|
|
showMarkerTooltip(markerId) {
|
|
const marker = this.getMarker(markerId);
|
|
marker.state.staticTooltip = true;
|
|
marker.showTooltip();
|
|
}
|
|
/**
|
|
* Hides the tooltip of a marker
|
|
*/
|
|
hideMarkerTooltip(markerId) {
|
|
const marker = this.getMarker(markerId);
|
|
marker.state.staticTooltip = false;
|
|
marker.hideTooltip();
|
|
}
|
|
/**
|
|
* Toggles a marker visibility
|
|
*/
|
|
toggleMarker(markerId, visible) {
|
|
const marker = this.getMarker(markerId);
|
|
marker.config.visible = import_core14.utils.isNil(visible) ? !marker.config.visible : visible;
|
|
this.renderMarkers();
|
|
}
|
|
/**
|
|
* Opens the panel with the content of the marker
|
|
*/
|
|
showMarkerPanel(markerId) {
|
|
const marker = this.getMarker(markerId);
|
|
if (marker.config.content) {
|
|
this.viewer.panel.show({
|
|
id: ID_PANEL_MARKER,
|
|
content: marker.config.content
|
|
});
|
|
} else {
|
|
this.hideMarkerPanel();
|
|
}
|
|
}
|
|
/**
|
|
* Closes the panel if currently showing the content of a marker
|
|
*/
|
|
hideMarkerPanel() {
|
|
this.viewer.panel.hide(ID_PANEL_MARKER);
|
|
}
|
|
/**
|
|
* Toggles the visibility of the list of markers
|
|
*/
|
|
toggleMarkersList() {
|
|
if (this.viewer.panel.isVisible(ID_PANEL_MARKERS_LIST)) {
|
|
this.hideMarkersList();
|
|
} else {
|
|
this.showMarkersList();
|
|
}
|
|
}
|
|
/**
|
|
* Opens side panel with the list of markers
|
|
*/
|
|
showMarkersList() {
|
|
let markers = [];
|
|
if (this.state.visible) {
|
|
Object.values(this.markers).forEach((marker) => {
|
|
if (marker.config.visible && !marker.config.hideList) {
|
|
markers.push(marker);
|
|
}
|
|
});
|
|
}
|
|
const e = new RenderMarkersListEvent(markers);
|
|
this.dispatchEvent(e);
|
|
markers = e.markers;
|
|
this.viewer.panel.show({
|
|
id: ID_PANEL_MARKERS_LIST,
|
|
content: MARKERS_LIST_TEMPLATE(markers, this.viewer.config.lang[MarkersButton.id]),
|
|
noMargin: true,
|
|
clickHandler: (target) => {
|
|
const li = import_core14.utils.getClosest(target, "li");
|
|
const markerId = li ? li.dataset[MARKER_DATA] : void 0;
|
|
if (markerId) {
|
|
const marker = this.getMarker(markerId);
|
|
this.dispatchEvent(new SelectMarkerListEvent(marker));
|
|
this.gotoMarker(marker.id);
|
|
this.hideMarkersList();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* Closes side panel if it contains the list of markers
|
|
*/
|
|
hideMarkersList() {
|
|
this.viewer.panel.hide(ID_PANEL_MARKERS_LIST);
|
|
}
|
|
/**
|
|
* Updates the visibility and the position of all markers
|
|
*/
|
|
renderMarkers() {
|
|
if (this.state.needsReRender) {
|
|
this.state.needsReRender = false;
|
|
return;
|
|
}
|
|
const zoomLevel = this.viewer.getZoomLevel();
|
|
const viewerPosition = this.viewer.getPosition();
|
|
const hoveringMarker = this.state.hoveringMarker;
|
|
Object.values(this.markers).forEach((marker) => {
|
|
let isVisible = this.state.visible && marker.config.visible;
|
|
let visibilityChanged = false;
|
|
let position = null;
|
|
if (isVisible) {
|
|
position = marker.render({ viewerPosition, zoomLevel, hoveringMarker });
|
|
isVisible = !!position;
|
|
}
|
|
visibilityChanged = marker.state.visible !== isVisible;
|
|
marker.state.visible = isVisible;
|
|
marker.state.position2D = position;
|
|
if (!marker.is3d()) {
|
|
import_core14.utils.toggleClass(marker.domElement, "psv-marker--visible", isVisible);
|
|
}
|
|
if (!isVisible) {
|
|
marker.hideTooltip();
|
|
} else if (marker.state.staticTooltip) {
|
|
marker.showTooltip();
|
|
} else if (marker !== this.state.hoveringMarker) {
|
|
marker.hideTooltip();
|
|
}
|
|
if (visibilityChanged) {
|
|
this.dispatchEvent(new MarkerVisibilityEvent(marker, isVisible));
|
|
if (marker.is3d()) {
|
|
this.state.needsReRender = true;
|
|
}
|
|
}
|
|
});
|
|
if (this.state.needsReRender) {
|
|
this.viewer.needsUpdate();
|
|
}
|
|
}
|
|
__getTargetMarker(target, closest = false) {
|
|
if (target instanceof Node) {
|
|
const target2 = closest ? import_core14.utils.getClosest(target, ".psv-marker") : target;
|
|
return target2 ? target2[MARKER_DATA] : void 0;
|
|
} else if (Array.isArray(target)) {
|
|
return target.map((o) => o.userData[MARKER_DATA]).filter((m) => !!m).sort((a, b) => b.config.zIndex - a.config.zIndex)[0];
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
/**
|
|
* Handles mouse enter events, show the tooltip for non polygon markers
|
|
*/
|
|
__onEnterMarker(e, marker) {
|
|
if (marker) {
|
|
this.state.hoveringMarker = marker;
|
|
this.dispatchEvent(new EnterMarkerEvent(marker));
|
|
if (marker instanceof AbstractStandardMarker) {
|
|
marker.applyScale({
|
|
zoomLevel: this.viewer.getZoomLevel(),
|
|
viewerPosition: this.viewer.getPosition(),
|
|
mouseover: true
|
|
});
|
|
}
|
|
if (!marker.state.staticTooltip && marker.config.tooltip?.trigger === "hover") {
|
|
marker.showTooltip(e.clientX, e.clientY);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Handles mouse leave events, hide the tooltip
|
|
*/
|
|
__onLeaveMarker(marker) {
|
|
if (marker) {
|
|
this.dispatchEvent(new LeaveMarkerEvent(marker));
|
|
if (marker instanceof AbstractStandardMarker) {
|
|
marker.applyScale({
|
|
zoomLevel: this.viewer.getZoomLevel(),
|
|
viewerPosition: this.viewer.getPosition(),
|
|
mouseover: false
|
|
});
|
|
}
|
|
this.state.hoveringMarker = null;
|
|
if (!marker.state.staticTooltip && marker.config.tooltip?.trigger === "hover") {
|
|
marker.hideTooltip();
|
|
} else if (marker.state.staticTooltip) {
|
|
marker.showTooltip();
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Handles mouse move events, refresh the tooltip for polygon markers
|
|
*/
|
|
__onHoverMarker(e, marker) {
|
|
if (marker && (marker.isPoly() || marker.is3d())) {
|
|
if (marker.config.tooltip?.trigger === "hover") {
|
|
marker.showTooltip(e.clientX, e.clientY);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Handles mouse click events, select the marker and open the panel if necessary
|
|
*/
|
|
__onClick(e, dblclick) {
|
|
const threeMarker = this.__getTargetMarker(e.data.objects);
|
|
const stdMarker = this.__getTargetMarker(e.data.target, true);
|
|
const marker = stdMarker || threeMarker;
|
|
if (this.state.currentMarker && this.state.currentMarker !== marker) {
|
|
this.dispatchEvent(new UnselectMarkerEvent(this.state.currentMarker));
|
|
this.viewer.panel.hide(ID_PANEL_MARKER);
|
|
if (!this.state.showAllTooltips && this.state.currentMarker.config.tooltip?.trigger === "click") {
|
|
this.hideMarkerTooltip(this.state.currentMarker.id);
|
|
}
|
|
this.state.currentMarker = null;
|
|
}
|
|
if (marker) {
|
|
this.state.currentMarker = marker;
|
|
this.dispatchEvent(new SelectMarkerEvent(marker, dblclick, e.data.rightclick));
|
|
if (this.config.clickEventOnMarker) {
|
|
e.data.marker = marker;
|
|
} else {
|
|
e.stopImmediatePropagation();
|
|
}
|
|
if (this.markers[marker.id]) {
|
|
if (marker.config.tooltip?.trigger === "click") {
|
|
if (marker.tooltip) {
|
|
this.hideMarkerTooltip(marker.id);
|
|
} else {
|
|
this.showMarkerTooltip(marker.id);
|
|
}
|
|
} else {
|
|
this.showMarkerPanel(marker.id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__afterChangerMarkers() {
|
|
this.__refreshUi();
|
|
this.__checkObjectsObserver();
|
|
this.viewer.needsUpdate();
|
|
this.dispatchEvent(new SetMarkersEvent(this.getMarkers()));
|
|
}
|
|
/**
|
|
* Updates the visiblity of the panel and the buttons
|
|
*/
|
|
__refreshUi() {
|
|
const nbMarkers = Object.values(this.markers).filter((m) => !m.config.hideList).length;
|
|
if (nbMarkers === 0) {
|
|
if (this.viewer.panel.isVisible(ID_PANEL_MARKERS_LIST) || this.viewer.panel.isVisible(ID_PANEL_MARKER)) {
|
|
this.viewer.panel.hide();
|
|
}
|
|
} else {
|
|
if (this.viewer.panel.isVisible(ID_PANEL_MARKERS_LIST)) {
|
|
this.showMarkersList();
|
|
} else if (this.viewer.panel.isVisible(ID_PANEL_MARKER)) {
|
|
this.state.currentMarker ? this.showMarkerPanel(this.state.currentMarker.id) : this.viewer.panel.hide();
|
|
}
|
|
}
|
|
this.viewer.navbar.getButton(MarkersButton.id, false)?.toggle(nbMarkers > 0);
|
|
this.viewer.navbar.getButton(MarkersListButton.id, false)?.toggle(nbMarkers > 0);
|
|
}
|
|
/**
|
|
* Adds or remove the objects observer if there are 3D markers
|
|
*/
|
|
__checkObjectsObserver() {
|
|
const has3d = Object.values(this.markers).some((marker) => marker.is3d());
|
|
if (has3d) {
|
|
this.viewer.observeObjects(MARKER_DATA);
|
|
} else {
|
|
this.viewer.unobserveObjects(MARKER_DATA);
|
|
}
|
|
}
|
|
};
|
|
MarkersPlugin.id = "markers";
|
|
MarkersPlugin.VERSION = "5.7.3";
|
|
MarkersPlugin.configParser = getConfig;
|
|
MarkersPlugin.readonlyOptions = ["markers"];
|
|
|
|
// src/index.ts
|
|
import_core15.DEFAULTS.lang[MarkersButton.id] = "Markers";
|
|
import_core15.DEFAULTS.lang[MarkersListButton.id] = "Markers list";
|
|
(0, import_core15.registerButton)(MarkersButton, "caption:left");
|
|
(0, import_core15.registerButton)(MarkersListButton, "caption:left");
|
|
__copyProps(__defProp(exports, "__esModule", { value: true }), src_exports);
|
|
|
|
}));//# sourceMappingURL=index.js.map
|