Mergin better performance branch

This commit is contained in:
barsdeveloper
2022-09-04 14:33:22 +02:00
parent 47c15fbf8d
commit 715dee6a5a
97 changed files with 2725 additions and 2833 deletions

View File

@@ -1,4 +1,4 @@
// @ts-check
import { LitElement } from "lit"
/**
* @typedef {import("../Blueprint").default} Blueprint
@@ -11,15 +11,20 @@
* @template {IEntity} T
* @template {ITemplate} U
*/
export default class IElement extends HTMLElement {
export default class IElement extends LitElement {
static properties = {
}
#nextUpdatedCallbacks = []
/** @type {Blueprint} */
#blueprint
get blueprint() {
return this.#blueprint
}
set blueprint(blueprint) {
this.#blueprint = blueprint
set blueprint(v) {
return this.#blueprint = v
}
/** @type {T} */
@@ -36,9 +41,6 @@ export default class IElement extends HTMLElement {
get template() {
return this.#template
}
set template(template) {
this.#template = template
}
/** @type {IInput[]} */
inputObjects = []
@@ -52,40 +54,79 @@ export default class IElement extends HTMLElement {
this.#entity = entity
this.#template = template
this.inputObjects = []
this.#template.constructed(this)
}
getTemplate() {
return this.template
createRenderRoot() {
return this
}
connectedCallback() {
this.#blueprint = this.closest("ueb-blueprint")
this.template.setup(this)
super.connectedCallback()
this.blueprint = this.closest("ueb-blueprint")
this.template.connectedCallback(this)
}
/**
* @param {Map} changedProperties
*/
willUpdate(changedProperties) {
super.willUpdate(changedProperties)
this.template.willUpdate(this, changedProperties)
}
/**
* @param {Map} changedProperties
*/
update(changedProperties) {
super.update(changedProperties)
this.template.update(this, changedProperties)
}
render() {
return this.template.render(this)
}
/**
* @param {Map} changedProperties
*/
firstUpdated(changedProperties) {
super.firstUpdated(changedProperties)
this.template.firstUpdated(this, changedProperties)
this.template.inputSetup(this)
}
updated(changedProperties) {
super.updated(changedProperties)
this.template.updated(this, changedProperties)
this.#nextUpdatedCallbacks.forEach(f => f(changedProperties))
this.#nextUpdatedCallbacks = []
}
disconnectedCallback() {
super.disconnectedCallback()
this.template.cleanup(this)
}
addNextUpdatedCallbacks(callback, requestUpdate = false) {
this.#nextUpdatedCallbacks.push(callback)
if (requestUpdate) {
this.requestUpdate()
}
}
/**
* @param {IElement} element
*/
isSameGraph(element) {
return this.#blueprint && this.#blueprint == element?.blueprint
return this.blueprint && this.blueprint == element?.blueprint
}
/**
* @template {IInput} V
* @param {new (...args: any[]) => V} type
* @returns {V}
*/
getInputObject(type) {
return /** @type {V} */ (this.template.inputObjects.find(object => object.constructor == type))
}
// Subclasses will want to override
createInputObjects() {
return []
}
}

View File

@@ -0,0 +1,68 @@
import IElement from "./IElement";
/**
* @typedef {import("../entity/IEntity").default} IEntity
* @typedef {import("../template/ITemplate").default} ITemplate
*/
/**
* @template {IEntity} T
* @template {ITemplate} U
* @extends {IElement<T, U>}
*/
export default class IFromToPositionedElement extends IElement {
static properties = {
...super.properties,
initialPositionX: {
type: Number,
attribute: false,
},
initialPositionY: {
type: Number,
attribute: false,
},
finaPositionX: {
type: Number,
attribute: false,
},
finaPositionY: {
type: Number,
attribute: false,
},
}
constructor(...args) {
super(...args)
this.initialPositionX = 0
this.initialPositionY = 0
this.finaPositionX = 0
this.finaPositionY = 0
}
/**
* @param {Number[]} param0
*/
setBothLocations([x, y]) {
this.initialPositionX = x
this.initialPositionY = y
this.finaPositionX = x
this.finaPositionY = y
}
/**
* @param {Number[]} offset
*/
addSourceLocation([offsetX, offsetY]) {
this.initialPositionX += offsetX
this.initialPositionY += offsetY
}
/**
* @param {Number[]} offset
*/
addDestinationLocation([offsetX, offsetY]) {
this.finaPositionX += offsetX
this.finaPositionY += offsetY
}
}

View File

@@ -1,5 +1,3 @@
// @ts-check
import Configuration from "../Configuration"
import IElement from "./IElement"
import Utility from "../Utility"
@@ -16,45 +14,57 @@ import Utility from "../Utility"
*/
export default class ISelectableDraggableElement extends IElement {
static properties = {
...super.properties,
selected: {
type: Boolean,
attribute: "data-selected",
reflect: true,
converter: Utility.booleanConverter,
},
locationX: {
type: Number,
attribute: false,
},
locationY: {
type: Number,
attribute: false,
},
}
constructor(...args) {
// @ts-expect-error
super(...args)
this.dragObject = null
this.location = [0, 0]
this.selected = false
this.locationX = 0
this.locationY = 0
this.listeningDrag = false
let self = this
this.dragHandler = e => self.addLocation(e.detail.value)
}
#setSelected(value = true) {
this.selected = value
if (this.blueprint) {
if (this.selected) {
this.blueprint.addEventListener(Configuration.nodeDragEventName, this.dragHandler)
} else {
this.blueprint.removeEventListener(Configuration.nodeDragEventName, this.dragHandler)
}
}
this.template.applySelected(this)
}
connectedCallback() {
super.connectedCallback()
this.#setSelected(this.selected)
this.setSelected(this.selected)
}
disconnectedCallback() {
super.disconnectedCallback()
this.blueprint.removeEventListener(Configuration.nodeDragEventName, this.dragHandler)
}
/**
* @param {Number[]} value
* @param {Number[]} param0
*/
setLocation(value = [0, 0]) {
const d = [value[0] - this.location[0], value[1] - this.location[1]]
this.location = value
this.template.applyLocation(this)
setLocation([x, y]) {
const d = [x - this.locationX, y - this.locationY]
this.locationX = x
this.locationY = y
if (this.blueprint) {
const dragLocalEvent = new CustomEvent(Configuration.nodeDragLocalEventName, {
detail: {
value: d
value: d,
},
bubbles: false,
cancelable: true
@@ -63,16 +73,29 @@ export default class ISelectableDraggableElement extends IElement {
}
}
addLocation(value) {
this.setLocation([this.location[0] + value[0], this.location[1] + value[1]])
/**
* @param {Number[]} param0
*/
addLocation([x, y]) {
this.setLocation([this.locationX + x, this.locationY + y])
}
setSelected(value = true) {
if (this.selected != value) {
this.#setSelected(value)
this.selected = value
if (this.blueprint) {
if (this.selected) {
this.listeningDrag = true
this.blueprint.addEventListener(Configuration.nodeDragEventName, this.dragHandler)
} else {
this.blueprint.removeEventListener(Configuration.nodeDragEventName, this.dragHandler)
this.listeningDrag = false
}
}
}
/**
* @param {Number[]} value
*/
dispatchDragEvent(value) {
const dragEvent = new CustomEvent(Configuration.nodeDragEventName, {
detail: {
@@ -85,8 +108,8 @@ export default class ISelectableDraggableElement extends IElement {
}
snapToGrid() {
let snappedLocation = Utility.snapToGrid(this.location, Configuration.gridSize)
if (this.location[0] != snappedLocation[0] || this.location[1] != snappedLocation[1]) {
const snappedLocation = Utility.snapToGrid([this.locationX, this.locationY], Configuration.gridSize)
if (this.locationX != snappedLocation[0] || this.locationY != snappedLocation[1]) {
this.setLocation(snappedLocation)
}
}

View File

@@ -1,204 +1,258 @@
// @ts-check
import Configuration from "../Configuration"
import IElement from "./IElement"
import IFromToPositionedElement from "./IFromToPositionedElement"
import LinkTemplate from "../template/LinkTemplate"
import Utility from "../Utility"
/**
* @typedef {import("./PinElement").default} PinElement
* @typedef {import("./LinkMessageElement").default} LinkMessageElement
* @typedef {import("../entity/IEntity").default} IEntity
*/
/**
* @extends {IElement<Object, LinkTemplate>}
* @extends {IFromToPositionedElement<Object, LinkTemplate>}
*/
export default class LinkElement extends IElement {
export default class LinkElement extends IFromToPositionedElement {
static properties = {
...super.properties,
source: {
type: String,
reflect: true,
},
destination: {
type: String,
reflect: true,
},
dragging: {
type: Boolean,
attribute: "data-dragging",
converter: Utility.booleanConverter,
reflect: true,
},
originatesFromInput: {
type: Boolean,
attribute: false,
},
svgPathD: {
type: String,
attribute: false,
},
linkMessageIcon: {
type: String,
attribute: false,
},
linkMessageText: {
type: String,
attribute: false,
},
}
/** @type {PinElement} */
#source
#sourcePin
get sourcePin() {
return this.#source
return this.#sourcePin
}
set sourcePin(pin) {
if (this.#source == pin) {
return
}
if (this.#source) {
const nodeElement = this.#source.getNodeElement()
nodeElement.removeEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler)
nodeElement.removeEventListener(Configuration.nodeDragLocalEventName, this.#nodeDragSourceHandler)
if (this.#destination) {
this.#unlinkPins()
}
}
this.#source = pin
if (this.#source) {
const nodeElement = this.#source.getNodeElement()
this.originatesFromInput = pin.isInput()
nodeElement.addEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler)
nodeElement.addEventListener(Configuration.nodeDragLocalEventName, this.#nodeDragSourceHandler)
this.setSourceLocation()
if (this.#destination) {
this.#linkPins()
}
}
this.template.applyPins(this)
this.#setPin(pin, false)
}
/** @type {PinElement} */
#destination
#destinationPin
get destinationPin() {
return this.#destination
return this.#destinationPin
}
set destinationPin(pin) {
if (this.#destination == pin) {
return
}
if (this.#destination) {
const nodeElement = this.#destination.getNodeElement()
nodeElement.removeEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler)
nodeElement.removeEventListener(Configuration.nodeDragLocalEventName, this.#nodeDragDestinatonHandler)
if (this.#source) {
this.#unlinkPins()
}
}
this.#destination = pin
if (this.#destination) {
const nodeElement = this.#destination.getNodeElement()
nodeElement.addEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler)
nodeElement.addEventListener(Configuration.nodeDragLocalEventName, this.#nodeDragDestinatonHandler)
this.setDestinationLocation()
if (this.#source) {
this.#linkPins()
}
}
this.template.applyPins(this)
this.#setPin(pin, true)
}
#nodeDeleteHandler
#nodeDragSourceHandler
#nodeDragDestinatonHandler
sourceLocation = [0, 0]
#nodeReflowSourceHandler
#nodeReflowDestinatonHandler
/** @type {SVGPathElement} */
pathElement
/** @type {LinkMessageElement} */
linkMessageElement
originatesFromInput = false
destinationLocation = [0, 0]
/**
* @param {PinElement} source
* @param {PinElement} destination
* @param {PinElement?} destination
*/
constructor(source, destination) {
super({}, new LinkTemplate())
const self = this
this.#nodeDeleteHandler = _ => self.remove()
this.#nodeDeleteHandler = () => self.remove()
this.#nodeDragSourceHandler = e => self.addSourceLocation(e.detail.value)
this.#nodeDragDestinatonHandler = e => self.addDestinationLocation(e.detail.value)
this.#nodeReflowSourceHandler = e => self.setSourceLocation()
this.#nodeReflowDestinatonHandler = e => self.setDestinationLocation()
this.source = null
this.destination = null
this.dragging = false
this.originatesFromInput = false
this.startPercentage = 0
this.svgPathD = ""
this.startPixels = 0
this.linkMessageIcon = ""
this.linkMessageText = ""
if (source) {
this.sourcePin = source
if (!destination) {
this.finaPositionX = this.initialPositionX
this.finaPositionY = this.initialPositionY
}
}
if (destination) {
this.destinationPin = destination
if (!source) {
this.initialPositionX = this.finaPositionX
this.initialPositionY = this.finaPositionY
}
}
if (source && destination) {
this.#linkPins()
}
/**
* @param {PinElement} pin
* @param {Boolean} isDestinationPin
*/
#setPin(pin, isDestinationPin) {
const getCurrentPin = () => isDestinationPin ? this.destinationPin : this.sourcePin
if (getCurrentPin() == pin) {
return
}
if (getCurrentPin()) {
const nodeElement = getCurrentPin().getNodeElement()
nodeElement.removeEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler)
nodeElement.removeEventListener(
Configuration.nodeDragLocalEventName,
isDestinationPin ? this.#nodeDragDestinatonHandler : this.#nodeDragSourceHandler
)
nodeElement.removeEventListener(
Configuration.nodeReflowEventName,
isDestinationPin ? this.#nodeReflowDestinatonHandler : this.#nodeReflowSourceHandler
)
this.#unlinkPins()
}
isDestinationPin
? this.#destinationPin = pin
: this.#sourcePin = pin
if (getCurrentPin()) {
const nodeElement = getCurrentPin().getNodeElement()
nodeElement.addEventListener(Configuration.nodeDeleteEventName, this.#nodeDeleteHandler)
nodeElement.addEventListener(
Configuration.nodeDragLocalEventName,
isDestinationPin ? this.#nodeDragDestinatonHandler : this.#nodeDragSourceHandler
)
nodeElement.addEventListener(
Configuration.nodeReflowEventName,
isDestinationPin ? this.#nodeReflowDestinatonHandler : this.#nodeReflowSourceHandler
)
isDestinationPin
? this.setDestinationLocation()
: (this.setSourceLocation(), this.originatesFromInput = this.sourcePin.isInput())
this.#linkPins()
}
}
#linkPins() {
this.#source.linkTo(this.#destination)
this.#destination.linkTo(this.#source)
if (this.sourcePin && this.destinationPin) {
this.sourcePin.linkTo(this.destinationPin)
this.destinationPin.linkTo(this.sourcePin)
}
}
#unlinkPins() {
if (this.#source && this.#destination) {
this.#source.unlinkFrom(this.#destination)
this.#destination.unlinkFrom(this.#source)
if (this.sourcePin && this.destinationPin) {
this.sourcePin.unlinkFrom(this.destinationPin)
this.destinationPin.unlinkFrom(this.sourcePin)
}
}
disconnectedCallback() {
super.disconnectedCallback()
this.#unlinkPins()
this.sourcePin = null
this.destinationPin = null
}
/**
* @returns {Number[]}
*/
getSourceLocation() {
return this.sourceLocation
}
/**
* @param {Number[]} offset
*/
addSourceLocation(offset) {
const location = [
this.sourceLocation[0] + offset[0],
this.sourceLocation[1] + offset[1]
]
this.sourceLocation = location
this.template.applyFullLocation(this)
}
/**
* @param {Number[]} location
* @param {Number[]?} location
*/
setSourceLocation(location = null) {
if (location == null) {
location = this.#source.template.getLinkLocation(this.#source)
const self = this
if (!this.hasUpdated || !this.sourcePin.hasUpdated) {
Promise.all([this.updateComplete, this.sourcePin.updateComplete]).then(() => self.setSourceLocation())
return
}
location = this.sourcePin.template.getLinkLocation(this.sourcePin)
}
this.sourceLocation = location
this.template.applySourceLocation(this)
}
getDestinationLocation() {
return this.destinationLocation
const [x, y] = location
this.initialPositionX = x
this.initialPositionY = y
}
/**
* @param {Number[]} offset
*/
addDestinationLocation(offset) {
const location = [
this.destinationLocation[0] + offset[0],
this.destinationLocation[1] + offset[1]
]
this.setDestinationLocation(location)
}
/**
* @param {Number[]} location
* @param {Number[]?} location
*/
setDestinationLocation(location = null) {
if (location == null) {
location = this.#destination.template.getLinkLocation(this.#destination)
}
this.destinationLocation = location
this.template.applyFullLocation(this)
}
/**
* @param {LinkMessageElement} linkMessage
*/
setLinkMessage(linkMessage) {
if (linkMessage) {
this.template.applyLinkMessage(this, linkMessage)
} else if (this.linkMessageElement) {
this.linkMessageElement.remove()
this.linkMessageElement = null
const self = this
if (!this.hasUpdated || !this.destinationPin.hasUpdated) {
Promise.all([this.updateComplete, this.destinationPin.updateComplete]).then(() => self.setDestinationLocation())
return
}
location = this.destinationPin.template.getLinkLocation(this.destinationPin)
}
this.finaPositionX = location[0]
this.finaPositionY = location[1]
}
startDragging() {
this.template.applyStartDragging(this)
this.dragging = true
}
finishDragging() {
this.template.applyFinishDragging(this)
this.dragging = false
}
removeMessage() {
this.linkMessageIcon = ""
this.linkMessageText = ""
}
setMessageConvertType() {
this.linkMessageIcon = "ueb-icon-conver-type"
this.linkMessageText = `Convert ${this.sourcePin.pinType} to ${this.destinationPin.pinType}.`
}
setMessageCorrect() {
this.linkMessageIcon = "ueb-icon-correct"
this.linkMessageText = ""
}
setMessageDirectionsIncompatible() {
this.linkMessageIcon = "ueb-icon-directions-incompatible"
this.linkMessageText = "Directions are not compatbile."
}
setMessagePlaceNode() {
this.linkMessageIcon = "ueb-icon-place-node"
this.linkMessageText = "Place a new node."
}
setMessageReplaceLink() {
this.linkMessageIcon = "ueb-icon-replace-link"
this.linkMessageText = "Replace existing input connections."
}
setMessageSameNode() {
this.linkMessageIcon = "ueb-icon-same-node"
this.linkMessageText = "Both are on the same node."
}
setMEssagetypesIncompatible() {
this.linkMessageIcon = "ueb-icon-types-incompatible"
this.linkMessageText = `${this.sourcePin.pinType} is not compatible with ${this.destinationPin.pinType}.`
}
}

View File

@@ -1,68 +0,0 @@
// @ts-check
import IElement from "./IElement"
import LinkMessageTemplate from "../template/LinkMessageTemplate"
/**
* @typedef {import("./PinElement").default} PinElement
* @typedef {import("./LinkElement").default} LinkElement
* @typedef {(sourcePin: PinElement, destinationPin: PinElement) => String} LinkRetrieval
*/
/**
* @extends {IElement<Object, LinkMessageTemplate>}
*/
export default class LinkMessageElement extends IElement {
static convertType = _ => new LinkMessageElement(
"ueb-icon-conver-type",
/** @type {LinkRetrieval} */
(s, d) => `Convert ${s.getType()} to ${d.getType()}.`
)
static correct = _ => new LinkMessageElement(
"ueb-icon-correct",
/** @type {LinkRetrieval} */
(s, d) => ""
)
static directionsIncompatible = _ => new LinkMessageElement(
"ueb-icon-directions-incompatible",
/** @type {LinkRetrieval} */
(s, d) => "Directions are not compatbile."
)
static placeNode = _ => new LinkMessageElement(
"ueb-icon-place-node",
/** @type {LinkRetrieval} */
(s, d) => "Place a new node."
)
static replaceLink = _ => new LinkMessageElement(
"ueb-icon-replace-link",
/** @type {LinkRetrieval} */
(s, d) => "Replace existing input connections."
)
static sameNode = _ => new LinkMessageElement(
"ueb-icon-same-node",
/** @type {LinkRetrieval} */
(s, d) => "Both are on the same node."
)
static typesIncompatible = _ => new LinkMessageElement(
"ueb-icon-types-incompatible",
/** @type {LinkRetrieval} */
(s, d) => `${s.getType()} is not compatible with ${d.getType()}.`
)
/** @type {String} */
icon
/** @type {LinkRetrieval} */
message
/** @type {LinkElement} */
linkElement
constructor(icon, message) {
super({}, new LinkMessageTemplate())
this.icon = icon
this.message = message
}
}
customElements.define("ueb-link-message", LinkMessageElement)

View File

@@ -1,10 +1,9 @@
// @ts-check
import Configuration from "../Configuration"
import IdentifierEntity from "../entity/IdentifierEntity"
import ISelectableDraggableElement from "./ISelectableDraggableElement"
import NodeTemplate from "../template/NodeTemplate"
import ObjectEntity from "../entity/ObjectEntity"
import PinElement from "./PinElement"
import PinEntity from "../entity/PinEntity"
import PinReferenceEntity from "../entity/PinReferenceEntity"
import SerializerFactory from "../serialization/SerializerFactory"
@@ -14,13 +13,64 @@ import SerializerFactory from "../serialization/SerializerFactory"
*/
export default class NodeElement extends ISelectableDraggableElement {
static properties = {
...ISelectableDraggableElement.properties,
name: {
type: String,
attribute: "data-name",
reflect: true,
},
advancedPinDisplay: {
type: String,
attribute: "data-advanced-display",
converter: IdentifierEntity.attributeConverter,
reflect: true,
},
enabledState: {
type: String,
attribute: "data-enabled-state",
reflect: true,
},
nodeDisplayName: {
type: String,
attribute: false,
},
}
get blueprint() {
return super.blueprint
}
set blueprint(v) {
super.blueprint = v
this.#pins.forEach(p => p.blueprint = v)
}
/** @type {HTMLElement} */
#nodeNameElement
get nodeNameElement() {
return this.#nodeNameElement
}
set nodeNameElement(value) {
this.#nodeNameElement = value
}
#pins
/**
* @param {ObjectEntity} entity
*/
constructor(entity) {
super(entity, new NodeTemplate())
this.#pins = this.getPinEntities().filter(v => !v.isHidden()).map(v => new PinElement(v))
this.#pins.forEach(pin => pin.nodeElement = this)
this.name = entity.getObjectName()
this.advancedPinDisplay = entity.AdvancedPinDisplay?.toString()
this.enabledState = entity.EnabledState
this.nodeDisplayName = entity.getDisplayName()
this.dragLinkObjects = []
super.setLocation([this.entity.NodePosX.value, this.entity.NodePosY.value])
this.entity.subscribe("AdvancedPinDisplay", value => this.advancedPinDisplay = value)
this.entity.subscribe("Name", value => this.name = value)
}
/**
@@ -70,11 +120,10 @@ export default class NodeElement extends ISelectableDraggableElement {
}
}
this.entity.Name = name
this.template.applyRename(this)
}
getPinElements() {
return this.template.getPinElements(this)
return this.#pins
}
/**
@@ -86,9 +135,7 @@ export default class NodeElement extends ISelectableDraggableElement {
setLocation(value = [0, 0]) {
let nodeType = this.entity.NodePosX.constructor
// @ts-expect-error
this.entity.NodePosX = new nodeType(value[0])
// @ts-expect-error
this.entity.NodePosY = new nodeType(value[1])
super.setLocation(value)
}
@@ -101,13 +148,20 @@ export default class NodeElement extends ISelectableDraggableElement {
this.dispatchEvent(deleteEvent)
}
dispatchReflowEvent() {
let reflowEvent = new CustomEvent(Configuration.nodeReflowEventName, {
bubbles: true,
cancelable: true
})
this.dispatchEvent(reflowEvent)
}
setShowAdvancedPinDisplay(value) {
this.entity.AdvancedPinDisplay = new IdentifierEntity(value ? "Shown" : "Hidden")
this.template.applyAdvancedPinDisplay(this)
}
toggleShowAdvancedPinDisplay() {
this.setShowAdvancedPinDisplay(this.entity.AdvancedPinDisplay.value != "Shown")
this.setShowAdvancedPinDisplay(this.entity.AdvancedPinDisplay?.toString() != "Shown")
}
}

View File

@@ -1,8 +1,9 @@
// @ts-check
import BoolPinTemplate from "../template/BoolPinTemplate"
import Configuration from "../Configuration"
import ExecPinTemplate from "../template/ExecPinTemplate"
import IElement from "./IElement"
import ISerializer from "../serialization/ISerializer"
import LinearColorEntity from "../entity/LinearColorEntity"
import LinearColorPinTemplate from "../template/LinearColorPinTemplate"
import LinkElement from "./LinkElement"
import NamePinTemplate from "../template/NamePinTemplate"
@@ -34,6 +35,46 @@ export default class PinElement extends IElement {
}
}
static properties = {
advancedView: {
type: String,
attribute: "data-advanced-view",
reflect: true,
},
color: {
type: LinearColorEntity,
converter: {
fromAttribute: (value, type) => {
return ISerializer.grammar.LinearColorFromAnyColor.parse(value).value
},
toAttribute: (value, type) => {
return Utility.printLinearColor(value)
},
},
reflect: true,
},
defaultValue: {
type: String,
attribute: false,
},
isLinked: {
type: Boolean,
converter: Utility.booleanConverter,
attribute: "data-linked",
reflect: true,
},
pinType: {
type: String,
attribute: "data-type",
reflect: true,
},
pinDirection: {
type: String,
attribute: "data-direction",
reflect: true,
},
}
/**
* @param {PinEntity} pinEntity
* @return {PinTemplate}
@@ -46,8 +87,6 @@ export default class PinElement extends IElement {
return result ?? PinTemplate
}
#color = ""
/** @type {NodeElement} */
nodeElement
@@ -56,20 +95,42 @@ export default class PinElement extends IElement {
connections = 0
get defaultValue() {
return this.unreactiveDefaultValue
}
set defaultValue(value) {
let oldValue = this.unreactiveDefaultValue
this.unreactiveDefaultValue = value
this.requestUpdate("defaultValue", oldValue)
}
/**
* @param {PinEntity} entity
*/
constructor(entity) {
super(
entity,
// @ts-expect-error
new (PinElement.getTypeTemplate(entity))()
)
this.advancedView = entity.bAdvancedView
this.unreactiveDefaultValue = entity.getDefaultValue()
this.pinType = this.entity.getType()
this.color = this.constructor.properties.color.converter.fromAttribute(Configuration.pinColor[this.pinType].toString())
this.isLinked = false
this.pinDirection = entity.isInput() ? "input" : entity.isOutput() ? "output" : "hidden"
this.entity.subscribe("DefaultValue", value => this.defaultValue = value.toString())
this.entity.subscribe("PinToolTip", value => {
let matchResult = value.match(/\s*(.+?(?=\n)|.+\S)\s*/)
if (matchResult) {
return Utility.formatStringName(matchResult[1])
}
return Utility.formatStringName(this.entity.PinName)
})
}
connectedCallback() {
super.connectedCallback()
this.#color = window.getComputedStyle(this).getPropertyValue("--ueb-pin-color")
}
/** @return {GuidEntity} */
@@ -89,9 +150,6 @@ export default class PinElement extends IElement {
return this.entity.PinName
}
/**
* @returns {String}
*/
getPinDisplayName() {
let matchResult = null
if (
@@ -112,22 +170,10 @@ export default class PinElement extends IElement {
return this.entity.isOutput()
}
isLinked() {
return this.entity.isLinked()
}
getType() {
return this.entity.getType()
}
getClickableElement() {
return this.clickableElement
}
getColor() {
return this.#color
}
getLinkLocation() {
return this.template.getLinkLocation(this)
}
@@ -136,13 +182,17 @@ export default class PinElement extends IElement {
* @returns {NodeElement}
*/
getNodeElement() {
return this.closest("ueb-node")
return this.nodeElement
}
getLinks() {
return this.entity.LinkedTo ?? []
}
setDefaultValue(value) {
this.entity.DefaultValue = value
}
sanitizeLinks() {
this.entity.LinkedTo = this.getLinks().filter(pinReference => {
let pin = this.blueprint.getPin(pinReference)
@@ -160,16 +210,16 @@ export default class PinElement extends IElement {
* @param {PinElement} targetPinElement
*/
linkTo(targetPinElement) {
this.entity.linkTo(targetPinElement.nodeElement.getNodeName(), targetPinElement.entity)
this.template.applyConnected(this)
this.entity.linkTo(targetPinElement.getNodeElement().getNodeName(), targetPinElement.entity)
this.isLinked = this.entity.isLinked()
}
/**
* @param {PinElement} targetPinElement
*/
unlinkFrom(targetPinElement) {
this.entity.unlinkFrom(targetPinElement.nodeElement.getNodeName(), targetPinElement.entity)
this.template.applyConnected(this)
this.entity.unlinkFrom(targetPinElement.getNodeElement().getNodeName(), targetPinElement.entity)
this.isLinked = this.entity.isLinked()
}
/**
@@ -178,8 +228,8 @@ export default class PinElement extends IElement {
*/
redirectLink(originalPinElement, newReference) {
const index = this.entity.LinkedTo.findIndex(pinReference =>
pinReference.objectName.toString() == originalPinElement.getPinName()
&& pinReference.pinGuid == originalPinElement.entity.PinId
pinReference.objectName.toString() == originalPinElement.getNodeElement().getNodeName()
&& pinReference.pinGuid.valueOf() == originalPinElement.entity.PinId.valueOf()
)
if (index >= 0) {
this.entity.LinkedTo[index] = newReference

View File

@@ -1,38 +1,47 @@
// @ts-check
import FastSelectionModel from "../selection/FastSelectionModel"
import IElement from "./IElement"
import IFromToPositionedElement from "./IFromToPositionedElement"
import SelectorTemplate from "../template/SelectorTemplate"
/**
* @extends {IElement<Object, SelectorTemplate>}
* @extends {IFromToPositionedElement<Object, SelectorTemplate>}
*/
export default class SelectorElement extends IElement {
export default class SelectorElement extends IFromToPositionedElement {
constructor() {
super({}, new SelectorTemplate())
this.selectionModel = null
}
/**
* @param {Number[]} initialPosition
*/
startSelecting(initialPosition) {
this.template.applyStartSelecting(this, initialPosition)
this.selectionModel = new FastSelectionModel(initialPosition, this.blueprint.getNodes(), this.blueprint.nodeBoundariesSupplier, this.blueprint.nodeSelectToggleFunction)
beginSelect(initialPosition) {
this.blueprint.selecting = true
this.setBothLocations(initialPosition)
this.selectionModel = new FastSelectionModel(
initialPosition,
this.blueprint.getNodes(),
this.blueprint.nodeBoundariesSupplier,
this.blueprint.nodeSelectToggleFunction
)
}
/**
* @param {Number[]} finalPosition
*/
doSelecting(finalPosition) {
this.template.applyDoSelecting(this, finalPosition)
this.selectionModel.selectTo(finalPosition)
selectTo(finalPosition) {
/** @type {FastSelectionModel} */ (this.selectionModel)
.selectTo(finalPosition)
this.finaPositionX = finalPosition[0]
this.finaPositionY = finalPosition[1]
}
finishSelecting() {
this.template.applyFinishSelecting(this)
endSelect() {
this.blueprint.selecting = false
this.selectionModel = null
this.initialPositionX = 0
this.initialPositionY = 0
this.finaPositionX = 0
this.finaPositionY = 0
}
}