From 0d62936d5a335df88691f874ef5b1098ccd0f776 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 24 Jan 2022 11:24:16 -0800 Subject: [PATCH] Change relationshop to TS --- packages/mindplot/.eslintrc.json | 1 - .../mindplot/src/components/CentralTopic.js | 4 +- .../mindplot/src/components/ControlPoint.js | 4 +- packages/mindplot/src/components/Designer.ts | 7 +- .../{Relationship.js => Relationship.ts} | 76 +++++++++------- ...ationshipPivot.js => RelationshipPivot.ts} | 40 ++++++--- packages/mindplot/src/components/Topic.js | 20 +++-- .../libraries/bootstrap/BootstrapDialog.js | 4 +- .../src/components/model/INodeModel.ts | 37 ++++---- .../mindplot/src/components/model/Mindmap.ts | 4 +- .../persistence/Pela2TangoMigrator.ts | 2 +- .../persistence/XMLSerializerFactory.ts | 1 + .../components/widget/AccountSettingsPanel.js | 1 + .../test/playground/layout/lib/raphael-min.js | 34 +++---- .../test/playground/map-render/js/editor.js | 4 +- packages/mindplot/test/unit/export/Helper.ts | 22 ++--- .../unit/export/SVGExporterTestSuite.test.ts | 33 ++++--- .../unit/export/TextExporterTestSuite.test.ts | 89 +++++++++---------- .../mindplot/test/unit/layout/Constants.ts | 6 +- packages/mindplot/webpack.playground.js | 2 +- 20 files changed, 220 insertions(+), 171 deletions(-) rename packages/mindplot/src/components/{Relationship.js => Relationship.ts} (87%) rename packages/mindplot/src/components/{RelationshipPivot.js => RelationshipPivot.ts} (86%) diff --git a/packages/mindplot/.eslintrc.json b/packages/mindplot/.eslintrc.json index 62d847a7..3473120e 100644 --- a/packages/mindplot/.eslintrc.json +++ b/packages/mindplot/.eslintrc.json @@ -37,7 +37,6 @@ // no-unused-vars already used "@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/ban-ts-comment": "warn", - "@typescript-eslint/no-empty-function": "warn", "import/no-extraneous-dependencies": ["warn", {"packageDir": "./", "devDependencies": false, "optionalDependencies": false, "peerDependencies": false}] }, "settings": { diff --git a/packages/mindplot/src/components/CentralTopic.js b/packages/mindplot/src/components/CentralTopic.js index bf2beee9..f10be143 100644 --- a/packages/mindplot/src/components/CentralTopic.js +++ b/packages/mindplot/src/components/CentralTopic.js @@ -42,7 +42,9 @@ class CentralTopic extends Topic { } /** */ - updateTopicShape() { } + updateTopicShape() { + // Overwite behaviour ... + } _updatePositionOnChangeSize() { // Center main topic ... diff --git a/packages/mindplot/src/components/ControlPoint.js b/packages/mindplot/src/components/ControlPoint.js index e490c321..3f28394f 100644 --- a/packages/mindplot/src/components/ControlPoint.js +++ b/packages/mindplot/src/components/ControlPoint.js @@ -112,7 +112,9 @@ class ControlPoint { ); } - _removeLine() { } + _removeLine() { + // Overwrite default behaviour ... + } _mouseDown(event, point, me) { if (!this._isBinded) { diff --git a/packages/mindplot/src/components/Designer.ts b/packages/mindplot/src/components/Designer.ts index 428302f9..0898715b 100644 --- a/packages/mindplot/src/components/Designer.ts +++ b/packages/mindplot/src/components/Designer.ts @@ -146,9 +146,12 @@ class Designer extends Events { }, { passive: false }); } + getActionDispatcher(): StandaloneActionDispatcher { + return this._actionDispatcher; + } + // @ts-ignore - // eslint-disable-next-line @typescript-eslint/ban-types - addEvent(type: string, listener: Function): void { + addEvent(type: string, listener: any): void { if (type === TopicEvent.EDIT || type === TopicEvent.CLICK) { const editor = TopicEventDispatcher.getInstance(); editor.addEvent(type, listener); diff --git a/packages/mindplot/src/components/Relationship.js b/packages/mindplot/src/components/Relationship.ts similarity index 87% rename from packages/mindplot/src/components/Relationship.js rename to packages/mindplot/src/components/Relationship.ts index 4c26734f..59f073f8 100644 --- a/packages/mindplot/src/components/Relationship.js +++ b/packages/mindplot/src/components/Relationship.ts @@ -15,16 +15,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Arrow, Point } from '@wisemapping/web2d'; import { $assert, $defined } from '@wisemapping/core-js'; - +import { Arrow, Point, ElementClass } from '@wisemapping/web2d'; import ConnectionLine from './ConnectionLine'; import ControlPoint from './ControlPoint'; - +import RelationshipModel from './model/RelationshipModel'; +import NodeGraph from './NodeGraph'; import Shape from './util/Shape'; class Relationship extends ConnectionLine { - constructor(sourceNode, targetNode, model) { + private _focusShape: ElementClass; + + private _onFocus: boolean; + + private _isInWorkspace: boolean; + + private _controlPointsController: ControlPoint; + + private _startArrow: Arrow; + + private _showEndArrow: Arrow; + + private _endArrow: Arrow; + + private _controlPointControllerListener: any; + + private _showStartArrow: Arrow; + + constructor(sourceNode: NodeGraph, targetNode: NodeGraph, model: RelationshipModel) { $assert(sourceNode, 'sourceNode can not be null'); $assert(targetNode, 'targetNode can not be null'); @@ -72,12 +90,12 @@ class Relationship extends ConnectionLine { } } - setStroke(color, style, opacity) { + setStroke(color: string, style: string, opacity: number): void { super.setStroke(color, style, opacity); this._startArrow.setStrokeColor(color); } - redraw() { + redraw(): void { const line2d = this._line2d; const sourceTopic = this._sourceTopic; const sourcePosition = sourceTopic.getPosition(); @@ -131,7 +149,7 @@ class Relationship extends ConnectionLine { this._controlPointsController.redraw(); } - _positionArrows() { + private _positionArrows(): void { const tpos = this._line2d.getTo(); const spos = this._line2d.getFrom(); @@ -182,7 +200,7 @@ class Relationship extends ConnectionLine { this.redraw(); } - _initializeControlPointController() { + _initializeControlPointController(): void { this.setOnFocus(true); } @@ -199,12 +217,11 @@ class Relationship extends ConnectionLine { super.removeFromWorkspace(workspace); } - // eslint-disable-next-line class-methods-use-this getType() { - return Relationship.type; + return 'Relationship'; } - setOnFocus(focus) { + setOnFocus(focus: boolean): void { // Change focus shape if (this.isOnFocus() !== focus) { if (focus) { @@ -219,7 +236,7 @@ class Relationship extends ConnectionLine { } } - _refreshShape() { + private _refreshShape() { const sPos = this._line2d.getFrom(); const tPos = this._line2d.getTo(); const ctrlPoints = this._line2d.getControlPoints(); @@ -233,7 +250,8 @@ class Relationship extends ConnectionLine { this._focusShape.updateLine(); } - addEvent(eventType, listener) { + // @typescript-eslint/ban-types + addEvent(eventType: string, listener: any) { let type = eventType; // Translate to web 2d events ... if (type === 'onfocus') { @@ -244,37 +262,37 @@ class Relationship extends ConnectionLine { line.addEvent(type, listener); } - isOnFocus() { + isOnFocus(): boolean { return this._onFocus; } - isInWorkspace() { + isInWorkspace(): boolean { return this._isInWorkspace; } - setVisibility(value) { + setVisibility(value: boolean) { super.setVisibility(value); if (this._showEndArrow) this._endArrow.setVisibility(this._showEndArrow); this._startArrow.setVisibility(this._showStartArrow && value); } - setOpacity(opacity) { + setOpacity(opacity: number) { super.setOpacity(opacity); if (this._showEndArrow) this._endArrow.setOpacity(opacity); if (this._showStartArrow) this._startArrow.setOpacity(opacity); } - setShowEndArrow(visible) { + setShowEndArrow(visible: boolean) { this._showEndArrow = visible; if (this._isInWorkspace) this.redraw(); } - setShowStartArrow(visible) { + setShowStartArrow(visible: boolean) { this._showStartArrow = visible; if (this._isInWorkspace) this.redraw(); } - setFrom(x, y) { + setFrom(x: number, y: number) { $assert($defined(x), 'x must be defined'); $assert($defined(y), 'y must be defined'); @@ -282,7 +300,7 @@ class Relationship extends ConnectionLine { this._startArrow.setFrom(x, y); } - setTo(x, y) { + setTo(x: number, y: number) { $assert($defined(x), 'x must be defined'); $assert($defined(y), 'y must be defined'); @@ -312,11 +330,11 @@ class Relationship extends ConnectionLine { return this._line2d.isDestControlPointCustom(); } - setIsSrcControlPointCustom(isCustom) { + setIsSrcControlPointCustom(isCustom: boolean) { this._line2d.setIsSrcControlPointCustom(isCustom); } - setIsDestControlPointCustom(isCustom) { + setIsDestControlPointCustom(isCustom: boolean) { this._line2d.setIsDestControlPointCustom(isCustom); } @@ -324,16 +342,14 @@ class Relationship extends ConnectionLine { return this._model.getId(); } - fireEvent(type, event) { + fireEvent(type: string, event: any): void { const elem = this._line2d; elem.trigger(type, event); } + + static getStrokeColor() { + return '#9b74e6'; + } } -Relationship.getStrokeColor = function getStrokeColor() { - return '#9b74e6'; -}; - -Relationship.type = 'Relationship'; - export default Relationship; diff --git a/packages/mindplot/src/components/RelationshipPivot.js b/packages/mindplot/src/components/RelationshipPivot.ts similarity index 86% rename from packages/mindplot/src/components/RelationshipPivot.js rename to packages/mindplot/src/components/RelationshipPivot.ts index d63e8166..7706b16f 100644 --- a/packages/mindplot/src/components/RelationshipPivot.js +++ b/packages/mindplot/src/components/RelationshipPivot.ts @@ -19,21 +19,39 @@ import { CurvedLine, Arrow, Point } from '@wisemapping/web2d'; import { $assert } from '@wisemapping/core-js'; import Relationship from './Relationship'; import Shape from './util/Shape'; +import Workspace from './Workspace'; +import { Designer } from '..'; +import Topic from './Topic'; class RelationshipPivot { - constructor(workspace, designer) { + private _workspace: Workspace; + + private _designer: Designer; + + private _mouseMoveEvent: any; + + private _onClickEvent: any; + + private _onTopicClick: any; + + private _sourceTopic: Topic; + + private _pivot: any; + + private _startArrow: any; + + constructor(workspace: Workspace, designer: Designer) { $assert(workspace, 'workspace can not be null'); $assert(designer, 'designer can not be null'); this._workspace = workspace; this._designer = designer; - // FIXME: the aim of the migration is remove .bind mootools method, please remove these! this._mouseMoveEvent = this._mouseMove.bind(this); this._onClickEvent = this._cleanOnMouseClick.bind(this); this._onTopicClick = this._connectOnFocus.bind(this); } - start(sourceTopic, targetPos) { + start(sourceTopic: Topic, targetPos: Point) { $assert(sourceTopic, 'sourceTopic can not be null'); $assert(targetPos, 'targetPos can not be null'); @@ -75,7 +93,7 @@ class RelationshipPivot { } } - dispose() { + dispose(): void { const workspace = this._workspace; if (this._isActive()) { @@ -99,7 +117,7 @@ class RelationshipPivot { } } - _mouseMove(event) { + _mouseMove(event: MouseEvent): boolean { const screen = this._workspace.getScreenManager(); const pos = screen.getWorkspaceMousePosition(event); @@ -121,13 +139,13 @@ class RelationshipPivot { return false; } - _cleanOnMouseClick(event) { + _cleanOnMouseClick(event: MouseEvent): void { // The user clicks on a desktop on in other element that is not a node. this.dispose(); event.stopPropagation(); } - _calculateFromPosition(toPosition) { + private _calculateFromPosition(toPosition: Point): Point { // Calculate origin position ... let sourcePosition = this._sourceTopic.getPosition(); if (this._sourceTopic.getType() === 'CentralTopic') { @@ -141,19 +159,21 @@ class RelationshipPivot { return Shape.calculateRelationShipPointCoordinates(this._sourceTopic, spoint); } - _connectOnFocus(event, targetTopic) { + private _connectOnFocus(event: string, targetTopic: Topic): void { const sourceTopic = this._sourceTopic; const mindmap = this._designer.getMindmap(); // Avoid circular connections ... if (targetTopic.getId() !== sourceTopic.getId()) { const relModel = mindmap.createRelationship(targetTopic.getId(), sourceTopic.getId()); - this._designer._actionDispatcher.addRelationship(relModel); + this._designer + .getActionDispatcher() + .addRelationship(relModel); } this.dispose(); } - _isActive() { + private _isActive() { return this._pivot != null; } } diff --git a/packages/mindplot/src/components/Topic.js b/packages/mindplot/src/components/Topic.js index b9b09794..7bef2423 100644 --- a/packages/mindplot/src/components/Topic.js +++ b/packages/mindplot/src/components/Topic.js @@ -212,7 +212,9 @@ class Topic extends NodeGraph { return model.getImageSize(); }; - result.setPosition = function setPosition() {}; + result.setPosition = function setPosition() { + // Ignore ... + }; } else if (shapeType === TopicShape.ELLIPSE) { result = new Rect(0.9, attributes); } else if (shapeType === TopicShape.ROUNDED_RECT) { @@ -235,13 +237,19 @@ class Topic extends NodeGraph { result.setStroke(1, 'solid', stokeColor); }; - result.getSize = function getSize() { - return this.size; + result.getSize = () => this.size; + + result.setPosition = () => { + // Overwrite behaviour ... }; - result.setPosition = function setPosition() {}; - result.setFill = function setFill() {}; - result.setStroke = function setStroke() {}; + result.setFill = () => { + // Overwrite behaviour ... + }; + + result.setStroke = () => { + // Overwrite behaviour ... + }; } else { $assert(false, `Unsupported figure shapeType:${shapeType}`); } diff --git a/packages/mindplot/src/components/libraries/bootstrap/BootstrapDialog.js b/packages/mindplot/src/components/libraries/bootstrap/BootstrapDialog.js index ef329717..d914f003 100644 --- a/packages/mindplot/src/components/libraries/bootstrap/BootstrapDialog.js +++ b/packages/mindplot/src/components/libraries/bootstrap/BootstrapDialog.js @@ -100,7 +100,9 @@ class BootstrapDialog extends Options { throw new Error('Unsupported operation'); } - onDialogShown() {} + onDialogShown() { + // Overwrite default behaviour ... + } onRemoveClick(event) { throw new Error('Unsupported operation'); diff --git a/packages/mindplot/src/components/model/INodeModel.ts b/packages/mindplot/src/components/model/INodeModel.ts index 706792de..0603d2b6 100644 --- a/packages/mindplot/src/components/model/INodeModel.ts +++ b/packages/mindplot/src/components/model/INodeModel.ts @@ -18,7 +18,6 @@ */ import { $assert, $defined } from '@wisemapping/core-js'; import FeatureModel from './FeatureModel'; -import IMindmap from './IMindmap'; import Mindmap from './Mindmap'; export type NodeModelType = 'CentralTopic' | 'MainTopic'; @@ -39,7 +38,7 @@ abstract class INodeModel { } getId(): number { - return this.getProperty('id'); + return this.getProperty('id') as number; } abstract getFeatures(): FeatureModel[]; @@ -71,7 +70,7 @@ abstract class INodeModel { } getText(): string { - return this.getProperty('text'); + return this.getProperty('text') as string; } setPosition(x: number, y: number): void { @@ -79,7 +78,7 @@ abstract class INodeModel { } getPosition(): { x: number, y: number } { - const value = this.getProperty('position'); + const value = this.getProperty('position') as string; let result = null; if (value != null) { result = parseJsObject(value); @@ -92,7 +91,7 @@ abstract class INodeModel { } getImageSize(): {width: number, height: number} { - const value = this.getProperty('imageSize'); + const value = this.getProperty('imageSize') as string; let result = null; if (value != null) { result = parseJsObject(value); @@ -105,7 +104,7 @@ abstract class INodeModel { } getMetadata(): string { - return this.getProperty('metadata'); + return this.getProperty('metadata') as string; } setMetadata(json: string): void { @@ -113,10 +112,10 @@ abstract class INodeModel { } getImageUrl(): string { - return this.getProperty('imageUrl'); + return this.getProperty('imageUrl') as string; } - getMindmap(): IMindmap { + getMindmap(): Mindmap { return this._mindmap; } @@ -131,7 +130,7 @@ abstract class INodeModel { /** */ getShapeType(): string { - return this.getProperty('shapeType'); + return this.getProperty('shapeType') as string; } /** */ @@ -148,7 +147,7 @@ abstract class INodeModel { } getOrder(): number { - return this.getProperty('order'); + return this.getProperty('order') as number; } setFontFamily(fontFamily: string): void { @@ -156,7 +155,7 @@ abstract class INodeModel { } getFontFamily(): string { - return this.getProperty('fontFamily'); + return this.getProperty('fontFamily') as string; } /** */ @@ -165,7 +164,7 @@ abstract class INodeModel { } getFontStyle(): string { - return this.getProperty('fontStyle'); + return this.getProperty('fontStyle') as string; } setFontWeight(weight) { @@ -181,7 +180,7 @@ abstract class INodeModel { } getFontColor(): string { - return this.getProperty('fontColor'); + return this.getProperty('fontColor') as string; } setFontSize(size: number) { @@ -189,11 +188,11 @@ abstract class INodeModel { } getFontSize(): number { - return this.getProperty('fontSize'); + return this.getProperty('fontSize') as number; } getBorderColor(): string { - return this.getProperty('borderColor'); + return this.getProperty('borderColor') as string; } setBorderColor(color: string): void { @@ -201,7 +200,7 @@ abstract class INodeModel { } getBackgroundColor(): string { - return this.getProperty('backgroundColor'); + return this.getProperty('backgroundColor') as string; } setBackgroundColor(color: string) { @@ -209,7 +208,7 @@ abstract class INodeModel { } areChildrenShrunken(): boolean { - const result = this.getProperty('shrunken'); + const result = this.getProperty('shrunken') as boolean; return $defined(result) ? result : false; } @@ -291,9 +290,9 @@ abstract class INodeModel { abstract getPropertiesKeys(): string[]; - abstract getProperty(key: string): any; + abstract getProperty(key: string): number | string | boolean; - abstract putProperty(key: string, value: any): void; + abstract putProperty(key: string, value: number | string| boolean): void; abstract setParent(parent: INodeModel): void; diff --git a/packages/mindplot/src/components/model/Mindmap.ts b/packages/mindplot/src/components/model/Mindmap.ts index c2621893..39c01a21 100644 --- a/packages/mindplot/src/components/model/Mindmap.ts +++ b/packages/mindplot/src/components/model/Mindmap.ts @@ -133,7 +133,7 @@ class Mindmap extends IMindmap { * @throws will throw an error if target node is null or undefined * @return the relationship model created */ - createRelationship(sourceNodeId: any, targetNodeId: any) { + createRelationship(sourceNodeId: number, targetNodeId: number):RelationshipModel { $assert($defined(sourceNodeId), 'from node cannot be null'); $assert($defined(targetNodeId), 'to node cannot be null'); @@ -154,7 +154,7 @@ class Mindmap extends IMindmap { this._relationships = this._relationships.filter((r) => r !== relationship); } - findNodeById(id: any) { + findNodeById(id: number) { let result = null; for (let i = 0; i < this._branches.length; i++) { const branch = this._branches[i]; diff --git a/packages/mindplot/src/components/persistence/Pela2TangoMigrator.ts b/packages/mindplot/src/components/persistence/Pela2TangoMigrator.ts index 6b013850..c5b5ddfa 100644 --- a/packages/mindplot/src/components/persistence/Pela2TangoMigrator.ts +++ b/packages/mindplot/src/components/persistence/Pela2TangoMigrator.ts @@ -83,7 +83,7 @@ class Pela2TangoMigrator implements XMLMindmapSerializer { } } - _fixNodePosition(node: { getPosition: () => any; setPosition: (arg0: any, arg1: any) => void; getChildren: () => any; }, parentPosition: { x: number; y: any; }) { + _fixNodePosition(node: NodeModel, parentPosition: {x:number, y:number}) { // Position was not required in previous versions. Try to synthesize one . let position = node.getPosition(); if (!position) { diff --git a/packages/mindplot/src/components/persistence/XMLSerializerFactory.ts b/packages/mindplot/src/components/persistence/XMLSerializerFactory.ts index 97d30a45..d4b0e17d 100644 --- a/packages/mindplot/src/components/persistence/XMLSerializerFactory.ts +++ b/packages/mindplot/src/components/persistence/XMLSerializerFactory.ts @@ -30,6 +30,7 @@ const codeToSerializer = [ codeName: ModelCodeName.BETA, serializer: XMLSerializerBeta, migrator() { + // Ignore .. }, }, { diff --git a/packages/mindplot/src/components/widget/AccountSettingsPanel.js b/packages/mindplot/src/components/widget/AccountSettingsPanel.js index f1cf3f3e..5e5e6e37 100644 --- a/packages/mindplot/src/components/widget/AccountSettingsPanel.js +++ b/packages/mindplot/src/components/widget/AccountSettingsPanel.js @@ -22,6 +22,7 @@ class AccountSettingsPanel extends ListToolbarPanel { constructor(elemId) { const model = { getValue() { + // Overwite default behaviour ... }, setValue() { window.location = '/c/logout'; diff --git a/packages/mindplot/test/playground/layout/lib/raphael-min.js b/packages/mindplot/test/playground/layout/lib/raphael-min.js index e27d122e..e9588cfb 100644 --- a/packages/mindplot/test/playground/layout/lib/raphael-min.js +++ b/packages/mindplot/test/playground/layout/lib/raphael-min.js @@ -121,7 +121,7 @@ w: a.w, k: {}, d: a.d && `M${a.d.replace(/[mlcxtrv]/g, (t) => ({ - l: 'L', c: 'C', x: 'z', t: 'm', r: 'l', v: 'c', + l: 'L', c: 'C', x: 'z', t: 'm', r: 'l', v: 'c', }[t] || 'M'))}z`, }, a.k) for (const s in a.k)a[o](s) && (e.glyphs[n].k[s] = a.k[s]); } @@ -149,29 +149,29 @@ }; var y = function (t) { if ((e = document.documentMode) && (e === 9 || e === 10)) return `url('#${t}')`; let e; const r = document.location; return `url('${r.protocol}//${r.host}${r.pathname}${r.search}#${t}')`; }; const m = function (t) { const e = t.getBBox(1); x(t.pattern, { patternTransform: `${t.matrix.invert()} translate(${e.x},${e.y})` }); }; const b = function (i, n, a) { if (i.type == 'path') { for (var s, o, l, h, u, f = r(n).toLowerCase().split('-'), p = i.paper, v = a ? 'end' : 'start', y = i.node, m = i.attrs, b = m['stroke-width'], _ = f.length, w = 'classic', k = 3, B = 3, C = 5; _--;) switch (f[_]) { case 'block': case 'classic': case 'oval': case 'diamond': case 'open': case 'none': w = f[_]; break; case 'wide': B = 5; break; case 'narrow': B = 2; break; case 'long': k = 5; break; case 'short': k = 2; } if (w == 'open' ? (k += 2, B += 2, C += 2, l = 1, h = a ? 4 : 1, u = { fill: 'none', stroke: m.stroke }) : (h = l = k / 2, u = { fill: m.stroke, stroke: 'none' }), i._.arrows ? a ? (i._.arrows.endPath && g[i._.arrows.endPath]--, i._.arrows.endMarker && g[i._.arrows.endMarker]--) : (i._.arrows.startPath && g[i._.arrows.startPath]--, i._.arrows.startMarker && g[i._.arrows.startMarker]--) : i._.arrows = {}, w != 'none') { - const S = `raphael-marker-${ w}`; const T = `raphael-marker-${ v }${w }${k }${B }-obj${ i.id}`; t._g.doc.getElementById(S) ? g[S]++ : (p.defs.appendChild(x(x('path'), { 'stroke-linecap': 'round', d: d[w], id: S })), g[S] = 1); let A; let M = t._g.doc.getElementById(T); M ? (g[T]++, A = M.getElementsByTagName('use')[0]) : (M = x(x('marker'), { + const S = `raphael-marker-${w}`; const T = `raphael-marker-${v}${w}${k}${B}-obj${i.id}`; t._g.doc.getElementById(S) ? g[S]++ : (p.defs.appendChild(x(x('path'), { 'stroke-linecap': 'round', d: d[w], id: S })), g[S] = 1); let A; let M = t._g.doc.getElementById(T); M ? (g[T]++, A = M.getElementsByTagName('use')[0]) : (M = x(x('marker'), { id: T, markerHeight: B, markerWidth: k, orient: 'auto', refX: h, refY: B / 2, - }), A = x(x('use'), { 'xlink:href': `#${S}`, transform: `${a ? `rotate(180 ${ k / 2 } ${ B / 2 }) ` : c}scale(${k / C},${B / C})`, 'stroke-width': (1 / ((k / C + B / C) / 2)).toFixed(4) }), M.appendChild(A), p.defs.appendChild(M), g[T] = 1), x(A, u); const E = l * (w != 'diamond' && w != 'oval'); a ? (s = i._.arrows.startdx * b || 0, o = t.getTotalLength(m.path) - E * b) : (s = E * b, o = t.getTotalLength(m.path) - (i._.arrows.enddx * b || 0)), (u = {})[`marker-${v}`] = `url(#${T})`, (o || s) && (u.d = t.getSubpath(m.path, s, o)), x(y, u), i._.arrows[`${v}Path`] = S, i._.arrows[`${v}Marker`] = T, i._.arrows[`${v}dx`] = E, i._.arrows[`${v}Type`] = w, i._.arrows[`${v}String`] = n; + }), A = x(x('use'), { 'xlink:href': `#${S}`, transform: `${a ? `rotate(180 ${k / 2} ${B / 2}) ` : c}scale(${k / C},${B / C})`, 'stroke-width': (1 / ((k / C + B / C) / 2)).toFixed(4) }), M.appendChild(A), p.defs.appendChild(M), g[T] = 1), x(A, u); const E = l * (w != 'diamond' && w != 'oval'); a ? (s = i._.arrows.startdx * b || 0, o = t.getTotalLength(m.path) - E * b) : (s = E * b, o = t.getTotalLength(m.path) - (i._.arrows.enddx * b || 0)), (u = {})[`marker-${v}`] = `url(#${T})`, (o || s) && (u.d = t.getSubpath(m.path, s, o)), x(y, u), i._.arrows[`${v}Path`] = S, i._.arrows[`${v}Marker`] = T, i._.arrows[`${v}dx`] = E, i._.arrows[`${v}Type`] = w, i._.arrows[`${v}String`] = n; } else a ? (s = i._.arrows.startdx * b || 0, o = t.getTotalLength(m.path) - s) : (s = 0, o = t.getTotalLength(m.path) - (i._.arrows.enddx * b || 0)), i._.arrows[`${v}Path`] && x(y, { d: t.getSubpath(m.path, s, o) }), delete i._.arrows[`${v}Path`], delete i._.arrows[`${v}Marker`], delete i._.arrows[`${v}dx`], delete i._.arrows[`${v}Type`], delete i._.arrows[`${v}String`]; for (u in g) if (g[e](u) && !g[u]) { const N = t._g.doc.getElementById(u); N && N.parentNode.removeChild(N); } } }; const _ = { '-': [3, 1], '.': [1, 1], '-.': [3, 1, 1, 1], '-..': [3, 1, 1, 1, 1, 1], '. ': [1, 3], '- ': [4, 3], '--': [8, 3], '- .': [4, 3, 1, 3], '--.': [8, 3, 1, 3], '--..': [8, 3, 1, 3, 1, 3], }; const w = function (t, e, i) { if (e = _[r(e).toLowerCase()]) { for (var n = t.attrs['stroke-width'] || '1', a = { round: n, square: n, butt: 0 }[t.attrs['stroke-linecap'] || i['stroke-linecap']] || 0, s = [], o = e.length; o--;)s[o] = e[o] * n + (o % 2 ? 1 : -1) * a; x(t.node, { 'stroke-dasharray': s.join(',') }); } else x(t.node, { 'stroke-dasharray': 'none' }); }; const k = function (i, a) { const l = i.node; const u = i.attrs; const f = l.style.visibility; for (let d in l.style.visibility = 'hidden', a) { - if (a[e](d)) { - if (!t._availableAttrs[e](d)) continue; let g = a[d]; switch (u[d] = g, d) { - case 'blur': i.blur(g); break; case 'title': var y = l.getElementsByTagName('title'); if (y.length && (y = y[0]))y.firstChild.nodeValue = g; else { y = x('title'); const _ = t._g.doc.createTextNode(g); y.appendChild(_), l.appendChild(y); } break; case 'href': case 'target': var k = l.parentNode; if (k.tagName.toLowerCase() != 'a') { const C = x('a'); k.insertBefore(C, l), C.appendChild(l), k = C; }d == 'target' ? k.setAttributeNS(p, 'show', g == 'blank' ? 'new' : g) : k.setAttributeNS(p, d, g); break; case 'cursor': l.style.cursor = g; break; case 'transform': i.transform(g); break; case 'arrow-start': b(i, g); break; case 'arrow-end': b(i, g, 1); break; case 'clip-rect': var S = r(g).split(h); if (S.length == 4) { - i.clip && i.clip.parentNode.parentNode.removeChild(i.clip.parentNode); var T = x('clipPath'); const A = x('rect'); T.id = t.createUUID(), x(A, { - x: S[0], y: S[1], width: S[2], height: S[3], - }), T.appendChild(A), i.paper.defs.appendChild(T), x(l, { 'clip-path': `url(#${ T.id })` }), i.clip = A; - } if (!g) { const M = l.getAttribute('clip-path'); if (M) { const E = t._g.doc.getElementById(M.replace(/(^url\(#|\)$)/g, c)); E && E.parentNode.removeChild(E), x(l, { 'clip-path': c }), delete i.clip; } } break; case 'path': i.type == 'path' && (x(l, { d: g ? u.path = t._pathToAbsolute(g) : 'M0,0' }), i._.dirty = 1, i._.arrows && ('startString' in i._.arrows && b(i, i._.arrows.startString), 'endString' in i._.arrows && b(i, i._.arrows.endString, 1))); break; case 'width': if (l.setAttribute(d, g), i._.dirty = 1, !u.fx) break; d = 'x', g = u.x; case 'x': u.fx && (g = -u.x - (u.width || 0)); case 'rx': if (d == 'rx' && i.type == 'rect') break; case 'cx': l.setAttribute(d, g), i.pattern && m(i), i._.dirty = 1; break; case 'height': if (l.setAttribute(d, g), i._.dirty = 1, !u.fy) break; d = 'y', g = u.y; case 'y': u.fy && (g = -u.y - (u.height || 0)); case 'ry': if (d == 'ry' && i.type == 'rect') break; case 'cy': l.setAttribute(d, g), i.pattern && m(i), i._.dirty = 1; break; case 'r': i.type == 'rect' ? x(l, { rx: g, ry: g }) : l.setAttribute(d, g), i._.dirty = 1; break; case 'src': i.type == 'image' && l.setAttributeNS(p, 'href', g); break; case 'stroke-width': i._.sx == 1 && i._.sy == 1 || (g /= s(o(i._.sx), o(i._.sy)) || 1), l.setAttribute(d, g), u['stroke-dasharray'] && w(i, u['stroke-dasharray'], a), i._.arrows && ('startString' in i._.arrows && b(i, i._.arrows.startString), 'endString' in i._.arrows && b(i, i._.arrows.endString, 1)); break; case 'stroke-dasharray': w(i, g, a); break; case 'fill': var N = r(g).match(t._ISURL); if (N) { - T = x('pattern'); var L = x('image'); T.id = t.createUUID(), x(T, { - x: 0, y: 0, patternUnits: 'userSpaceOnUse', height: 1, width: 1, - }), x(L, { x: 0, y: 0, 'xlink:href': N[1] }), T.appendChild(L), (function (e) { t._preload(N[1], function () { const t = this.offsetWidth; const r = this.offsetHeight; x(e, { width: t, height: r }), x(L, { width: t, height: r }); }); }(T)), i.paper.defs.appendChild(T), x(l, { fill: `url(#${ T.id })` }), i.pattern = T, i.pattern && m(i); break; - } var P = t.getRGB(g); if (P.error) { if ((i.type == 'circle' || i.type == 'ellipse' || r(g).charAt() != 'r') && v(i, g)) { if ('opacity' in u || 'fill-opacity' in u) { var z = t._g.doc.getElementById(l.getAttribute('fill').replace(/^url\(#|\)$/g, c)); if (z) { var F = z.getElementsByTagName('stop'); x(F[F.length - 1], { 'stop-opacity': ('opacity' in u ? u.opacity : 1) * ('fill-opacity' in u ? u['fill-opacity'] : 1) }); } }u.gradient = g, u.fill = 'none'; break; } } else delete a.gradient, delete u.gradient, !t.is(u.opacity, 'undefined') && t.is(a.opacity, 'undefined') && x(l, { opacity: u.opacity }), !t.is(u['fill-opacity'], 'undefined') && t.is(a['fill-opacity'], 'undefined') && x(l, { 'fill-opacity': u['fill-opacity'] }); P[e]('opacity') && x(l, { 'fill-opacity': P.opacity > 1 ? P.opacity / 100 : P.opacity }); case 'stroke': P = t.getRGB(g), l.setAttribute(d, P.hex), d == 'stroke' && P[e]('opacity') && x(l, { 'stroke-opacity': P.opacity > 1 ? P.opacity / 100 : P.opacity }), d == 'stroke' && i._.arrows && ('startString' in i._.arrows && b(i, i._.arrows.startString), 'endString' in i._.arrows && b(i, i._.arrows.endString, 1)); break; case 'gradient': (i.type == 'circle' || i.type == 'ellipse' || r(g).charAt() != 'r') && v(i, g); break; case 'opacity': u.gradient && !u[e]('stroke-opacity') && x(l, { 'stroke-opacity': g > 1 ? g / 100 : g }); case 'fill-opacity': if (u.gradient) { (z = t._g.doc.getElementById(l.getAttribute('fill').replace(/^url\(#|\)$/g, c))) && (F = z.getElementsByTagName('stop'), x(F[F.length - 1], { 'stop-opacity': g })); break; } default: d == 'font-size' && (g = `${n(g, 10)}px`); var R = d.replace(/(\-.)/g, (t) => t.substring(1).toUpperCase()); l.style[R] = g, i._.dirty = 1, l.setAttribute(d, g); + if (a[e](d)) { + if (!t._availableAttrs[e](d)) continue; let g = a[d]; switch (u[d] = g, d) { + case 'blur': i.blur(g); break; case 'title': var y = l.getElementsByTagName('title'); if (y.length && (y = y[0]))y.firstChild.nodeValue = g; else { y = x('title'); const _ = t._g.doc.createTextNode(g); y.appendChild(_), l.appendChild(y); } break; case 'href': case 'target': var k = l.parentNode; if (k.tagName.toLowerCase() != 'a') { const C = x('a'); k.insertBefore(C, l), C.appendChild(l), k = C; }d == 'target' ? k.setAttributeNS(p, 'show', g == 'blank' ? 'new' : g) : k.setAttributeNS(p, d, g); break; case 'cursor': l.style.cursor = g; break; case 'transform': i.transform(g); break; case 'arrow-start': b(i, g); break; case 'arrow-end': b(i, g, 1); break; case 'clip-rect': var S = r(g).split(h); if (S.length == 4) { + i.clip && i.clip.parentNode.parentNode.removeChild(i.clip.parentNode); var T = x('clipPath'); const A = x('rect'); T.id = t.createUUID(), x(A, { + x: S[0], y: S[1], width: S[2], height: S[3], + }), T.appendChild(A), i.paper.defs.appendChild(T), x(l, { 'clip-path': `url(#${T.id})` }), i.clip = A; + } if (!g) { const M = l.getAttribute('clip-path'); if (M) { const E = t._g.doc.getElementById(M.replace(/(^url\(#|\)$)/g, c)); E && E.parentNode.removeChild(E), x(l, { 'clip-path': c }), delete i.clip; } } break; case 'path': i.type == 'path' && (x(l, { d: g ? u.path = t._pathToAbsolute(g) : 'M0,0' }), i._.dirty = 1, i._.arrows && ('startString' in i._.arrows && b(i, i._.arrows.startString), 'endString' in i._.arrows && b(i, i._.arrows.endString, 1))); break; case 'width': if (l.setAttribute(d, g), i._.dirty = 1, !u.fx) break; d = 'x', g = u.x; case 'x': u.fx && (g = -u.x - (u.width || 0)); case 'rx': if (d == 'rx' && i.type == 'rect') break; case 'cx': l.setAttribute(d, g), i.pattern && m(i), i._.dirty = 1; break; case 'height': if (l.setAttribute(d, g), i._.dirty = 1, !u.fy) break; d = 'y', g = u.y; case 'y': u.fy && (g = -u.y - (u.height || 0)); case 'ry': if (d == 'ry' && i.type == 'rect') break; case 'cy': l.setAttribute(d, g), i.pattern && m(i), i._.dirty = 1; break; case 'r': i.type == 'rect' ? x(l, { rx: g, ry: g }) : l.setAttribute(d, g), i._.dirty = 1; break; case 'src': i.type == 'image' && l.setAttributeNS(p, 'href', g); break; case 'stroke-width': i._.sx == 1 && i._.sy == 1 || (g /= s(o(i._.sx), o(i._.sy)) || 1), l.setAttribute(d, g), u['stroke-dasharray'] && w(i, u['stroke-dasharray'], a), i._.arrows && ('startString' in i._.arrows && b(i, i._.arrows.startString), 'endString' in i._.arrows && b(i, i._.arrows.endString, 1)); break; case 'stroke-dasharray': w(i, g, a); break; case 'fill': var N = r(g).match(t._ISURL); if (N) { + T = x('pattern'); var L = x('image'); T.id = t.createUUID(), x(T, { + x: 0, y: 0, patternUnits: 'userSpaceOnUse', height: 1, width: 1, + }), x(L, { x: 0, y: 0, 'xlink:href': N[1] }), T.appendChild(L), (function (e) { t._preload(N[1], function () { const t = this.offsetWidth; const r = this.offsetHeight; x(e, { width: t, height: r }), x(L, { width: t, height: r }); }); }(T)), i.paper.defs.appendChild(T), x(l, { fill: `url(#${T.id})` }), i.pattern = T, i.pattern && m(i); break; + } var P = t.getRGB(g); if (P.error) { if ((i.type == 'circle' || i.type == 'ellipse' || r(g).charAt() != 'r') && v(i, g)) { if ('opacity' in u || 'fill-opacity' in u) { var z = t._g.doc.getElementById(l.getAttribute('fill').replace(/^url\(#|\)$/g, c)); if (z) { var F = z.getElementsByTagName('stop'); x(F[F.length - 1], { 'stop-opacity': ('opacity' in u ? u.opacity : 1) * ('fill-opacity' in u ? u['fill-opacity'] : 1) }); } }u.gradient = g, u.fill = 'none'; break; } } else delete a.gradient, delete u.gradient, !t.is(u.opacity, 'undefined') && t.is(a.opacity, 'undefined') && x(l, { opacity: u.opacity }), !t.is(u['fill-opacity'], 'undefined') && t.is(a['fill-opacity'], 'undefined') && x(l, { 'fill-opacity': u['fill-opacity'] }); P[e]('opacity') && x(l, { 'fill-opacity': P.opacity > 1 ? P.opacity / 100 : P.opacity }); case 'stroke': P = t.getRGB(g), l.setAttribute(d, P.hex), d == 'stroke' && P[e]('opacity') && x(l, { 'stroke-opacity': P.opacity > 1 ? P.opacity / 100 : P.opacity }), d == 'stroke' && i._.arrows && ('startString' in i._.arrows && b(i, i._.arrows.startString), 'endString' in i._.arrows && b(i, i._.arrows.endString, 1)); break; case 'gradient': (i.type == 'circle' || i.type == 'ellipse' || r(g).charAt() != 'r') && v(i, g); break; case 'opacity': u.gradient && !u[e]('stroke-opacity') && x(l, { 'stroke-opacity': g > 1 ? g / 100 : g }); case 'fill-opacity': if (u.gradient) { (z = t._g.doc.getElementById(l.getAttribute('fill').replace(/^url\(#|\)$/g, c))) && (F = z.getElementsByTagName('stop'), x(F[F.length - 1], { 'stop-opacity': g })); break; } default: d == 'font-size' && (g = `${n(g, 10)}px`); var R = d.replace(/(\-.)/g, (t) => t.substring(1).toUpperCase()); l.style[R] = g, i._.dirty = 1, l.setAttribute(d, g); + } } - } -}B(i, a), l.style.visibility = f; + }B(i, a), l.style.visibility = f; }; var B = function (i, a) { if (i.type == 'text' && (a[e]('text') || a[e]('font') || a[e]('font-size') || a[e]('x') || a[e]('y'))) { const s = i.attrs; const o = i.node; const l = o.firstChild ? n(t._g.doc.defaultView.getComputedStyle(o.firstChild, c).getPropertyValue('font-size'), 10) : 10; if (a[e]('text')) { for (s.text = a.text; o.firstChild;)o.removeChild(o.firstChild); for (var h, u = r(a.text).split('\n'), f = [], p = 0, d = u.length; p < d; p++)h = x('tspan'), p && x(h, { dy: 1.2 * l, x: s.x }), h.appendChild(t._g.doc.createTextNode(u[p])), o.appendChild(h), f[p] = h; } else for (p = 0, d = (f = o.getElementsByTagName('tspan')).length; p < d; p++)p ? x(f[p], { dy: 1.2 * l, x: s.x }) : x(f[0], { dy: 0 }); x(o, { x: s.x, y: s.y }), i._.dirty = 1; const g = i._getBBox(); const v = s.y - (g.y + g.height / 2); v && t.is(v, 'finite') && x(f[0], { dy: v }); } }; const C = function (t) { return t.parentNode && t.parentNode.tagName.toLowerCase() === 'a' ? t.parentNode : t; }; const S = function (e, r) { this[0] = this.node = e, e.raphael = !0, this.id = (`0000${(Math.random() * Math.pow(36, 5) << 0).toString(36)}`).slice(-5), e.raphaelid = this.id, this.matrix = t.matrix(), this.realPath = null, this.paper = r, this.attrs = this.attrs || {}, this._ = { transform: [], sx: 1, sy: 1, deg: 0, dx: 0, dy: 0, dirty: 1, @@ -217,7 +217,7 @@ const e = 'hasOwnProperty'; const r = String; const i = parseFloat; const n = Math; const a = n.round; const s = n.max; const o = n.min; const l = n.abs; const h = /[, ]+/; const u = t.eve; const c = ' '; const f = ''; const p = { M: 'm', L: 'l', C: 'c', Z: 'x', m: 't', l: 'r', c: 'v', z: 'x', }; const d = /([clmz]),?([^clmz]*)/gi; const g = / progid:\S+Blur\([^\)]+\)/g; const x = /-?[^,\s-]+/g; const v = 'position:absolute;left:0;top:0;width:1px;height:1px;behavior:url(#default#VML)'; const y = 21600; const m = { path: 1, rect: 1, image: 1 }; const b = { circle: 1, ellipse: 1 }; const _ = function (e, r, i) { const n = t.matrix(); return n.rotate(-e, 0.5, 0.5), { dx: n.x(r, i), dy: n.y(r, i) }; }; const w = function (t, e, r, i, n, a) { const s = t._; const o = t.matrix; const h = s.fillpos; const u = t.node; const f = u.style; let p = 1; let d = ''; const g = y / e; const x = y / r; if (f.visibility = 'hidden', e && r) { if (u.coordsize = l(g) + c + l(x), f.rotation = a * (e * r < 0 ? -1 : 1), a) { var v = _(a, i, n); i = v.dx, n = v.dy; } if (e < 0 && (d += 'x'), r < 0 && (d += ' y') && (p = -1), f.flip = d, u.coordorigin = i * -g + c + n * -x, h || s.fillsize) { let m = u.getElementsByTagName('fill'); m = m && m[0], u.removeChild(m), h && (v = _(a, o.x(h[0], h[1]), o.y(h[0], h[1])), m.position = v.dx * p + c + v.dy * p), s.fillsize && (m.size = s.fillsize[0] * l(e) + c + s.fillsize[1] * l(r)), u.appendChild(m); }f.visibility = 'visible'; } }; t.toString = function () { return `Your browser doesn’t support SVG. Falling down to VML.\nYou are running Raphaël ${this.version}`; }; let k; const B = function (t, e, i) { for (var n = r(e).toLowerCase().split('-'), a = i ? 'end' : 'start', s = n.length, o = 'classic', l = 'medium', h = 'medium'; s--;) switch (n[s]) { case 'block': case 'classic': case 'oval': case 'diamond': case 'open': case 'none': o = n[s]; break; case 'wide': case 'narrow': h = n[s]; break; case 'long': case 'short': l = n[s]; } const u = t.node.getElementsByTagName('stroke')[0]; u[`${a}arrow`] = o, u[`${a}arrowlength`] = l, u[`${a}arrowwidth`] = h; }; const C = function (n, l) { - n.attrs = n.attrs || {}; const u = n.node; const g = n.attrs; let v = u.style; const _ = m[n.type] && (l.x != g.x || l.y != g.y || l.width != g.width || l.height != g.height || l.cx != g.cx || l.cy != g.cy || l.rx != g.rx || l.ry != g.ry || l.r != g.r); const C = b[n.type] && (g.cx != l.cx || g.cy != l.cy || g.r != l.r || g.rx != l.rx || g.ry != l.ry); const T = n; for (const A in l)l[e](A) && (g[A] = l[A]); if (_ && (g.path = t._getPath[n.type](n), n._.dirty = 1), l.href && (u.href = l.href), l.title && (u.title = l.title), l.target && (u.target = l.target), l.cursor && (v.cursor = l.cursor), 'blur' in l && n.blur(l.blur), (l.path && n.type == 'path' || _) && (u.path = (function (e) { let i = /[ahqstv]/gi; let n = t._pathToAbsolute; if (r(e).match(i) && (n = t._path2curve), i = /[clmz]/g, n == t._pathToAbsolute && !r(e).match(i)) { var s = r(e).replace(d, (t, e, r) => { let i = []; const n = 'm' == e.toLowerCase(); let s = p[e]; return r.replace(x, (t) => { n && i.length == 2 && (s += i + p[e == 'm' ? 'l' : 'L'], i = []), i.push(a(t * y)); }), s + i; }); return s; } let o; let l; const h = n(e); s = []; for (let u = 0, g = h.length; u < g; u++) { o = h[u], (l = h[u][0].toLowerCase()) == 'z' && (l = 'x'); for (let v = 1, m = o.length; v < m; v++)l += a(o[v] * y) + (v != m - 1 ? ',' : f); s.push(l); } return s.join(c); }(~r(g.path).toLowerCase().indexOf('r') ? t._pathToAbsolute(g.path) : g.path)), n._.dirty = 1, n.type == 'image' && (n._.fillpos = [g.x, g.y], n._.fillsize = [g.width, g.height], w(n, 1, 1, 0, 0, 0))), 'transform' in l && n.transform(l.transform), C) { const M = +g.cx; const E = +g.cy; const N = +g.rx || +g.r || 0; const L = +g.ry || +g.r || 0; u.path = t.format('ar{0},{1},{2},{3},{4},{1},{4},{1}x', a((M - N) * y), a((E - L) * y), a((M + N) * y), a((E + L) * y), a(M * y)), n._.dirty = 1; } if ('clip-rect' in l) { const P = r(l['clip-rect']).split(h); if (P.length == 4) { P[2] = +P[2] + +P[0], P[3] = +P[3] + +P[1]; const z = u.clipRect || t._g.doc.createElement('div'); const F = z.style; F.clip = t.format('rect({1}px {2}px {3}px {0}px)', P), u.clipRect || (F.position = 'absolute', F.top = 0, F.left = 0, F.width = `${n.paper.width}px`, F.height = `${n.paper.height}px`, u.parentNode.insertBefore(z, u), z.appendChild(u), u.clipRect = z); }l['clip-rect'] || u.clipRect && (u.clipRect.style.clip = 'auto'); } if (n.textpath) { const R = n.textpath.style; l.font && (R.font = l.font), l['font-family'] && (R.fontFamily = `"${l['font-family'].split(',')[0].replace(/^['"]+|['"]+$/g, f)}"`), l['font-size'] && (R.fontSize = l['font-size']), l['font-weight'] && (R.fontWeight = l['font-weight']), l['font-style'] && (R.fontStyle = l['font-style']); } if ('arrow-start' in l && B(T, l['arrow-start']), 'arrow-end' in l && B(T, l['arrow-end'], 1), l.opacity != null || l.fill != null || l.src != null || l.stroke != null || l['stroke-width'] != null || l['stroke-opacity'] != null || l['fill-opacity'] != null || l['stroke-dasharray'] != null || l['stroke-miterlimit'] != null || l['stroke-linejoin'] != null || l['stroke-linecap'] != null) { + n.attrs = n.attrs || {}; const u = n.node; const g = n.attrs; let v = u.style; const _ = m[n.type] && (l.x != g.x || l.y != g.y || l.width != g.width || l.height != g.height || l.cx != g.cx || l.cy != g.cy || l.rx != g.rx || l.ry != g.ry || l.r != g.r); const C = b[n.type] && (g.cx != l.cx || g.cy != l.cy || g.r != l.r || g.rx != l.rx || g.ry != l.ry); const T = n; for (const A in l)l[e](A) && (g[A] = l[A]); if (_ && (g.path = t._getPath[n.type](n), n._.dirty = 1), l.href && (u.href = l.href), l.title && (u.title = l.title), l.target && (u.target = l.target), l.cursor && (v.cursor = l.cursor), 'blur' in l && n.blur(l.blur), (l.path && n.type == 'path' || _) && (u.path = (function (e) { let i = /[ahqstv]/gi; let n = t._pathToAbsolute; if (r(e).match(i) && (n = t._path2curve), i = /[clmz]/g, n == t._pathToAbsolute && !r(e).match(i)) { var s = r(e).replace(d, (t, e, r) => { let i = []; const n = e.toLowerCase() == 'm'; let s = p[e]; return r.replace(x, (t) => { n && i.length == 2 && (s += i + p[e == 'm' ? 'l' : 'L'], i = []), i.push(a(t * y)); }), s + i; }); return s; } let o; let l; const h = n(e); s = []; for (let u = 0, g = h.length; u < g; u++) { o = h[u], (l = h[u][0].toLowerCase()) == 'z' && (l = 'x'); for (let v = 1, m = o.length; v < m; v++)l += a(o[v] * y) + (v != m - 1 ? ',' : f); s.push(l); } return s.join(c); }(~r(g.path).toLowerCase().indexOf('r') ? t._pathToAbsolute(g.path) : g.path)), n._.dirty = 1, n.type == 'image' && (n._.fillpos = [g.x, g.y], n._.fillsize = [g.width, g.height], w(n, 1, 1, 0, 0, 0))), 'transform' in l && n.transform(l.transform), C) { const M = +g.cx; const E = +g.cy; const N = +g.rx || +g.r || 0; const L = +g.ry || +g.r || 0; u.path = t.format('ar{0},{1},{2},{3},{4},{1},{4},{1}x', a((M - N) * y), a((E - L) * y), a((M + N) * y), a((E + L) * y), a(M * y)), n._.dirty = 1; } if ('clip-rect' in l) { const P = r(l['clip-rect']).split(h); if (P.length == 4) { P[2] = +P[2] + +P[0], P[3] = +P[3] + +P[1]; const z = u.clipRect || t._g.doc.createElement('div'); const F = z.style; F.clip = t.format('rect({1}px {2}px {3}px {0}px)', P), u.clipRect || (F.position = 'absolute', F.top = 0, F.left = 0, F.width = `${n.paper.width}px`, F.height = `${n.paper.height}px`, u.parentNode.insertBefore(z, u), z.appendChild(u), u.clipRect = z); }l['clip-rect'] || u.clipRect && (u.clipRect.style.clip = 'auto'); } if (n.textpath) { const R = n.textpath.style; l.font && (R.font = l.font), l['font-family'] && (R.fontFamily = `"${l['font-family'].split(',')[0].replace(/^['"]+|['"]+$/g, f)}"`), l['font-size'] && (R.fontSize = l['font-size']), l['font-weight'] && (R.fontWeight = l['font-weight']), l['font-style'] && (R.fontStyle = l['font-style']); } if ('arrow-start' in l && B(T, l['arrow-start']), 'arrow-end' in l && B(T, l['arrow-end'], 1), l.opacity != null || l.fill != null || l.src != null || l.stroke != null || l['stroke-width'] != null || l['stroke-opacity'] != null || l['fill-opacity'] != null || l['stroke-dasharray'] != null || l['stroke-miterlimit'] != null || l['stroke-linejoin'] != null || l['stroke-linecap'] != null) { let j = u.getElementsByTagName('fill'); if (!(j = j && j[0]) && (j = k('fill')), n.type == 'image' && l.src && (j.src = l.src), l.fill && (j.on = !0), j.on != null && l.fill != 'none' && l.fill !== null || (j.on = !1), j.on && l.fill) { const I = r(l.fill).match(t._ISURL); if (I) { j.parentNode == u && u.removeChild(j), j.rotate = !0, j.src = I[1], j.type = 'tile'; const D = n.getBBox(1); j.position = D.x + c + D.y, n._.fillpos = [D.x, D.y], t._preload(I[1], function () { n._.fillsize = [this.offsetWidth, this.offsetHeight]; }); } else j.color = t.getRGB(l.fill).hex, j.src = f, j.type = 'solid', t.getRGB(l.fill).error && (T.type in { circle: 1, ellipse: 1 } || r(l.fill).charAt() != 'r') && S(T, l.fill, j) && (g.fill = 'none', g.gradient = l.fill, j.rotate = !1); } if ('fill-opacity' in l || 'opacity' in l) { var q = ((+g['fill-opacity'] + 1 || 2) - 1) * ((+g.opacity + 1 || 2) - 1) * ((+t.getRGB(l.fill).o + 1 || 2) - 1); q = o(s(q, 0), 1), j.opacity = q, j.src && (j.color = 'none'); }u.appendChild(j); let O = u.getElementsByTagName('stroke') && u.getElementsByTagName('stroke')[0]; let V = !1; !O && (V = O = k('stroke')), (l.stroke && l.stroke != 'none' || l['stroke-width'] || l['stroke-opacity'] != null || l['stroke-dasharray'] || l['stroke-miterlimit'] || l['stroke-linejoin'] || l['stroke-linecap']) && (O.on = !0), (l.stroke == 'none' || l.stroke === null || O.on == null || l.stroke == 0 || l['stroke-width'] == 0) && (O.on = !1); const W = t.getRGB(l.stroke); O.on && l.stroke && (O.color = W.hex), q = ((+g['stroke-opacity'] + 1 || 2) - 1) * ((+g.opacity + 1 || 2) - 1) * ((+W.o + 1 || 2) - 1); let Y = 0.75 * (i(l['stroke-width']) || 1); if (q = o(s(q, 0), 1), l['stroke-width'] == null && (Y = g['stroke-width']), l['stroke-width'] && (O.weight = Y), Y && Y < 1 && (q *= Y) && (O.weight = 1), O.opacity = q, l['stroke-linejoin'] && (O.joinstyle = l['stroke-linejoin'] || 'miter'), O.miterlimit = l['stroke-miterlimit'] || 8, l['stroke-linecap'] && (O.endcap = l['stroke-linecap'] == 'butt' ? 'flat' : l['stroke-linecap'] == 'square' ? 'square' : 'round'), 'stroke-dasharray' in l) { const G = { '-': 'shortdash', '.': 'shortdot', '-.': 'shortdashdot', '-..': 'shortdashdotdot', '. ': 'dot', '- ': 'dash', '--': 'longdash', '- .': 'dashdot', '--.': 'longdashdot', '--..': 'longdashdotdot', diff --git a/packages/mindplot/test/playground/map-render/js/editor.js b/packages/mindplot/test/playground/map-render/js/editor.js index 7b3a8e75..6e5409d7 100644 --- a/packages/mindplot/test/playground/map-render/js/editor.js +++ b/packages/mindplot/test/playground/map-render/js/editor.js @@ -8,8 +8,8 @@ global.accountName = 'Test User'; global.accountEmail = 'test@example.com'; const p = new LocalStorageManager('samples/{id}.wxml'); -const options = DesignerOptionsBuilder.buildOptions({ - persistenceManager: p +const options = DesignerOptionsBuilder.buildOptions({ + persistenceManager: p, }); const designer = buildDesigner(options); diff --git a/packages/mindplot/test/unit/export/Helper.ts b/packages/mindplot/test/unit/export/Helper.ts index 7d65de25..cccbd2b8 100644 --- a/packages/mindplot/test/unit/export/Helper.ts +++ b/packages/mindplot/test/unit/export/Helper.ts @@ -16,11 +16,11 @@ * limitations under the License. */ import { Blob } from 'blob-polyfill'; -import Exporter from '../../../src/components/export/Exporter'; import path from 'path'; import fs from 'fs'; import { diff } from 'jest-diff'; import { expect } from '@jest/globals'; +import Exporter from '../../../src/components/export/Exporter'; const saveOutputRecord = false; @@ -40,31 +40,31 @@ export const parseXMLFile = (filePath: fs.PathOrFileDescriptor, mimeType: DOMPar let content = stream.toString(); // Hack for SVG exported from the browser ... - if(mimeType=="image/svg+xml"){ - content = content.replace(' { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(xmlStr, mimeType); // Is there any parsing error ?. - if (xmlDoc.getElementsByTagName("parsererror").length > 0) { + if (xmlDoc.getElementsByTagName('parsererror').length > 0) { const xmmStr = new XMLSerializer().serializeToString(xmlDoc); console.log(xmmStr); throw new Error(`Unexpected error parsing: ${xmlStr}. Error: ${xmmStr}`); } return xmlDoc; -} +}; export const exporterAssert = async (testName: string, exporter: Exporter) => { const actualStr = await exporter.export(); - //Compared with expected ... + // Compared with expected ... const expectedPath = path.resolve(__dirname, `./expected/${testName}.${exporter.extension()}`); if (saveOutputRecord) { fs.writeFileSync(expectedPath, actualStr); @@ -73,8 +73,8 @@ export const exporterAssert = async (testName: string, exporter: Exporter) => { // compare with expected ... const expectedStr = fs.readFileSync(expectedPath).toString(); if (actualStr !== expectedStr) { - const diffResult = diff(actualStr, expectedStr); - console.log(diffResult); - expect(actualStr).toEqual(expectedStr); + const diffResult = diff(actualStr, expectedStr); + console.log(diffResult); + expect(actualStr).toEqual(expectedStr); } -} \ No newline at end of file +}; diff --git a/packages/mindplot/test/unit/export/SVGExporterTestSuite.test.ts b/packages/mindplot/test/unit/export/SVGExporterTestSuite.test.ts index dfa25f1f..0f7802d2 100644 --- a/packages/mindplot/test/unit/export/SVGExporterTestSuite.test.ts +++ b/packages/mindplot/test/unit/export/SVGExporterTestSuite.test.ts @@ -1,7 +1,7 @@ -import Mindmap from '../../../src/components/model/Mindmap'; import path from 'path'; import fs from 'fs'; import { expect, test } from '@jest/globals'; // Workaround for cypress conflict +import Mindmap from '../../../src/components/model/Mindmap'; import XMLSerializerFactory from '../../../src/components/persistence/XMLSerializerFactory'; import SVGExporter from '../../../src/components/export/SVGExporter'; import { parseXMLFile, setupBlob, exporterAssert } from './Helper'; @@ -11,23 +11,22 @@ setupBlob(); describe('SVG export test execution', () => { test.each(fs.readdirSync(path.resolve(__dirname, './input/')) .filter((f) => f.endsWith('.wxml')) - .map((filename: string) => filename.split('.')[0])) - (`Exporting %p suite`, async (testName: string) => { - // Load mindmap DOM ... - const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`); - const mapDocument = parseXMLFile(mindmapPath, 'text/xml'); + .map((filename: string) => filename.split('.')[0]))('Exporting %p suite', async (testName: string) => { + // Load mindmap DOM ... + const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`); + const mapDocument = parseXMLFile(mindmapPath, 'text/xml'); - // Convert to mindmap ... - const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument); - const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName); + // Convert to mindmap ... + const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument); + const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName); - // Load SVG ... - const svgPath = path.resolve(__dirname, `./input/${testName}.svg`); - expect(fs.existsSync(svgPath)).toEqual(true); - const svgDocument = parseXMLFile(svgPath, 'image/svg+xml'); + // Load SVG ... + const svgPath = path.resolve(__dirname, `./input/${testName}.svg`); + expect(fs.existsSync(svgPath)).toEqual(true); + const svgDocument = parseXMLFile(svgPath, 'image/svg+xml'); - // Generate output ... - const exporter = new SVGExporter(mindmap, svgDocument.documentElement); - await exporterAssert(testName, exporter); - }); + // Generate output ... + const exporter = new SVGExporter(mindmap, svgDocument.documentElement); + await exporterAssert(testName, exporter); + }); }); diff --git a/packages/mindplot/test/unit/export/TextExporterTestSuite.test.ts b/packages/mindplot/test/unit/export/TextExporterTestSuite.test.ts index 0d2c6c92..dec9bb3a 100644 --- a/packages/mindplot/test/unit/export/TextExporterTestSuite.test.ts +++ b/packages/mindplot/test/unit/export/TextExporterTestSuite.test.ts @@ -1,61 +1,58 @@ -import Mindmap from '../../../src/components/model/Mindmap'; import path from 'path'; +import fs from 'fs'; +import { test } from '@jest/globals'; // Workaround for cypress conflict +import Mindmap from '../../../src/components/model/Mindmap'; import XMLSerializerFactory from '../../../src/components/persistence/XMLSerializerFactory'; import TextExporterFactory from '../../../src/components/export/TextExporterFactory'; import { parseXMLFile, setupBlob, exporterAssert } from './Helper'; -import fs from 'fs'; -import { test } from '@jest/globals'; // Workaround for cypress conflict setupBlob(); const testNames = fs.readdirSync(path.resolve(__dirname, './input/')) -.filter((f) => f.endsWith('.wxml')) -.map((filename: string) => filename.split('.')[0]); + .filter((f) => f.endsWith('.wxml')) + .map((filename: string) => filename.split('.')[0]); describe('WXML export test execution', () => { - test.each(testNames) - (`Exporting %p suite`, async (testName: string) => { - // Load mindmap DOM ... - const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`); - const mapDocument = parseXMLFile(mindmapPath, 'text/xml'); + test.each(testNames)('Exporting %p suite', async (testName: string) => { + // Load mindmap DOM ... + const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`); + const mapDocument = parseXMLFile(mindmapPath, 'text/xml'); - // Convert to mindmap ... - const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument); - const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName); + // Convert to mindmap ... + const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument); + const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName); - const exporter = TextExporterFactory.create('wxml', mindmap); - await exporterAssert(testName, exporter); - }); + const exporter = TextExporterFactory.create('wxml', mindmap); + await exporterAssert(testName, exporter); }); +}); - describe('Txt export test execution', () => { - test.each(testNames) - (`Exporting %p suite`, async (testName: string) => { - // Load mindmap DOM ... - const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`); - const mapDocument = parseXMLFile(mindmapPath, 'text/xml'); - - // Convert to mindmap ... - const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument); - const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName); - - const exporter = TextExporterFactory.create('txt', mindmap); - await exporterAssert(testName, exporter); - }); - }); +describe('Txt export test execution', () => { + test.each(testNames)('Exporting %p suite', async (testName: string) => { + // Load mindmap DOM ... + const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`); + const mapDocument = parseXMLFile(mindmapPath, 'text/xml'); - describe('MD export test execution', () => { - test.each(testNames) - (`Exporting %p suite`, async (testName: string) => { - // Load mindmap DOM ... - const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`); - const mapDocument = parseXMLFile(mindmapPath, 'text/xml'); - - // Convert to mindmap ... - const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument); - const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName); - - const exporter = TextExporterFactory.create('md', mindmap); - await exporterAssert(testName, exporter); - }); -}); + // Convert to mindmap ... + const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument); + const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName); + + const exporter = TextExporterFactory.create('txt', mindmap); + await exporterAssert(testName, exporter); + }); +}); + +describe('MD export test execution', () => { + test.each(testNames)('Exporting %p suite', async (testName: string) => { + // Load mindmap DOM ... + const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`); + const mapDocument = parseXMLFile(mindmapPath, 'text/xml'); + + // Convert to mindmap ... + const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument); + const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName); + + const exporter = TextExporterFactory.create('md', mindmap); + await exporterAssert(testName, exporter); + }); +}); diff --git a/packages/mindplot/test/unit/layout/Constants.ts b/packages/mindplot/test/unit/layout/Constants.ts index dd26e691..be6b5f30 100644 --- a/packages/mindplot/test/unit/layout/Constants.ts +++ b/packages/mindplot/test/unit/layout/Constants.ts @@ -1,5 +1,5 @@ const Constants = { - NODE_SIZE: { width: 80, height: 30 }, - ROOT_NODE_SIZE: { width: 120, height: 40 } -} + NODE_SIZE: { width: 80, height: 30 }, + ROOT_NODE_SIZE: { width: 120, height: 40 }, +}; export default Constants; diff --git a/packages/mindplot/webpack.playground.js b/packages/mindplot/webpack.playground.js index 76961c35..665d1a97 100644 --- a/packages/mindplot/webpack.playground.js +++ b/packages/mindplot/webpack.playground.js @@ -2,8 +2,8 @@ const path = require('path'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin'); -const common = require('./webpack.common'); const { merge } = require('webpack-merge'); +const common = require('./webpack.common'); const playgroundConfig = { mode: 'development',