fix: CellOverlay constructor use all parameters to set properties (#159)

The `align` and `verticalAlign` values passed to the constructor weren't
set, so the overlay position was always set to
the default one.

The `align` and `verticalAlign` properties are now using the AlignValue
and VAlignValue types respectively instead of
defining inline types. This improves the consistent in the whole code.

To demonstrate the fix, the Overlays story now set 'align' and
'verticalAlign' randomly.


Also introduce `jest` to test the fix and the whole
implementation of the changed method. Types check support is provided by
`ts-jest`. As maxGraph uses a lot of browser objects, also setup
`jest-jsdom-environment`.
development
Thomas Bouffard 2022-12-16 16:51:51 +01:00 committed by GitHub
parent e730207a3d
commit b7a322b36f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 85 additions and 17 deletions

View File

@ -49,6 +49,9 @@ jobs:
- name: Generate @maxgraph/core types - name: Generate @maxgraph/core types
working-directory: packages/core working-directory: packages/core
run: npm run generate-types run: npm run generate-types
- name: Test @maxgraph/core
working-directory: packages/core
run: npm test
- name: Test TypeScript support - name: Test TypeScript support
working-directory: packages/ts-support working-directory: packages/ts-support
run: npm test run: npm test

View File

@ -0,0 +1,40 @@
/*
Copyright 2022-present The maxGraph project Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { describe, expect, test } from '@jest/globals';
import { CellOverlay, Point } from '../../../src';
test('Constructor set all parameters', () => {
const cellOverlay = new CellOverlay(
// @ts-ignore
null,
'my tooltip',
'left',
'middle',
new Point(10, 20),
'custom'
);
expect(cellOverlay).toEqual(
expect.objectContaining({
align: 'left',
cursor: 'custom',
offset: new Point(10, 20),
tooltip: 'my tooltip',
verticalAlign: 'middle',
})
);
});

View File

@ -0,0 +1,6 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
// preset: 'ts-jest',
preset: 'ts-jest/presets/default-esm',
testEnvironment: 'jsdom', // need to access to the browser objects
};

View File

@ -22,11 +22,15 @@
"build": "cross-env NODE_ENV=production webpack --mode=production", "build": "cross-env NODE_ENV=production webpack --mode=production",
"generate-types": "tsc --emitDeclarationOnly", "generate-types": "tsc --emitDeclarationOnly",
"generate-esm": "tsc --emitDeclarationOnly false --declaration false --declarationDir null", "generate-esm": "tsc --emitDeclarationOnly false --declaration false --declarationDir null",
"prepack": "run-s generate-types generate-esm build" "prepack": "run-s generate-types generate-esm build",
"test": "jest"
}, },
"devDependencies": { "devDependencies": {
"circular-dependency-plugin": "^5.2.2", "circular-dependency-plugin": "^5.2.2",
"npm-run-all": "~4.1.5" "jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
"npm-run-all": "~4.1.5",
"ts-jest": "^29.0.3"
}, },
"sideEffects": true "sideEffects": true
} }

View File

@ -22,6 +22,7 @@ import EventSource from '../event/EventSource';
import ImageBox from '../image/ImageBox'; import ImageBox from '../image/ImageBox';
import CellState from './CellState'; import CellState from './CellState';
import ObjectIdentity from '../../util/ObjectIdentity'; import ObjectIdentity from '../../util/ObjectIdentity';
import { AlignValue, VAlignValue } from '../../types';
/** /**
* Extends {@link EventSource} to implement a graph overlay, represented by an icon * Extends {@link EventSource} to implement a graph overlay, represented by an icon
@ -77,8 +78,8 @@ class CellOverlay extends EventSource implements ObjectIdentity {
constructor( constructor(
image: ImageBox, image: ImageBox,
tooltip: string | null = null, tooltip: string | null = null,
align = 'right', align: AlignValue = 'right',
verticalAlign = 'bottom', verticalAlign: VAlignValue = 'bottom',
offset: Point = new Point(), offset: Point = new Point(),
cursor = 'help' cursor = 'help'
) { ) {
@ -86,6 +87,8 @@ class CellOverlay extends EventSource implements ObjectIdentity {
this.image = image; this.image = image;
this.tooltip = tooltip; this.tooltip = tooltip;
this.align = align;
this.verticalAlign = verticalAlign;
this.offset = offset; this.offset = offset;
this.cursor = cursor; this.cursor = cursor;
} }
@ -101,18 +104,20 @@ class CellOverlay extends EventSource implements ObjectIdentity {
tooltip?: string | null; tooltip?: string | null;
/** /**
* Holds the horizontal alignment for the overlay. Default is * Holds the horizontal alignment for the overlay.
* {@link Constants#ALIGN_RIGHT}. For edges, the overlay always appears in the *
* center of the edge. * For edges, the overlay always appears in the center of the edge.
* @default 'right'
*/ */
align: 'left' | 'center' | 'right' = 'right'; align: AlignValue = 'right';
/** /**
* Holds the vertical alignment for the overlay. Default is * Holds the vertical alignment for the overlay.
* {@link Constants#ALIGN_BOTTOM}. For edges, the overlay always appears in the *
* center of the edge. * For edges, the overlay always appears in the center of the edge.
* @default 'bottom'
*/ */
verticalAlign: 'top' | 'middle' | 'bottom' = 'bottom'; verticalAlign: VAlignValue = 'bottom';
/** /**
* Holds the offset as an {@link Point}. The offset will be scaled according to the * Holds the offset as an {@link Point}. The offset will be scaled according to the
@ -121,7 +126,8 @@ class CellOverlay extends EventSource implements ObjectIdentity {
offset = new Point(); offset = new Point();
/** /**
* Holds the cursor for the overlay. Default is 'help'. * Holds the cursor for the overlay.
* @default 'help'.
*/ */
cursor = 'help'; cursor = 'help';

View File

@ -54,6 +54,14 @@ const Template = ({ label, ...args }) => {
// Enables tooltips for the overlays // Enables tooltips for the overlays
graph.setTooltips(true); graph.setTooltips(true);
function pickAlignValueRandomly() {
return ['left', 'center', 'right'][Math.floor(Math.random() * 3)];
}
function pickVerticalAlignValueRandomly() {
return ['top', 'bottom'][Math.floor(Math.random() * 2)];
}
// Installs a handler for click events in the graph // Installs a handler for click events in the graph
// that toggles the overlay for the respective cell // that toggles the overlay for the respective cell
graph.addListener(InternalEvent.CLICK, (sender, evt) => { graph.addListener(InternalEvent.CLICK, (sender, evt) => {
@ -61,12 +69,13 @@ const Template = ({ label, ...args }) => {
if (cell != null) { if (cell != null) {
const overlays = graph.getCellOverlays(cell); const overlays = graph.getCellOverlays(cell);
if (overlays.length === 0) {
if (overlays.length == 0) {
// Creates a new overlay with an image and a tooltip // Creates a new overlay with an image and a tooltip
const overlay = new CellOverlay( const overlay = new CellOverlay(
new ImageBox('/images/check.png', 16, 16), new ImageBox('/images/check.png', 16, 16),
'Overlay tooltip' 'Overlay tooltip',
pickAlignValueRandomly(),
pickVerticalAlignValueRandomly()
); );
// Installs a handler for clicks on the overlay // Installs a handler for clicks on the overlay
@ -104,7 +113,7 @@ const Template = ({ label, ...args }) => {
}); });
const v2 = graph.insertVertex({ const v2 = graph.insertVertex({
parent, parent,
value: 'Doubleclick', value: 'Double Click',
position: [200, 150], position: [200, 150],
size: [100, 40], size: [100, 40],
}); });