diff --git a/packages/core/src/util/ObjectIdentity.ts b/packages/core/src/util/ObjectIdentity.ts index 7c95368db..849c777bc 100644 --- a/packages/core/src/util/ObjectIdentity.ts +++ b/packages/core/src/util/ObjectIdentity.ts @@ -44,17 +44,21 @@ class ObjectIdentity { /** * Returns the ID for the given object or function. */ - static get(obj: IdentityObject | IdentityFunction) { - if (isNullish(obj[FIELD_NAME])) { - if (typeof obj === 'object') { - const ctor = getFunctionName(obj.constructor); - obj[FIELD_NAME] = `${ctor}#${ObjectIdentity.counter++}`; - } else if (typeof obj === 'function') { - obj[FIELD_NAME] = `Function#${ObjectIdentity.counter++}`; + static get(obj: IdentityObject | IdentityFunction | null) { + if (obj) { + if (isNullish(obj[FIELD_NAME])) { + if (typeof obj === 'object') { + const ctor = getFunctionName(obj.constructor); + obj[FIELD_NAME] = `${ctor}#${ObjectIdentity.counter++}`; + } else if (typeof obj === 'function') { + obj[FIELD_NAME] = `Function#${ObjectIdentity.counter++}`; + } } + + return obj[FIELD_NAME] as string; } - return obj[FIELD_NAME] as string; + return null; } /** diff --git a/packages/core/src/util/canvas/SvgCanvas2D.ts b/packages/core/src/util/canvas/SvgCanvas2D.ts index 420197603..2c8b814c0 100644 --- a/packages/core/src/util/canvas/SvgCanvas2D.ts +++ b/packages/core/src/util/canvas/SvgCanvas2D.ts @@ -26,6 +26,7 @@ import { FONT_STRIKETHROUGH, FONT_UNDERLINE, LINE_HEIGHT, + NONE, NS_SVG, NS_XLINK, WORD_WRAP, @@ -666,37 +667,37 @@ class SvgCanvas2D extends AbstractCanvas2D { const { node } = this; const s = this.state; - if (node != null) { + if (node) { if (node.nodeName === 'path') { // Checks if the path is not empty - if (this.path != null && this.path.length > 0) { + if (this.path && this.path.length > 0) { node.setAttribute('d', this.path.join(' ')); } else { return; } } - if (filled && s.fillColor != null) { + if (filled && s.fillColor !== NONE) { this.updateFill(); } else if (!this.styleEnabled) { // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=814952 if (node.nodeName === 'ellipse' && mxClient.IS_FF) { node.setAttribute('fill', 'transparent'); } else { - node.setAttribute('fill', 'none'); + node.setAttribute('fill', NONE); } // Sets the actual filled state for stroke tolerance filled = false; } - if (stroked && s.strokeColor != null) { + if (stroked && s.strokeColor !== NONE) { this.updateStroke(); } else if (!this.styleEnabled) { - node.setAttribute('stroke', 'none'); + node.setAttribute('stroke', NONE); } - if (s.transform != null && s.transform.length > 0) { + if (s.transform && s.transform.length > 0) { node.setAttribute('transform', s.transform); } @@ -714,8 +715,8 @@ class SvgCanvas2D extends AbstractCanvas2D { node.setAttribute('pointer-events', this.pointerEventsValue); } // Enables clicks for nodes inside a link element - else if (!this.pointerEvents && this.originalRoot == null) { - node.setAttribute('pointer-events', 'none'); + else if (!this.pointerEvents && !this.originalRoot) { + node.setAttribute('pointer-events', NONE); } // Removes invisible nodes from output if they don't handle events @@ -723,10 +724,10 @@ class SvgCanvas2D extends AbstractCanvas2D { (node.nodeName !== 'rect' && node.nodeName !== 'path' && node.nodeName !== 'ellipse') || - (node.getAttribute('fill') !== 'none' && + (node.getAttribute('fill') !== NONE && node.getAttribute('fill') !== 'transparent') || - node.getAttribute('stroke') !== 'none' || - node.getAttribute('pointer-events') !== 'none' + node.getAttribute('stroke') !== NONE || + node.getAttribute('pointer-events') !== NONE ) { // LATER: Update existing DOM for performance this.root.appendChild(node); @@ -748,8 +749,8 @@ class SvgCanvas2D extends AbstractCanvas2D { this.node.setAttribute('fill-opacity', String(s.alpha * s.fillAlpha)); } - if (s.fillColor) { - if (s.gradientColor) { + if (s.fillColor !== NONE) { + if (s.gradientColor !== NONE) { const id = this.getSvgGradient( s.fillColor, s.gradientColor, @@ -790,7 +791,8 @@ class SvgCanvas2D extends AbstractCanvas2D { const s = this.state; - if (s.strokeColor) this.node.setAttribute('stroke', s.strokeColor.toLowerCase()); + if (s.strokeColor !== NONE) + this.node.setAttribute('stroke', s.strokeColor.toLowerCase()); if (s.alpha < 1 || s.strokeAlpha < 1) { this.node.setAttribute('stroke-opacity', String(s.alpha * s.strokeAlpha)); @@ -894,10 +896,10 @@ class SvgCanvas2D extends AbstractCanvas2D { shadow.getAttribute('fill') !== 'none' && (!mxClient.IS_FF || shadow.getAttribute('fill') !== 'transparent') ) { - shadow.setAttribute('fill', String(s.shadowColor)); + shadow.setAttribute('fill', s.shadowColor); } - if (shadow.getAttribute('stroke') !== 'none' && s.shadowColor) { + if (shadow.getAttribute('stroke') !== 'none' && s.shadowColor !== NONE) { shadow.setAttribute('stroke', s.shadowColor); } @@ -1725,7 +1727,7 @@ class SvgCanvas2D extends AbstractCanvas2D { updateFont(node: SVGElement) { const s = this.state; - if (s.fontColor) node.setAttribute('fill', s.fontColor); + if (s.fontColor !== NONE) node.setAttribute('fill', s.fontColor); if (!this.styleEnabled || s.fontFamily !== DEFAULT_FONTFAMILY) { node.setAttribute('font-family', s.fontFamily); diff --git a/packages/core/src/view/cell/CellMarker.ts b/packages/core/src/view/cell/CellMarker.ts index fe87ec2fb..1a0aefd7b 100644 --- a/packages/core/src/view/cell/CellMarker.ts +++ b/packages/core/src/view/cell/CellMarker.ts @@ -287,7 +287,7 @@ class CellMarker extends EventSource { if (state !== this.markedState || color !== this.currentColor) { this.currentColor = color; - if (state && this.currentColor) { + if (state && this.currentColor !== NONE) { this.markedState = state; this.mark(); } else if (this.markedState) { diff --git a/packages/core/src/view/cell/CellRenderer.ts b/packages/core/src/view/cell/CellRenderer.ts index 9b3318512..3fc20e33b 100644 --- a/packages/core/src/view/cell/CellRenderer.ts +++ b/packages/core/src/view/cell/CellRenderer.ts @@ -359,7 +359,6 @@ class CellRenderer { if (value === 'inherit') { referenced = state.cell.getParent(); - /* disable swimlane for now } else if (value === 'swimlane') { // @ts-ignore shape[field] = @@ -371,9 +370,8 @@ class CellRenderer { referenced = state.cell; } - referenced = graph.swimlane.getSwimlane(referenced); - key = graph.swimlane.swimlaneIndicatorColorAttribute; - */ + referenced = graph.getSwimlane(referenced); + key = graph.swimlaneIndicatorColorAttribute; } else if (value === 'indicated' && state.shape) { // @ts-ignore shape[field] = state.shape.indicatorColor; @@ -437,7 +435,7 @@ class CellRenderer { state.text = new this.defaultTextShape( value, new Rectangle(), - state.style.align || ALIGN_CENTER, + state.style.align ?? ALIGN_CENTER, state.getVerticalAlign(), state.style.fontColor, state.style.fontFamily, @@ -455,9 +453,9 @@ class CellRenderer { graph.isLabelClipped(state.cell), state.style.overflow, state.style.labelPadding, - state.style.textDirection || DEFAULT_TEXT_DIRECTION + state.style.textDirection ?? DEFAULT_TEXT_DIRECTION ); - state.text.opacity = state.style.textOpacity; + state.text.opacity = state.style.textOpacity ?? 100; state.text.dialect = isForceHtml ? DIALECT_STRICTHTML : state.view.graph.dialect; state.text.style = state.style; state.text.state = state; @@ -928,7 +926,7 @@ class CellRenderer { const isForceHtml = state.view.graph.isHtmlLabel(state.cell) || (value && isNode(value)); const dialect = isForceHtml ? DIALECT_STRICTHTML : state.view.graph.dialect; - const overflow = state.style.overflow || 'visible'; + const overflow = state.style.overflow ?? 'visible'; if ( state.text && diff --git a/packages/core/src/view/cell/GraphCellsMixin.ts b/packages/core/src/view/cell/GraphCellsMixin.ts index 4e359b998..39eacd4d0 100644 --- a/packages/core/src/view/cell/GraphCellsMixin.ts +++ b/packages/core/src/view/cell/GraphCellsMixin.ts @@ -1409,7 +1409,7 @@ const GraphCellsMixin: PartialType = { this.getModel().setStyle(cell, cellStyle); } else {*/ const state = this.getView().createState(cell); - const align = state.style.align || ALIGN_CENTER; + const align = state.style.align ?? ALIGN_CENTER; if (align === ALIGN_RIGHT) { geo.x += geo.width - size.width; @@ -2377,7 +2377,7 @@ const GraphCellsMixin: PartialType = { const state = this.getView().getState(cell); if (state && cell.isVisible() && (!ignoreFn || !ignoreFn(state))) { - const deg = state.style.rotation; + const deg = state.style.rotation ?? 0; let box: CellState | Rectangle = state; // TODO: CHECK ME!!!! ========================================================== if (deg !== 0) { @@ -2486,7 +2486,7 @@ const GraphCellsMixin: PartialType = { pt = next; } } else { - const alpha = toRadians(state.style.rotation); + const alpha = toRadians(state.style.rotation ?? 0); if (alpha !== 0) { const cos = Math.cos(-alpha); diff --git a/packages/core/src/view/cell/datatypes/CellState.ts b/packages/core/src/view/cell/datatypes/CellState.ts index f561bf986..f6b23264d 100644 --- a/packages/core/src/view/cell/datatypes/CellState.ts +++ b/packages/core/src/view/cell/datatypes/CellState.ts @@ -12,7 +12,7 @@ import GraphView from '../../view/GraphView'; import Shape from '../../geometry/shape/Shape'; import TextShape from '../../geometry/shape/node/TextShape'; import Dictionary from '../../../util/Dictionary'; -import { NONE } from '../../../util/Constants'; +import { ALIGN_MIDDLE, NONE } from '../../../util/Constants'; import { CellStateStyles } from '../../../types'; import RectangleShape from '../../geometry/shape/node/RectangleShape'; import CellOverlay from '../CellOverlay'; @@ -466,7 +466,7 @@ class CellState extends Rectangle { * returned. */ getVerticalAlign() { - return this.style.verticalAlign; + return this.style.verticalAlign ?? ALIGN_MIDDLE; } /** @@ -477,8 +477,8 @@ class CellState extends Rectangle { isTransparentState() { let result = false; - const stroke = this.style.strokeColor; - const fill = this.style.fillColor; + const stroke = this.style.strokeColor ?? NONE; + const fill = this.style.fillColor ?? NONE; result = stroke === NONE && fill === NONE && !this.getImageSrc(); diff --git a/packages/core/src/view/cell/vertex/VertexHandler.ts b/packages/core/src/view/cell/vertex/VertexHandler.ts index 8a46beb12..8f350055a 100644 --- a/packages/core/src/view/cell/vertex/VertexHandler.ts +++ b/packages/core/src/view/cell/vertex/VertexHandler.ts @@ -1046,7 +1046,7 @@ class VertexHandler { */ resizeVertex(me: InternalMouseEvent) { const ct = new Point(this.state.getCenterX(), this.state.getCenterY()); - const alpha = toRadians(this.state.style.rotation); + const alpha = toRadians(this.state.style.rotation ?? 0); const point = new Point(me.getGraphX(), me.getGraphY()); const tr = this.graph.view.translate; const { scale } = this.graph.view; @@ -1334,7 +1334,7 @@ class VertexHandler { } } else if (index === InternalEvent.ROTATION_HANDLE) { if (this.currentAlpha != null) { - const delta = this.currentAlpha - (this.state.style.rotation || 0); + const delta = this.currentAlpha - (this.state.style.rotation ?? 0); if (delta !== 0) { this.rotateCell(this.state.cell, delta); @@ -1344,7 +1344,7 @@ class VertexHandler { } } else { const gridEnabled = this.graph.isGridEnabledEvent(me.getEvent()); - const alpha = toRadians(this.state.style.rotation); + const alpha = toRadians(this.state.style.rotation ?? 0); const cos = Math.cos(-alpha); const sin = Math.sin(-alpha); @@ -1523,7 +1523,7 @@ class VertexHandler { if (geo && this.labelShape && this.labelShape.bounds) { if (index === InternalEvent.LABEL_HANDLE) { - const alpha = -toRadians(this.state.style.rotation); + const alpha = -toRadians(this.state.style.rotation ?? 0); const cos = Math.cos(alpha); const sin = Math.sin(alpha); const { scale } = this.graph.view; @@ -1923,7 +1923,7 @@ class VertexHandler { 'w-resize', ]; - const alpha = toRadians(this.state.style.rotation); + const alpha = toRadians(this.state.style.rotation ?? 0); const cos = Math.cos(alpha); const sin = Math.sin(alpha); const da = Math.round((alpha * 4) / Math.PI); diff --git a/packages/core/src/view/connection/ConstraintHandler.ts b/packages/core/src/view/connection/ConstraintHandler.ts index 92392efe9..f9bf54eda 100644 --- a/packages/core/src/view/connection/ConstraintHandler.ts +++ b/packages/core/src/view/connection/ConstraintHandler.ts @@ -76,7 +76,7 @@ class ConstraintHandler { focusIcons: ImageShape[] = []; - constraints: ConnectionConstraint[] = []; + constraints: ConnectionConstraint[] | null = null; currentConstraint: ConnectionConstraint | null = null; @@ -275,6 +275,7 @@ class ConstraintHandler { 2 * tol, 2 * tol ); + const state = this.graph.view.getState(this.getCellForEvent(me, point) as Cell); // Keeps focus icons visible while over vertex bounds and no other cell under mouse or shift is pressed @@ -396,16 +397,16 @@ class ConstraintHandler { * the handler is not enabled then the outline is painted, but the constraints * are ignored. */ - setFocus(me: InternalMouseEvent, state: CellState, source: boolean) { + setFocus(me: InternalMouseEvent, state: CellState | null, source: boolean) { this.constraints = - state != null && !this.isStateIgnored(state, source) && state.cell.isConnectable() + state && !this.isStateIgnored(state, source) && state.cell.isConnectable() ? this.isEnabled() - ? this.graph.getAllConnectionConstraints(state, source) || [] + ? this.graph.getAllConnectionConstraints(state, source) ?? [] : [] - : []; + : null; // Only uses cells which have constraints - if (this.constraints != null) { + if (this.constraints && state) { this.currentFocus = state; this.currentFocusArea = new Rectangle(state.x, state.y, state.width, state.height); diff --git a/packages/core/src/view/selection/CellHighlight.ts b/packages/core/src/view/selection/CellHighlight.ts index d13ffbd55..5550635b6 100644 --- a/packages/core/src/view/selection/CellHighlight.ts +++ b/packages/core/src/view/selection/CellHighlight.ts @@ -186,8 +186,7 @@ class CellHighlight { if (this.state != null && this.shape != null) { this.shape.scale = this.state.view.scale; - // @ts-ignore - if (this.graph.model.isEdge(this.state.cell)) { + if (this.state.cell.isEdge()) { this.shape.strokeWidth = this.getStrokeWidth(); this.shape.points = this.state.absolutePoints; this.shape.outline = false; diff --git a/packages/html/.storybook/preview.js b/packages/html/.storybook/preview.js index 32d38e266..9232b1b74 100644 --- a/packages/html/.storybook/preview.js +++ b/packages/html/.storybook/preview.js @@ -1,21 +1,22 @@ +import '@maxgraph/css/common.css'; export const parameters = { - actions: { argTypesRegex: "^on[A-Z].*" }, + actions: { argTypesRegex: '^on[A-Z].*' }, controls: { matchers: { color: /(background|color)$/i, date: /Date$/, }, }, -} +}; export const globalTypes = { width: { type: 'number', - defaultValue: 800 + defaultValue: 800, }, height: { type: 'number', - defaultValue: 600 - } + defaultValue: 600, + }, }; diff --git a/packages/html/stories/HelloWorld.stories.js b/packages/html/stories/HelloWorld.stories.js index b3bdb030d..7dbd5cf2a 100644 --- a/packages/html/stories/HelloWorld.stories.js +++ b/packages/html/stories/HelloWorld.stories.js @@ -1,4 +1,5 @@ import { Graph, InternalEvent, RubberBand } from '@maxgraph/core'; + import { globalTypes } from '../.storybook/preview'; export default { diff --git a/packages/html/webpack.config.js b/packages/html/webpack.config.js index 6b0e9e663..df7272881 100644 --- a/packages/html/webpack.config.js +++ b/packages/html/webpack.config.js @@ -6,6 +6,7 @@ module.exports = merge(base, { resolve: { alias: { '@maxgraph/core': path.resolve(__dirname, '../core/src'), + '@maxgraph/css': path.resolve(__dirname, '../core/css'), }, }, });