From a3243dd1bae196382d460098f85a698a8ab6d686 Mon Sep 17 00:00:00 2001 From: Gregory Bednov Date: Thu, 16 Jan 2025 18:08:10 +0300 Subject: [PATCH] Add files via upload --- AddObjectForm.svelte | 271 ++++++++++++++++++++++++++++++ App.svelte | 17 ++ CustomGlobalConnectRules.ts | 43 +++++ CustomGlobalConnectRulesModule.ts | 8 + CustomOutlineModule.ts | 62 +++++++ CustomPaletteModule.ts | 89 ++++++++++ CustomShapeRendererModule.ts | 67 ++++++++ Diagram.svelte | 28 +++ ManhattanConnectionModule.ts | 54 ++++++ StyleModule.ts | 11 ++ editor.ts | 64 +++++++ main.ts | 13 ++ style.css | 143 ++++++++++++++++ vite-env.d.ts | 1 + 14 files changed, 871 insertions(+) create mode 100644 AddObjectForm.svelte create mode 100644 App.svelte create mode 100644 CustomGlobalConnectRules.ts create mode 100644 CustomGlobalConnectRulesModule.ts create mode 100644 CustomOutlineModule.ts create mode 100644 CustomPaletteModule.ts create mode 100644 CustomShapeRendererModule.ts create mode 100644 Diagram.svelte create mode 100644 ManhattanConnectionModule.ts create mode 100644 StyleModule.ts create mode 100644 editor.ts create mode 100644 main.ts create mode 100644 style.css create mode 100644 vite-env.d.ts diff --git a/AddObjectForm.svelte b/AddObjectForm.svelte new file mode 100644 index 0000000..9a8300b --- /dev/null +++ b/AddObjectForm.svelte @@ -0,0 +1,271 @@ + + +
+ +
+ + {#if типОбъекта === 'Прибор'} + +
+ + +
+ + +
+ + +
+ + +
+ +Функции + {#each функции as функция, i} +
+ + + + +
+ {/each} + + + {:else} + +
+ + +
+ {/if} +
+ +
+
+ \ No newline at end of file diff --git a/App.svelte b/App.svelte new file mode 100644 index 0000000..5e39ba3 --- /dev/null +++ b/App.svelte @@ -0,0 +1,17 @@ + + +
+

FSA Editor

+ + +
+ + diff --git a/CustomGlobalConnectRules.ts b/CustomGlobalConnectRules.ts new file mode 100644 index 0000000..210f8bd --- /dev/null +++ b/CustomGlobalConnectRules.ts @@ -0,0 +1,43 @@ +import RuleProvider from 'diagram-js/lib/features/rules/RuleProvider'; +export default class CustomGlobalConnectRules extends RuleProvider { + static $inject = ['eventBus']; + + constructor(eventBus: any) { + super(eventBus); + } + + init(): void { + // Правило для начала соединения + this.addRule('connection.start', (context) => { + return true; + const { source } = context; + + if (source?.businessObject?.type === 'custom:connectable') { + return true; // Разрешить соединение + } + + return false; // Запретить соединение + }); + + // Правило для создания соединения + this.addRule('connection.create', (context) => { + //return true; + const { source, target } = context; + // console.log(typeof source); + // console.log(source.constructor.name) + // instanceof Shape); + + //if (source?.type === Shape) + + //if ( + // source?.businessObject?.type === 'custom:connectable' && + // target?.businessObject?.type === 'custom:connectable' + //) { + return { type: 'Connection' }; + // { type: 'Connection' }; // Тип соединения +// } + + return false; // Запретить соединение + }); + } +} diff --git a/CustomGlobalConnectRulesModule.ts b/CustomGlobalConnectRulesModule.ts new file mode 100644 index 0000000..424e449 --- /dev/null +++ b/CustomGlobalConnectRulesModule.ts @@ -0,0 +1,8 @@ +import CustomGlobalConnectRules from './CustomGlobalConnectRules'; + +const CustomGlobalConnectRulesModule = { + __init__: ['customGlobalConnectRules'], + customGlobalConnectRules: ['type', CustomGlobalConnectRules] +}; + +export default CustomGlobalConnectRulesModule; \ No newline at end of file diff --git a/CustomOutlineModule.ts b/CustomOutlineModule.ts new file mode 100644 index 0000000..7133159 --- /dev/null +++ b/CustomOutlineModule.ts @@ -0,0 +1,62 @@ +import { Element } from 'diagram-js/lib/model/Types'; +import { Outline } from 'diagram-js/lib/features/outline/OutlineProvider'; +import OutlineProvider from 'diagram-js/lib/features/outline/OutlineProvider'; +import { + attr as svgAttr, + create as svgCreate} from 'tiny-svg'; + +import Styles from 'diagram-js/lib/draw/Styles'; + +function CustomOutlineProvider(outline:OutlineProvider, styles:Styles) { + this._styles = styles; + outline.registerProvider(this); +} + +CustomOutlineProvider.$inject = [ + 'outline', + 'styles' +]; + +CustomOutlineProvider.prototype.getOutline = function(element:Element) { + if (element.type === 'custom:circle') { + const outline = svgCreate('circle'); + + svgAttr(outline , { + x: `${element.x}`, + y: `${element.y}`, + cx: element.width / 2, + cy: element.height / 2, + r: 60, + fill: "none", + }); + + console.log(outline); + return outline; + } +} + +CustomOutlineProvider.prototype.updateOutline = function(element: Element, outline: Outline) { + if (element.type === 'custom:circle') { + outline = svgCreate('rect'); + + svgAttr(outline , { + x: `${element.x}`, + y: `${element.y}`, + cx: element.width / 2, + cy: element.height / 2, + r: 60, + fill: "none", + }); + } + console.log(outline); + + return false; +} + +const CustomOutlineModule = { + __init__: ['outlineProvider'], + __depends__: [ 'Outline' ], + outlineProvider: ['type', CustomOutlineProvider] +}; + +export default CustomOutlineModule; diff --git a/CustomPaletteModule.ts b/CustomPaletteModule.ts new file mode 100644 index 0000000..9c9eb51 --- /dev/null +++ b/CustomPaletteModule.ts @@ -0,0 +1,89 @@ +import ElementFactory from "diagram-js/lib/core/ElementFactory"; +import Palette from "diagram-js/lib/features/palette/Palette"; +import LassoTool from "diagram-js/lib/features/lasso-tool/LassoTool"; +import Create from "diagram-js/lib/features/create/Create"; +import GlobalConnect from "diagram-js/lib/features/global-connect/GlobalConnect"; + +function PalettePlugin (create: Create, + elementFactory:ElementFactory, + globalConnect: GlobalConnect, + lassoTool: LassoTool, + palette: Palette) { + palette.registerProvider({ + getPaletteEntries: () => ({ + 'hand-tool': { + group: 'tools', + className: 'icon-hand-tool', + title: 'Hand Tool', + action: { + click: function() { + //console.log("Hello"); + } + } + }, + 'lasso-tool': { + group: 'tools', + className: 'icon-lasso-tool', + title: 'Lasso Tool', + action: { + click: function(event) { + lassoTool.activateSelection(event as MouseEvent); + } + } + }, + 'tool-separator': { + group: 'tools', + separator: true, + action: {} + }, + 'create-shape': { + group: 'create', + className: 'icon-create-shape', + title: 'Create Shape', + action: { + click: function() { + var shape = elementFactory.createShape({ + width: 100, + height: 80, + canStartConnection:true + }); + console.log(shape.canStartConnection); + create.start(event, shape); + } + } + }, + 'create-device': { + group: 'create', + className: 'icon-create-shape', + title: 'Create Device', + action: { + click: function() { + var shape = elementFactory.createShape({ + width: 100, + height: 80, + canStartConnection:true, + type: 'custom:circle' + }); + console.log(shape.canStartConnection); + create.start(event, shape); + } + } + }, + 'create-connection': { + group: 'create', + className: 'icon-connect', + title: 'Create Connection', + action: { + click: (event) => { + globalConnect.start(event, false); + } + } + } + }) + }); +} + +export default { + __init__: [ 'palettePlugin' ], + palettePlugin: [ 'type', PalettePlugin ] + }; \ No newline at end of file diff --git a/CustomShapeRendererModule.ts b/CustomShapeRendererModule.ts new file mode 100644 index 0000000..8ffac93 --- /dev/null +++ b/CustomShapeRendererModule.ts @@ -0,0 +1,67 @@ +import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer'; +import { assign } from 'min-dash'; +import { + append as svgAppend, + attr as svgAttr, + create as svgCreate +} from 'tiny-svg'; +import { data } from './AddObjectForm.svelte'; + + +const HIGH_PRIORITY = 1500; + +class CustomShapeRenderer extends BaseRenderer { + + static $inject = ['eventBus', 'styles']; + + constructor(eventBus: any, styles: any) { + super(eventBus, HIGH_PRIORITY); + this.styles = styles; + this.SHAPE_STYLE = styles.style({ fill: 'Canvas', stroke: 'CanvasText', strokeWidth: 2 }); + } + + canRender(element: any): boolean { + return element.type === 'custom:circle'; + } + + + drawShape(visuals, element, attrs): SVGElement { + console.log(data); + var circle = svgCreate('circle'); + + svgAttr(circle, { + cx: `${element.width / 2}`, + cy: `${element.height / 2 - 40}`, + r: '2.5mm', + fill: "none", + stroke: "CanvasText", + }); + + var line = svgCreate('line'); + svgAttr(line, { + x1: element.width / 2, + x2: element.width / 2, + y1: element.height/2, + y2: element.height/2 - 30 - 2, + stroke: "CanvasText", + + }) + + var g = svgCreate('g'); + svgAppend(g, circle); + svgAppend(g, line); + + svgAttr(g, assign({}, this.SHAPE_STYLE, attrs || {})); + svgAppend(visuals, g); + return g; + } +} + + +const CustomShapeRendererModule = { + __init__: ['customShapeRenderer'], + customShapeRenderer: ['type', CustomShapeRenderer] +}; + + +export default CustomShapeRendererModule; \ No newline at end of file diff --git a/Diagram.svelte b/Diagram.svelte new file mode 100644 index 0000000..7b7896b --- /dev/null +++ b/Diagram.svelte @@ -0,0 +1,28 @@ + + + + +
\ No newline at end of file diff --git a/ManhattanConnectionModule.ts b/ManhattanConnectionModule.ts new file mode 100644 index 0000000..05d16e1 --- /dev/null +++ b/ManhattanConnectionModule.ts @@ -0,0 +1,54 @@ + +import { connectPoints } from 'diagram-js/lib/layout/ManhattanLayout'; +import Modeling from 'diagram-js/lib/features/modeling/Modeling'; +import EventBus from 'diagram-js/lib/core/EventBus'; +import { Connection } from 'diagram-js/lib/model/Types'; + +export function updateWaypointsByManhattan (connection: Connection, modeling: Modeling ): void { + if (connection.source && connection.target) { + const x0 = connection.source.x + connection.source.width / 2; + const x1 = connection.target.x + connection.target.width / 2; + const y0 = connection.source.y + connection.source.height / 2; + const y1 = connection.target.y + connection.target.height / 2; + const x2 = (Math.abs(x0-x1) < 5) ? x0 : x1; + const y2 = (Math.abs(y0-y1) < 5) ? y0 : y1; + const waypoints = connectPoints( + { x: x0, y: y0 }, + { x: x2, y: y2 }); + + const hasChanged = JSON.stringify(connection.waypoints) != JSON.stringify(waypoints); + if (hasChanged) { + modeling.updateWaypoints(connection, waypoints) + } + } +} + +function ManhattanLayoutPlugin(eventBus: EventBus, modeling: Modeling) { + eventBus.on('commandStack.connection.create.executed', (event) => { + var connection = (event as any).element; + if (connection) { + updateWaypointsByManhattan(connection, modeling); + } + }); + + + eventBus.on("shape.move.end", (event) => { + var shape = (event as any).shape; + if (shape.incoming) { + shape.incoming.forEach((element: Connection) => { + updateWaypointsByManhattan(element, modeling); + }); + } + + if (shape.outgoing) { + shape.outgoing.forEach((element: Connection) => { + updateWaypointsByManhattan(element, modeling); + }); + } + }); +} + +export default { + __init__: [ 'manhattanLayoutPlugin' ], + manhattanLayoutPlugin: [ 'type', ManhattanLayoutPlugin ] +}; diff --git a/StyleModule.ts b/StyleModule.ts new file mode 100644 index 0000000..8bff962 --- /dev/null +++ b/StyleModule.ts @@ -0,0 +1,11 @@ +export default { + __init__: ['customRenderer'], + customRenderer: [ + 'type', + function (defaultRenderer: any) { + defaultRenderer.CONNECTION_STYLE = { fill: 'none', strokeWidth: 5, stroke: 'CanvasText' }; + defaultRenderer.SHAPE_STYLE = { fill: 'Canvas', stroke: 'CanvasText', strokeWidth: 2 }; + defaultRenderer.FRAME_STYLE = { fill: 'none', stroke: 'CanvasText', strokeDasharray: 4, strokeWidth: 2 }; + } + ] +}; \ No newline at end of file diff --git a/editor.ts b/editor.ts new file mode 100644 index 0000000..4c823b3 --- /dev/null +++ b/editor.ts @@ -0,0 +1,64 @@ +import Diagram from 'diagram-js'; +import ConnectModule from 'diagram-js/lib/features/connect'; +import ContextPadModule from 'diagram-js/lib/features/context-pad'; +import CreateModule from 'diagram-js/lib/features/create'; +import LassoToolModule from 'diagram-js/lib/features/lasso-tool'; +import ModelingModule from 'diagram-js/lib/features/modeling'; +import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'; +import MoveModule from 'diagram-js/lib/features/move'; +import OutlineModule from 'diagram-js/lib/features/outline'; +import PaletteModule from 'diagram-js/lib/features/palette'; +import ResizeModule from 'diagram-js/lib/features/resize'; +import RulesModule from 'diagram-js/lib/features/rules'; +import SelectionModule from 'diagram-js/lib/features/selection'; +import GlobalConnectModule from 'diagram-js/lib/features/global-connect'; +import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll'; +import BendpointMoveModule from 'diagram-js/lib/features/bendpoints'; +import StyleModule from './StyleModule.ts'; +import ManhattanConnectionModule from './ManhattanConnectionModule.ts'; +import CustomPaletteModule from './CustomPaletteModule.ts'; +import CustomGlobalConnectRulesModule from './CustomGlobalConnectRulesModule.ts'; +import CustomShapeRendererModule from './CustomShapeRendererModule.ts'; +import CustomOutlineModule from './CustomOutlineModule.ts'; + +interface EditorOptions { + container: HTMLElement; + additionalModules?: Array; +} + +export default function Editor(options: EditorOptions): Diagram { + const { container } = options; + + const modules = [ + BendpointMoveModule + , ConnectModule + , ContextPadModule + , CreateModule + , GlobalConnectModule + , LassoToolModule + , ModelingModule + , MoveCanvasModule + , MoveModule + //, OutlineModule + , PaletteModule + //, ResizeModule + , RulesModule + , SelectionModule + , ZoomScrollModule + , StyleModule + , ManhattanConnectionModule + , CustomPaletteModule + , CustomGlobalConnectRulesModule + , CustomShapeRendererModule + , CustomOutlineModule + ]; + + + console.log(container); + return new Diagram({ + canvas: { + container + }, + modules: modules + }); +} diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..56f8d21 --- /dev/null +++ b/main.ts @@ -0,0 +1,13 @@ +import { mount } from 'svelte' +import App from './App.svelte'; + +const target = document.getElementById('app'); + +if (!target) { + throw new Error("Target element with ID 'app' not found in DOM."); +} + +const app = mount(App, { + target: document.getElementById('app')!, +}) +export default app; \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..09016c3 --- /dev/null +++ b/style.css @@ -0,0 +1,143 @@ +:root { + color: CanvasText; + background-color: Canvas; +} + +button { + background-color: ButtonFace; + color: ButtonText; + border-color: ButtonBorder; +} +button:hover { + border-color: AccentColor; +} +button:focus { + outline: 4px auto Highlight; +} + +.anchor { + background-color: AccentColor; + color: AccentColorText; + visibility: hidden; + transition: visibility 0.2s ease-in-out; +} + +@media (prefers-color-scheme: dark) { + :root { + color: CanvasText; + background-color: Canvas; + } +} + + +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + --primary-color: CanvasText; + --hover-color: #747bff; + --background-color: #242424; + --background-light: #ffffff; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: var(--background-color); + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + margin: 0; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: var(--background-color); + color: inherit; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: var(--primary-color); +} +button:focus { + outline: 4px auto -webkit-focus-ring-color; +} + +.svgContainer { + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; +} + +@media (prefers-color-scheme: light) { + :root { + color: var(--background-color); + background-color: var(--background-light); + } + button { + background-color: #f9f9f9; + } + button:hover { + border-color: var(--hover-color); + } +} + +.svgContainer { + border: solid CanvasText 1px; +} + +.icon-hand-tool { + background: url('../resources/icon-hand-tool.svg'); +} + +.icon-lasso-tool { + background: url('../resources/icon-lasso-tool.svg'); +} + +.icon-hand-tool:hover { + background: url('../resources/hovered/icon-hand-tool.svg'); +} + +.icon-lasso-tool:hover { + background: url('../resources/hovered/icon-lasso-tool.svg'); +} + +.pad-icon-remove { + background: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%221.5%22%20width%3D%2246%22%20height%3D%2246%22%3E%3Cline%20x1%3D%225%22%20y1%3D%225%22%20x2%3D%2215%22%20y2%3D%2215%22%2F%3E%3Cline%20x1%3D%2215%22%20y1%3D%225%22%20x2%3D%225%22%20y2%3D%2215%22%2F%3E%3C%2Fsvg%3E') !important; +} + +.pad-icon-connect { + background: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%221.5%22%20width%3D%2246%22%20height%3D%2246%22%3E%3Cline%20x1%3D%2215%22%20y1%3D%225%22%20x2%3D%225%22%20y2%3D%2215%22%2F%3E%3C%2Fsvg%3E') !important; +} + +.icon-create-shape { + background: url('../resources/icon-create-rect.svg'); +} + +.icon-create-shape:hover { + background: url('../resources/hovered/icon-create-rect.svg'); +} + +.icon-connect { + background: url('../resources/icon-connect.svg'); +} + +.icon-connect:hover { + background: url('../resources/hovered/icon-connect.svg'); +} \ No newline at end of file diff --git a/vite-env.d.ts b/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/vite-env.d.ts @@ -0,0 +1 @@ +///