From 705ef21b7b6249b98a6b839da550a95a6bca96ec Mon Sep 17 00:00:00 2001 From: sbosse Date: Mon, 21 Jul 2025 23:41:19 +0200 Subject: [PATCH] Mon 21 Jul 22:43:21 CEST 2025 --- .../mxgraph/src/js/handler/mxCellHighlight.js | 303 ++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 js/ui/mxgraph/src/js/handler/mxCellHighlight.js diff --git a/js/ui/mxgraph/src/js/handler/mxCellHighlight.js b/js/ui/mxgraph/src/js/handler/mxCellHighlight.js new file mode 100644 index 0000000..3f49a66 --- /dev/null +++ b/js/ui/mxgraph/src/js/handler/mxCellHighlight.js @@ -0,0 +1,303 @@ +/** + * Copyright (c) 2006-2015, JGraph Ltd + * Copyright (c) 2006-2015, Gaudenz Alder + */ +/** + * Class: mxCellHighlight + * + * A helper class to highlight cells. Here is an example for a given cell. + * + * (code) + * var highlight = new mxCellHighlight(graph, '#ff0000', 2); + * highlight.highlight(graph.view.getState(cell))); + * (end) + * + * Constructor: mxCellHighlight + * + * Constructs a cell highlight. + */ +function mxCellHighlight(graph, highlightColor, strokeWidth, dashed) +{ + if (graph != null) + { + this.graph = graph; + this.highlightColor = (highlightColor != null) ? highlightColor : mxConstants.DEFAULT_VALID_COLOR; + this.strokeWidth = (strokeWidth != null) ? strokeWidth : mxConstants.HIGHLIGHT_STROKEWIDTH; + this.dashed = (dashed != null) ? dashed : false; + this.opacity = mxConstants.HIGHLIGHT_OPACITY; + + // Updates the marker if the graph changes + this.repaintHandler = mxUtils.bind(this, function() + { + // Updates reference to state + if (this.state != null) + { + var tmp = this.graph.view.getState(this.state.cell); + + if (tmp == null) + { + this.hide(); + } + else + { + this.state = tmp; + this.repaint(); + } + } + }); + + this.graph.getView().addListener(mxEvent.SCALE, this.repaintHandler); + this.graph.getView().addListener(mxEvent.TRANSLATE, this.repaintHandler); + this.graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, this.repaintHandler); + this.graph.getModel().addListener(mxEvent.CHANGE, this.repaintHandler); + + // Hides the marker if the current root changes + this.resetHandler = mxUtils.bind(this, function() + { + this.hide(); + }); + + this.graph.getView().addListener(mxEvent.DOWN, this.resetHandler); + this.graph.getView().addListener(mxEvent.UP, this.resetHandler); + } +}; + +/** + * Variable: keepOnTop + * + * Specifies if the highlights should appear on top of everything + * else in the overlay pane. Default is false. + */ +mxCellHighlight.prototype.keepOnTop = false; + +/** + * Variable: graph + * + * Reference to the enclosing . + */ +mxCellHighlight.prototype.graph = true; + +/** + * Variable: state + * + * Reference to the . + */ +mxCellHighlight.prototype.state = null; + +/** + * Variable: spacing + * + * Specifies the spacing between the highlight for vertices and the vertex. + * Default is 2. + */ +mxCellHighlight.prototype.spacing = 2; + +/** + * Variable: resetHandler + * + * Holds the handler that automatically invokes reset if the highlight + * should be hidden. + */ +mxCellHighlight.prototype.resetHandler = null; + +/** + * Function: setHighlightColor + * + * Sets the color of the rectangle used to highlight drop targets. + * + * Parameters: + * + * color - String that represents the new highlight color. + */ +mxCellHighlight.prototype.setHighlightColor = function(color) +{ + this.highlightColor = color; + + if (this.shape != null) + { + this.shape.stroke = color; + } +}; + +/** + * Function: drawHighlight + * + * Creates and returns the highlight shape for the given state. + */ +mxCellHighlight.prototype.drawHighlight = function() +{ + this.shape = this.createShape(); + this.repaint(); + + if (!this.keepOnTop && this.shape.node.parentNode.firstChild != this.shape.node) + { + this.shape.node.parentNode.insertBefore(this.shape.node, this.shape.node.parentNode.firstChild); + } +}; + +/** + * Function: createShape + * + * Creates and returns the highlight shape for the given state. + */ +mxCellHighlight.prototype.createShape = function() +{ + var shape = this.graph.cellRenderer.createShape(this.state); + + shape.svgStrokeTolerance = this.graph.tolerance; + shape.scale = this.state.view.scale; + shape.outline = true; + shape.points = this.state.absolutePoints; + shape.apply(this.state); + shape.strokewidth = this.strokeWidth / this.state.view.scale / this.state.view.scale; + shape.arrowStrokewidth = this.strokeWidth; + shape.stroke = this.highlightColor; + shape.opacity = this.opacity; + shape.isDashed = this.dashed; + shape.isShadow = false; + + shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; + shape.init(this.graph.getView().getOverlayPane()); + mxEvent.redirectMouseEvents(shape.node, this.graph, this.state); + + if (this.graph.dialect != mxConstants.DIALECT_SVG) + { + shape.pointerEvents = false; + } + else + { + shape.svgPointerEvents = 'stroke'; + } + + return shape; +}; + + +/** + * Function: repaint + * + * Updates the highlight after a change of the model or view. + */ +mxCellHighlight.prototype.repaint = function() +{ + if (this.state != null && this.shape != null) + { + if (this.graph.model.isEdge(this.state.cell)) + { + this.shape.points = this.state.absolutePoints; + } + else + { + this.shape.bounds = new mxRectangle(this.state.x - this.spacing, this.state.y - this.spacing, + this.state.width + 2 * this.spacing, this.state.height + 2 * this.spacing); + this.shape.rotation = Number(this.state.style[mxConstants.STYLE_ROTATION] || '0'); + } + + // Uses cursor from shape in highlight + if (this.state.shape != null) + { + this.shape.setCursor(this.state.shape.getCursor()); + } + + // Workaround for event transparency in VML with transparent color + // is to use a non-transparent color with near zero opacity + if (mxClient.IS_QUIRKS || document.documentMode == 8) + { + if (this.shape.stroke == 'transparent') + { + // KNOWN: Quirks mode does not seem to catch events if + // we do not force an update of the DOM via a change such + // as mxLog.debug. Since IE6 is EOL we do not add a fix. + this.shape.stroke = 'white'; + this.shape.opacity = 1; + } + else + { + this.shape.opacity = this.opacity; + } + } + + this.shape.redraw(); + } +}; + +/** + * Function: hide + * + * Resets the state of the cell marker. + */ +mxCellHighlight.prototype.hide = function() +{ + this.highlight(null); +}; + +/** + * Function: mark + * + * Marks the and fires a event. + */ +mxCellHighlight.prototype.highlight = function(state) +{ + if (this.state != state) + { + if (this.shape != null) + { + this.shape.destroy(); + this.shape = null; + } + + this.state = state; + + if (this.state != null) + { + this.drawHighlight(); + } + } +}; + +/** + * Function: isHighlightAt + * + * Returns true if this highlight is at the given position. + */ +mxCellHighlight.prototype.isHighlightAt = function(x, y) +{ + var hit = false; + + // Quirks mode is currently not supported as it used a different coordinate system + if (this.shape != null && document.elementFromPoint != null && !mxClient.IS_QUIRKS) + { + var elt = document.elementFromPoint(x, y); + + while (elt != null) + { + if (elt == this.shape.node) + { + hit = true; + break; + } + + elt = elt.parentNode; + } + } + + return hit; +}; + +/** + * Function: destroy + * + * Destroys the handler and all its resources and DOM nodes. + */ +mxCellHighlight.prototype.destroy = function() +{ + this.graph.getView().removeListener(this.resetHandler); + this.graph.getView().removeListener(this.repaintHandler); + this.graph.getModel().removeListener(this.repaintHandler); + + if (this.shape != null) + { + this.shape.destroy(); + this.shape = null; + } +};