/*! * Copyright (c) 2023, 2025, Oracle and/or its affiliates. */ /** * @file * * Contains a link tool that should serve as a placeholder for a potential * element. */ const { dia, V } = joint; const COLOR_STROKE = "var(--a-diagram-link-placeholder-border-color, none)"; const COLOR_FILL = "var(--a-diagram-link-placeholder-background-color, #666)"; const COLOR_GLYPH = "var(--a-diagram-link-placeholder-text-color, #fff)"; export default class Placeholder extends dia.ToolView { preinitialize() { super.preinitialize( ...arguments ); this.name = "placeholder"; this.events = { mouseenter: "onMouseEnter", mouseleave: "onMouseLeave", mousedown: "onPointerDown", mouseup: "onPointerUp" }; this.radius = 15; this.tagName = "g"; this.children = [{ tagName: "circle", selector: "button", attributes: { r: this.radius, cx: 0, fill: COLOR_FILL, stroke: COLOR_STROKE, cursor: "pointer", "user-select": "none", } }, { tagName: "text", selector: "label", textContent: "\ue069", attributes: { "font-family": "apex-core-font", "font-size": 20, "dominant-baseline": "central", "text-anchor": "middle", "pointer-events": "none", fill: COLOR_GLYPH, stroke: "none", x: 0, style: "user-select: none" } }]; this.options = { scale: null, disabled: false }; } constructor( opt ) { super(); Object.assign( this.options, opt ); } onRender() { this.renderChildren(); this.update(); } update() { const { ratio, translate } = this; const view = this.relatedView; const tangent = view.getTangentAtRatio( ratio ); const { scale } = this.options; let position; if ( tangent ) { position = tangent.start; if ( translate ) { const dX = tangent.end.x - tangent.start.x; const dY = tangent.end.y - tangent.start.y; const hypo = Math.sqrt( Math.pow( dX, 2 ) + Math.pow( dY, 2 ) ); const sinA = dY / hypo; const cosA = dX / hypo; const dY2 = sinA * this.radius * ( scale || 1 ); const dX2 = cosA * this.radius * ( scale || 1 ); position.x += dX2 * translate; position.y += dY2 * translate; } } else { position = view.getPointAtRatio( ratio ); } let matrix = V.createSVGMatrix().translate( position.x, position.y ); if ( scale ) { matrix = matrix.scale( scale ); } this.vel.transform( matrix, { absolute: true } ); return this; } setColors( { stroke, fill, glyph, reset = false } = {} ) { const { button, label } = this.childNodes; if ( reset ) { this.resetColors(); } else { if ( stroke ) { button.setAttribute( "stroke", stroke ); } if ( fill ) { button.setAttribute( "fill", fill ); } if ( glyph ) { label.setAttribute( "fill", glyph ); } } } resetColors() { this.setColors( { stroke: COLOR_STROKE, fill: COLOR_FILL, glyph: COLOR_GLYPH } ); } getLinkPoint() { return this.relatedView.getPointAtRatio( this.ratio ); } onMouseEnter( e ) { this.relatedView.notify( "link:placeholder:mouseenter", this, this.ratio, this.getLinkPoint(), e ); } onMouseLeave( e ) { this.relatedView.notify( "link:placeholder:mouseleave", this, this.ratio, this.getLinkPoint(), e ); } onPointerDown( e ) { if ( this.guard( e ) ) { return; } this.relatedView.notify( "link:placeholder:pointerdown", this, this.ratio, this.getLinkPoint(), e ); } onPointerUp( e ) { if ( this.guard( e ) ) { return; } this.relatedView.notify( "link:placeholder:pointerup", this, this.ratio, this.getLinkPoint(), e ); } enable() { this.options.disabled = false; this.el.classList.remove( "disabled" ); } disable() { this.options.disabled = true; this.el.classList.add( "disabled" ); } }