wisemapping-frontend/packages/web2d/src/components/peer/svg/ElementPeer.js

277 lines
7.6 KiB
JavaScript
Raw Normal View History

2021-10-05 01:56:40 +02:00
/*
2021-12-03 05:38:53 +01:00
* Copyright [2021] [wisemapping]
2021-10-05 01:56:40 +02:00
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2021-12-03 06:23:14 +01:00
import { $assert, $defined } from '@wisemapping/core-js';
import EventUtils from '../utils/EventUtils';
2021-10-05 01:56:40 +02:00
2021-12-05 00:39:20 +01:00
class ElementPeer {
constructor(svgElement) {
2021-10-05 01:56:40 +02:00
this._native = svgElement;
if (!this._native.addEvent) {
// Hack bug: https://bugzilla.mozilla.org/show_bug.cgi?id=740811
for (const key in Element) {
if (Object.prototype.hasOwnProperty.call(Element, key)) {
this._native[key] = Element.prototype[key];
}
2021-10-05 01:56:40 +02:00
}
}
this._size = { width: 1, height: 1 };
this._changeListeners = {};
// http://support.adobe.com/devsup/devsup.nsf/docs/50493.htm
// __handlers stores handlers references so they can be removed afterwards
this.__handlers = new Map();
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
setChildren(children) {
this._children = children;
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
getChildren() {
let result = this._children;
2021-12-03 06:23:14 +01:00
if (!$defined(result)) {
2021-10-05 01:56:40 +02:00
result = [];
this._children = result;
}
return result;
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
getParent() {
return this._parent;
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
setParent(parent) {
this._parent = parent;
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
append(elementPeer) {
// Store parent and child relationship.
elementPeer.setParent(this);
const children = this.getChildren();
2021-12-05 00:39:20 +01:00
children.push(elementPeer);
2021-10-05 01:56:40 +02:00
// Append element as a child.
this._native.appendChild(elementPeer._native);
// Broadcast events ...
EventUtils.broadcastChangeEvent(this, 'strokeStyle');
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
removeChild(elementPeer) {
// Store parent and child relationship.
elementPeer.setParent(null);
2021-12-14 18:06:09 +01:00
let children = this.getChildren();
2021-10-05 01:56:40 +02:00
// Remove from children array ...
const oldLength = children.length;
2021-12-14 18:06:09 +01:00
children = children.filter((c) => c !== elementPeer);
this.setChildren(children);
2022-07-13 03:58:11 +02:00
$assert(children.length < oldLength, `element could not be removed:${elementPeer}`);
2021-10-05 01:56:40 +02:00
// Append element as a child.
this._native.removeChild(elementPeer._native);
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
/**
2022-07-13 03:58:11 +02:00
* http://www.w3.org/TR/DOM-Level-3-Events/events.html
* http://developer.mozilla.org/en/docs/addEvent
*/
2021-10-05 01:56:40 +02:00
addEvent(type, listener) {
// wrap it so it can be ~backward compatible with jQuery.trigger
const wrappedListener = (e) => listener(e, e.detail);
this.__handlers.set(listener, wrappedListener);
this._native.addEventListener(type, wrappedListener);
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
trigger(type, event) {
// TODO: check this for correctness and for real jQuery.trigger replacement
this._native.dispatchEvent(new CustomEvent(type, { detail: event }));
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
// eslint-disable-next-line class-methods-use-this
cloneEvents(/* from */) {
throw new Error('cloneEvents not implemented');
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
removeEvent(type, listener) {
this._native.removeEventListener(type, this.__handlers.get(listener));
this.__handlers.delete(listener);
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
setSize(width, height) {
2021-12-31 00:03:59 +01:00
if ($defined(width) && this._size.width !== Number.parseFloat(width, 10)) {
this._size.width = Number.parseFloat(width, 10);
2022-01-02 19:37:33 +01:00
this._native.setAttribute('width', this._size.width.toFixed(2));
2021-10-05 01:56:40 +02:00
}
2021-12-31 00:03:59 +01:00
if ($defined(height) && this._size.height !== Number.parseFloat(height, 10)) {
this._size.height = Number.parseFloat(height, 10);
2022-01-02 19:37:33 +01:00
this._native.setAttribute('height', this._size.height.toFixed(2));
2021-10-05 01:56:40 +02:00
}
EventUtils.broadcastChangeEvent(this, 'strokeStyle');
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
getSize() {
return { width: this._size.width, height: this._size.height };
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
setFill(color, opacity) {
2021-12-03 06:23:14 +01:00
if ($defined(color)) {
2021-10-05 01:56:40 +02:00
this._native.setAttribute('fill', color);
}
2021-12-03 06:23:14 +01:00
if ($defined(opacity)) {
2021-10-05 01:56:40 +02:00
this._native.setAttribute('fill-opacity', opacity);
}
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
getFill() {
const color = this._native.getAttribute('fill');
const opacity = this._native.getAttribute('fill-opacity');
return { color, opacity: Number(opacity) };
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
getStroke() {
2023-01-30 05:10:57 +01:00
const stoke = this._native;
const color = stoke.getAttribute('stroke');
2021-10-05 01:56:40 +02:00
const dashstyle = this._stokeStyle;
2023-01-30 05:10:57 +01:00
const opacity = stoke.getAttribute('stroke-opacity');
const width = stoke.getAttribute('stroke-width');
2021-10-05 01:56:40 +02:00
return {
color,
style: dashstyle,
opacity,
width,
2021-10-05 01:56:40 +02:00
};
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
setStroke(width, style, color, opacity) {
2021-12-03 06:23:14 +01:00
if ($defined(width)) {
2021-10-05 01:56:40 +02:00
this._native.setAttribute('stroke-width', `${width}px`);
}
2021-12-03 06:23:14 +01:00
if ($defined(color)) {
2021-10-05 01:56:40 +02:00
this._native.setAttribute('stroke', color);
}
2021-12-03 06:23:14 +01:00
if ($defined(style)) {
2021-10-05 01:56:40 +02:00
this._stokeStyle = style;
2023-01-30 05:10:57 +01:00
switch (style) {
case 'dash':
this._native.setAttribute('stroke-dasharray', '5 5');
this._native.setAttribute('stroke-linecap', null);
break;
case 'dot':
this._native.setAttribute('stroke-dasharray', '1 8');
this._native.setAttribute('stroke-linecap', 'round');
break;
case 'dashdot':
case 'longdash':
this._native.setAttribute('stroke-dasharray', '10 5 2');
this._native.setAttribute('stroke-linecap', 'round');
break;
case 'solid':
this._native.setAttribute('stroke-dasharray', null);
this._native.setAttribute('stroke-linecap', null);
break;
default:
throw new Error(`Unsupported style: ${style}`);
}
2021-10-05 01:56:40 +02:00
}
2021-12-03 06:23:14 +01:00
if ($defined(opacity)) {
2021-10-05 01:56:40 +02:00
this._native.setAttribute('stroke-opacity', opacity);
}
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
2022-03-01 01:12:45 +01:00
setVisibility(value, fade) {
this._native.setAttribute('visibility', value ? 'visible' : 'hidden');
this._native.style.opacity = value ? 1 : 0;
if (fade) {
this._native.style.transition = `visibility ${fade}ms, opacity ${fade}ms`;
} else {
this._native.style.transition = null;
}
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
isVisible() {
const visibility = this._native.getAttribute('visibility');
return !(visibility === 'hidden');
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
updateStrokeStyle() {
const strokeStyle = this._stokeStyle;
if (this.getParent()) {
if (strokeStyle && strokeStyle !== 'solid') {
2021-10-05 01:56:40 +02:00
this.setStroke(null, strokeStyle);
}
}
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
attachChangeEventListener(type, listener) {
const listeners = this.getChangeEventListeners(type);
2021-12-03 06:23:14 +01:00
if (!$defined(listener)) {
throw new Error('Listener can not be null');
2021-10-05 01:56:40 +02:00
}
listeners.push(listener);
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
getChangeEventListeners(type) {
let listeners = this._changeListeners[type];
2021-12-03 06:23:14 +01:00
if (!$defined(listeners)) {
2021-10-05 01:56:40 +02:00
listeners = [];
this._changeListeners[type] = listeners;
}
return listeners;
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
/**
2022-07-13 03:58:11 +02:00
* Move element to the front
*/
2021-10-05 01:56:40 +02:00
moveToFront() {
this._native.parentNode.appendChild(this._native);
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
/**
2022-07-13 03:58:11 +02:00
* Move element to the back
*/
2021-10-05 01:56:40 +02:00
moveToBack() {
this._native.parentNode.insertBefore(this._native, this._native.parentNode.firstChild);
2021-12-05 00:39:20 +01:00
}
2021-10-05 01:56:40 +02:00
setCursor(type) {
this._native.style.cursor = type;
2021-12-05 00:39:20 +01:00
}
static stokeStyleToStrokDasharray() {
return {
solid: [],
dot: [1, 3],
dash: [4, 3],
longdash: [10, 2],
dashdot: [5, 3, 1, 3],
};
}
}
ElementPeer.svgNamespace = 'http://www.w3.org/2000/svg';
ElementPeer.linkNamespace = 'http://www.w3.org/1999/xlink';
2021-10-05 01:56:40 +02:00
export default ElementPeer;