From 443210c94a08f9b63c757e950c3204cc3a65070d Mon Sep 17 00:00:00 2001 From: Mingfei Ding Date: Wed, 11 Oct 2023 15:52:56 +0800 Subject: [PATCH 1/9] feat(selection): add the eventTypes option which allows specifying selection listening buttons --- packages/x6-plugin-selection/src/index.ts | 38 +++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/x6-plugin-selection/src/index.ts b/packages/x6-plugin-selection/src/index.ts index 55892841e95..ff3771805c1 100644 --- a/packages/x6-plugin-selection/src/index.ts +++ b/packages/x6-plugin-selection/src/index.ts @@ -47,6 +47,12 @@ export class Selection Selection.defaultOptions, options, ) + + if (!Array.isArray(this.options.eventTypes)) { + // a new option, compatible with the behavior of older versions + this.options.eventTypes = ['leftMouseDown', 'mouseWheelDown'] + } + CssLoader.ensure(this.name, content) } @@ -304,7 +310,12 @@ export class Selection } protected startListening() { - this.graph.on('blank:mousedown', this.onBlankMouseDown, this) + if (this.options.eventTypes?.includes('leftMouseDown')) { + this.graph.on('blank:mousedown', this.onBlankLeftMouseDown, this) + } + if (this.options.eventTypes?.includes('mouseWheelDown')) { + this.graph.on('blank:mousedown', this.onBlankMouseWheelDown, this) + } this.graph.on('blank:click', this.onBlankClick, this) this.graph.on('cell:mousemove', this.onCellMouseMove, this) this.graph.on('cell:mouseup', this.onCellMouseUp, this) @@ -312,13 +323,34 @@ export class Selection } protected stopListening() { - this.graph.off('blank:mousedown', this.onBlankMouseDown, this) + if (this.options.eventTypes?.includes('leftMouseDown')) { + this.graph.off('blank:mousedown', this.onBlankLeftMouseDown, this) + } + if (this.options.eventTypes?.includes('mouseWheelDown')) { + this.graph.off('blank:mousedown', this.onBlankMouseWheelDown, this) + } this.graph.off('blank:click', this.onBlankClick, this) this.graph.off('cell:mousemove', this.onCellMouseMove, this) this.graph.off('cell:mouseup', this.onCellMouseUp, this) this.selectionImpl.off('box:mousedown', this.onBoxMouseDown, this) } + protected onBlankLeftMouseDown(mouseDownEvent: EventArgs['blank:mousedown']) { + if (mouseDownEvent.e.button !== 0) { + return + } + this.onBlankMouseDown(mouseDownEvent) + } + + protected onBlankMouseWheelDown( + mouseDownEvent: EventArgs['blank:mousedown'], + ) { + if (mouseDownEvent.e.button !== 1) { + return + } + this.onBlankMouseDown(mouseDownEvent) + } + protected onBlankMouseDown({ e }: EventArgs['blank:mousedown']) { const allowGraphPanning = this.graph.panning.allowPanning(e, true) const scroller = this.graph.getPlugin('scroller') @@ -449,9 +481,11 @@ export class Selection } export namespace Selection { + type SelectionEventType = 'leftMouseDown' | 'mouseWheelDown' export interface EventArgs extends SelectionImpl.EventArgs {} export interface Options extends SelectionImpl.CommonOptions { enabled?: boolean + eventTypes?: SelectionEventType[] } export type Filter = SelectionImpl.Filter From 9664d9ae81341f4c20f9df21faffbbdb9c16281f Mon Sep 17 00:00:00 2001 From: Mingfei Ding Date: Wed, 11 Oct 2023 15:54:29 +0800 Subject: [PATCH 2/9] feat(panning): add a new eventType 'mouseWheelDown' --- packages/x6/src/graph/panning.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/x6/src/graph/panning.ts b/packages/x6/src/graph/panning.ts index f26a1dee575..d1556b560d5 100644 --- a/packages/x6/src/graph/panning.ts +++ b/packages/x6/src/graph/panning.ts @@ -34,6 +34,12 @@ export class PanningManager extends Base { this.onRightMouseDown = this.onRightMouseDown.bind(this) Dom.Event.on(this.graph.container, 'mousedown', this.onRightMouseDown) } + + if (eventTypes.includes('mouseWheelDown')) { + this.onMouseWheelDown = this.onMouseWheelDown.bind(this) + Dom.Event.on(this.graph.container, 'mousedown', this.onMouseWheelDown) + } + if (eventTypes.includes('mouseWheel')) { this.mousewheelHandle = new Dom.MouseWheelHandle( this.graph.container, @@ -57,6 +63,9 @@ export class PanningManager extends Base { if (eventTypes.includes('rightMouseDown')) { Dom.Event.off(this.graph.container, 'mousedown', this.onRightMouseDown) } + if (eventTypes.includes('mouseWheelDown')) { + Dom.Event.off(this.graph.container, 'mousedown', this.onMouseWheelDown) + } if (eventTypes.includes('mouseWheel')) { if (this.mousewheelHandle) { this.mousewheelHandle.disable() @@ -137,6 +146,12 @@ export class PanningManager extends Base { } } + protected onMouseWheelDown(e: Dom.MouseDownEvent) { + if (e.button === 1 && this.allowPanning(e, true)) { + this.startPanning(e) + } + } + protected allowMouseWheel(e: WheelEvent) { return this.pannable && !e.ctrlKey } @@ -195,7 +210,11 @@ export class PanningManager extends Base { } export namespace PanningManager { - type EventType = 'leftMouseDown' | 'rightMouseDown' | 'mouseWheel' + type EventType = + | 'leftMouseDown' + | 'rightMouseDown' + | 'mouseWheel' + | 'mouseWheelDown' export interface Options { enabled?: boolean modifiers?: string | ModifierKey[] | null From 335be796c85b3781559f4487f87944a114f36443 Mon Sep 17 00:00:00 2001 From: Mingfei Ding Date: Wed, 11 Oct 2023 15:56:15 +0800 Subject: [PATCH 3/9] test(selection): allow panning with mouseWheelDown in the selection example --- examples/x6-example-features/src/pages/selection/index.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/x6-example-features/src/pages/selection/index.tsx b/examples/x6-example-features/src/pages/selection/index.tsx index 4c0328ddd93..9a5f2b9bb4b 100644 --- a/examples/x6-example-features/src/pages/selection/index.tsx +++ b/examples/x6-example-features/src/pages/selection/index.tsx @@ -13,6 +13,10 @@ export default class Example extends React.Component { width: 800, height: 600, grid: true, + panning: { + enabled: true, + eventTypes: ['mouseWheelDown'], + }, }) const keyboard = new Keyboard() From a3a9ec5f251bbbc393245612d5eb5e459cf40847 Mon Sep 17 00:00:00 2001 From: Mingfei Ding Date: Thu, 12 Oct 2023 14:17:36 +0800 Subject: [PATCH 4/9] docs(selection): add document for new option 'eventTypes' --- .../docs/tutorial/plugins/selection.zh.md | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/sites/x6-sites/docs/tutorial/plugins/selection.zh.md b/sites/x6-sites/docs/tutorial/plugins/selection.zh.md index 77a474ce723..df5d7a2cdfb 100644 --- a/sites/x6-sites/docs/tutorial/plugins/selection.zh.md +++ b/sites/x6-sites/docs/tutorial/plugins/selection.zh.md @@ -57,20 +57,21 @@ graph.use( ## 配置 -| 属性名 | 类型 | 默认值 | 必选 | 描述 | -|----------------------------|----------------|--------------------|------|------------------------------------------------------------------------------------------------------------------------------------------| -| className | string | - | | 附加样式名,用于定制样式 | -| multiple | boolean | `true` | | 是否启用点击多选,启用后按住 `ctrl` 或 `command` 键点击节点实现多选 | -| multipleSelectionModifiers | ModifierKey | `['ctrl', 'meta']` | | 用于设置上面点击多选配套的修饰键 | -| rubberband | boolean | `false` | | 是否启用框选节点功能 | -| modifiers | ModifierKey | - | | 用于设置上面框选配套的修饰键 | -| strict | boolean | `false` | | 选框是否需要完全包围节点时才选中节点 | -| movable | boolean | `true` | | 拖动选框时框选的节点是否一起移动 | -| content | string | - | | 设置附加显示的内容 | -| filter | Filter | - | | 节点过滤器 | -| showNodeSelectionBox | boolean | `false` | | 是否显示节点的选择框 | -| showEdgeSelectionBox | boolean | `false` | | 是否显示边的选择框 | -| pointerEvents | `node \| auto` | `auto` | | 如果打开 `showNodeSelectionBox` 时,会在节点上方盖一层元素,导致节点的事件无法响应,此时可以配置 `pointerEvents: none` 来解决,默认值是 `auto` | +| 属性名 | 类型 | 默认值 | 必选 | 描述 | +| -------------------------- | -------------------- | ------------------------------------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| className | string | - | | 附加样式名,用于定制样式 | +| multiple | boolean | `true` | | 是否启用点击多选,启用后按住 `ctrl` 或 `command` 键点击节点实现多选 | +| multipleSelectionModifiers | ModifierKey | `['ctrl', 'meta']` | | 用于设置上面点击多选配套的修饰键 | +| rubberband | boolean | `false` | | 是否启用框选节点功能 | +| modifiers | ModifierKey | - | | 用于设置上面框选配套的修饰键 | +| strict | boolean | `false` | | 选框是否需要完全包围节点时才选中节点 | +| movable | boolean | `true` | | 拖动选框时框选的节点是否一起移动 | +| content | string | - | | 设置附加显示的内容 | +| filter | Filter | - | | 节点过滤器 | +| showNodeSelectionBox | boolean | `false` | | 是否显示节点的选择框 | +| showEdgeSelectionBox | boolean | `false` | | 是否显示边的选择框 | +| pointerEvents | `node \| auto` | `auto` | | 如果打开 `showNodeSelectionBox` 时,会在节点上方盖一层元素,导致节点的事件无法响应,此时可以配置 `pointerEvents: none` 来解决,默认值是 `auto` | +| eventTypes | SelectionEventType[] | `['leftMouseDown', 'mouseWheelDown']` | | 用于设置框选的触发事件类型 | `Filter` 的类型定义如下: @@ -96,6 +97,17 @@ X6 中修饰键包括 `alt`、`ctrl`、`meta`、`shift` 四个,设置修饰键 - `alt&ctrl` 表示同时按下 `alt` 和 `ctrl`。 - `alt|ctrl&shift` 表示同时按下 `alt` 和 `shift` 或者同时按下 `ctrl` 和 `shift`。 +`SelectionEventType` 的类型定义如下: + +```ts +type SelectionEventType = 'leftMouseDown' | 'mouseWheelDown'; +``` +触发框选的交互方式。支持2种形式或者他们之间的组合: + +- `leftMouseDown`: 按下鼠标左键移动进行拖拽 +- `mouseWheelDown`: 按下鼠标滚轮进行拖拽 + + ## API ### graph.select(...) From e1c9a477fc4fff1e1f85a16a405b77b16c265216 Mon Sep 17 00:00:00 2001 From: Mingfei Ding Date: Thu, 12 Oct 2023 14:18:42 +0800 Subject: [PATCH 5/9] docs(panning): add document for 'mouseWheelDown' of 'eventType' --- sites/x6-sites/docs/api/graph/panning.zh.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sites/x6-sites/docs/api/graph/panning.zh.md b/sites/x6-sites/docs/api/graph/panning.zh.md index 4c7df92ef32..41dc9e09782 100644 --- a/sites/x6-sites/docs/api/graph/panning.zh.md +++ b/sites/x6-sites/docs/api/graph/panning.zh.md @@ -38,7 +38,7 @@ const graph = new Graph({ interface Options { enabled?: boolean modifiers?: ModifierKey - eventTypes?: ('leftMouseDown' | 'rightMouseDown' | 'mouseWheel')[] + eventTypes?: ('leftMouseDown' | 'rightMouseDown' | 'mouseWheel', 'mouseWheelDown')[] } ``` @@ -70,7 +70,8 @@ type ModifierKey = string | ('alt' | 'ctrl' | 'meta' | 'shift')[] | null - `leftMouseDown`: 按下鼠标左键移动进行拖拽 - `rightMouseDown`: 按下鼠标右键移动进行拖拽 -- `mouseWheel`: 使用鼠标滚轮拖拽 +- `mouseWheel`: 使用鼠标滚轮滚动拖拽 +- `mouseWheelDown`: 按下鼠标滚轮进行拖拽 ## 方法 From bfa50bcde7030bbe45d5ca0950d036d1a079f154 Mon Sep 17 00:00:00 2001 From: Mingfei Ding Date: Thu, 12 Oct 2023 14:29:45 +0800 Subject: [PATCH 6/9] fix: improve code style --- packages/x6-plugin-selection/src/index.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/x6-plugin-selection/src/index.ts b/packages/x6-plugin-selection/src/index.ts index ff3771805c1..012dda822e3 100644 --- a/packages/x6-plugin-selection/src/index.ts +++ b/packages/x6-plugin-selection/src/index.ts @@ -336,19 +336,17 @@ export class Selection } protected onBlankLeftMouseDown(mouseDownEvent: EventArgs['blank:mousedown']) { - if (mouseDownEvent.e.button !== 0) { - return + if (mouseDownEvent.e.button === 0) { + this.onBlankMouseDown(mouseDownEvent) } - this.onBlankMouseDown(mouseDownEvent) } protected onBlankMouseWheelDown( mouseDownEvent: EventArgs['blank:mousedown'], ) { - if (mouseDownEvent.e.button !== 1) { - return + if (mouseDownEvent.e.button === 1) { + this.onBlankMouseDown(mouseDownEvent) } - this.onBlankMouseDown(mouseDownEvent) } protected onBlankMouseDown({ e }: EventArgs['blank:mousedown']) { From bc1b9d39841335ea830d928f45a03ff400b23ad1 Mon Sep 17 00:00:00 2001 From: Mingfei Ding Date: Thu, 12 Oct 2023 17:04:02 +0800 Subject: [PATCH 7/9] fix: move eventTypes to Selection.CommonOptions & add into the default option --- packages/x6-plugin-selection/src/index.ts | 17 +++++------------ packages/x6-plugin-selection/src/selection.ts | 5 +++++ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/x6-plugin-selection/src/index.ts b/packages/x6-plugin-selection/src/index.ts index 012dda822e3..346a609733d 100644 --- a/packages/x6-plugin-selection/src/index.ts +++ b/packages/x6-plugin-selection/src/index.ts @@ -3,7 +3,6 @@ import { ModifierKey, CssLoader, Dom, - ObjectExt, Cell, EventArgs, Graph, @@ -42,15 +41,10 @@ export class Selection constructor(options: Selection.Options = {}) { super() - this.options = ObjectExt.merge( - { enabled: true }, - Selection.defaultOptions, - options, - ) - - if (!Array.isArray(this.options.eventTypes)) { - // a new option, compatible with the behavior of older versions - this.options.eventTypes = ['leftMouseDown', 'mouseWheelDown'] + this.options = { + enabled: true, + ...Selection.defaultOptions, + ...options, } CssLoader.ensure(this.name, content) @@ -479,11 +473,9 @@ export class Selection } export namespace Selection { - type SelectionEventType = 'leftMouseDown' | 'mouseWheelDown' export interface EventArgs extends SelectionImpl.EventArgs {} export interface Options extends SelectionImpl.CommonOptions { enabled?: boolean - eventTypes?: SelectionEventType[] } export type Filter = SelectionImpl.Filter @@ -507,5 +499,6 @@ export namespace Selection { selectEdgeOnMoved: false, following: true, content: null, + eventTypes: ['leftMouseDown', 'mouseWheelDown'], } } diff --git a/packages/x6-plugin-selection/src/selection.ts b/packages/x6-plugin-selection/src/selection.ts index ea7b53fe350..243b604e422 100644 --- a/packages/x6-plugin-selection/src/selection.ts +++ b/packages/x6-plugin-selection/src/selection.ts @@ -950,6 +950,8 @@ export class SelectionImpl extends View { } export namespace SelectionImpl { + type SelectionEventType = 'leftMouseDown' | 'mouseWheelDown' + export interface CommonOptions { model?: Model collection?: Collection @@ -977,6 +979,9 @@ export namespace SelectionImpl { // Whether to respond event on the selectionBox pointerEvents?: 'none' | 'auto' + + // with which mouse button the selection can be started + eventTypes?: SelectionEventType[] } export interface Options extends CommonOptions { From 63877a69e582fa69ec016cd425f4049e6a029801 Mon Sep 17 00:00:00 2001 From: Mingfei Ding Date: Fri, 20 Oct 2023 02:22:38 +0800 Subject: [PATCH 8/9] fix: put mouse button check log inside callback to enable dynamically change eventTypes --- packages/x6-plugin-selection/src/index.ts | 34 ++++++----------------- packages/x6/src/graph/panning.ts | 5 +++- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/packages/x6-plugin-selection/src/index.ts b/packages/x6-plugin-selection/src/index.ts index 346a609733d..8554fe2e256 100644 --- a/packages/x6-plugin-selection/src/index.ts +++ b/packages/x6-plugin-selection/src/index.ts @@ -304,12 +304,7 @@ export class Selection } protected startListening() { - if (this.options.eventTypes?.includes('leftMouseDown')) { - this.graph.on('blank:mousedown', this.onBlankLeftMouseDown, this) - } - if (this.options.eventTypes?.includes('mouseWheelDown')) { - this.graph.on('blank:mousedown', this.onBlankMouseWheelDown, this) - } + this.graph.on('blank:mousedown', this.onBlankMouseDown, this) this.graph.on('blank:click', this.onBlankClick, this) this.graph.on('cell:mousemove', this.onCellMouseMove, this) this.graph.on('cell:mouseup', this.onCellMouseUp, this) @@ -317,33 +312,22 @@ export class Selection } protected stopListening() { - if (this.options.eventTypes?.includes('leftMouseDown')) { - this.graph.off('blank:mousedown', this.onBlankLeftMouseDown, this) - } - if (this.options.eventTypes?.includes('mouseWheelDown')) { - this.graph.off('blank:mousedown', this.onBlankMouseWheelDown, this) - } + this.graph.off('blank:mousedown', this.onBlankMouseDown, this) this.graph.off('blank:click', this.onBlankClick, this) this.graph.off('cell:mousemove', this.onCellMouseMove, this) this.graph.off('cell:mouseup', this.onCellMouseUp, this) this.selectionImpl.off('box:mousedown', this.onBoxMouseDown, this) } - protected onBlankLeftMouseDown(mouseDownEvent: EventArgs['blank:mousedown']) { - if (mouseDownEvent.e.button === 0) { - this.onBlankMouseDown(mouseDownEvent) - } - } - - protected onBlankMouseWheelDown( - mouseDownEvent: EventArgs['blank:mousedown'], - ) { - if (mouseDownEvent.e.button === 1) { - this.onBlankMouseDown(mouseDownEvent) + protected onBlankMouseDown({ e }: EventArgs['blank:mousedown']) { + const eventTypes = this.options.eventTypes + if ( + !(eventTypes && eventTypes.includes('leftMouseDown') && e.button === 0) && + !(eventTypes && eventTypes.includes('mouseWheelDown') && e.button === 1) + ) { + return } - } - protected onBlankMouseDown({ e }: EventArgs['blank:mousedown']) { const allowGraphPanning = this.graph.panning.allowPanning(e, true) const scroller = this.graph.getPlugin('scroller') const allowScrollerPanning = scroller && scroller.allowPanning(e, true) diff --git a/packages/x6/src/graph/panning.ts b/packages/x6/src/graph/panning.ts index 8011938aa54..03b8fc99eff 100644 --- a/packages/x6/src/graph/panning.ts +++ b/packages/x6/src/graph/panning.ts @@ -102,7 +102,10 @@ export class PanningManager extends Base { protected onMouseDown({ e }: { e: Dom.MouseDownEvent }) { const eventTypes = this.widgetOptions.eventTypes - if (!(eventTypes && eventTypes.includes('leftMouseDown'))) { + if ( + !(eventTypes && eventTypes.includes('leftMouseDown') && e.button === 0) && + !(eventTypes && eventTypes.includes('mouseWheelDown') && e.button === 1) + ) { return } const selection = this.graph.getPlugin('selection') From 62e1eec1ba4a4642b4d1fa6d663f103a0283984c Mon Sep 17 00:00:00 2001 From: Mingfei Ding Date: Fri, 27 Oct 2023 15:59:37 +0800 Subject: [PATCH 9/9] fix: optimize code style --- packages/x6-plugin-selection/src/index.ts | 14 +++++++++----- packages/x6/src/graph/panning.ts | 21 +++++++++++++-------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/packages/x6-plugin-selection/src/index.ts b/packages/x6-plugin-selection/src/index.ts index 8554fe2e256..3e7dba6fc2b 100644 --- a/packages/x6-plugin-selection/src/index.ts +++ b/packages/x6-plugin-selection/src/index.ts @@ -320,11 +320,7 @@ export class Selection } protected onBlankMouseDown({ e }: EventArgs['blank:mousedown']) { - const eventTypes = this.options.eventTypes - if ( - !(eventTypes && eventTypes.includes('leftMouseDown') && e.button === 0) && - !(eventTypes && eventTypes.includes('mouseWheelDown') && e.button === 1) - ) { + if (!this.allowBlankMouseDown(e)) { return } @@ -339,6 +335,14 @@ export class Selection } } + protected allowBlankMouseDown(e: Dom.MouseDownEvent) { + const eventTypes = this.options.eventTypes + return ( + (eventTypes?.includes('leftMouseDown') && e.button === 0) || + (eventTypes?.includes('mouseWheelDown') && e.button === 1) + ) + } + protected onBlankClick() { this.clean() } diff --git a/packages/x6/src/graph/panning.ts b/packages/x6/src/graph/panning.ts index 03b8fc99eff..26e67fb9945 100644 --- a/packages/x6/src/graph/panning.ts +++ b/packages/x6/src/graph/panning.ts @@ -101,13 +101,10 @@ export class PanningManager extends Base { } protected onMouseDown({ e }: { e: Dom.MouseDownEvent }) { - const eventTypes = this.widgetOptions.eventTypes - if ( - !(eventTypes && eventTypes.includes('leftMouseDown') && e.button === 0) && - !(eventTypes && eventTypes.includes('mouseWheelDown') && e.button === 1) - ) { + if (!this.allowBlankMouseDown(e)) { return } + const selection = this.graph.getPlugin('selection') const allowRubberband = selection && selection.allowRubberband(e, true) if ( @@ -120,17 +117,17 @@ export class PanningManager extends Base { protected onRightMouseDown(e: Dom.MouseDownEvent) { const eventTypes = this.widgetOptions.eventTypes - if (!(eventTypes && eventTypes.includes('rightMouseDown'))) { + if (!(eventTypes?.includes('rightMouseDown') && e.button === 2)) { return } - if (e.button === 2 && this.allowPanning(e, true)) { + if (this.allowPanning(e, true)) { this.startPanning(e) } } protected onMouseWheel(e: WheelEvent, deltaX: number, deltaY: number) { const eventTypes = this.widgetOptions.eventTypes - if (!(eventTypes && eventTypes.includes('mouseWheel'))) { + if (!eventTypes?.includes('mouseWheel')) { return } if (!e.ctrlKey) { @@ -138,6 +135,14 @@ export class PanningManager extends Base { } } + protected allowBlankMouseDown(e: Dom.MouseDownEvent) { + const eventTypes = this.widgetOptions.eventTypes + return ( + (eventTypes?.includes('leftMouseDown') && e.button === 0) || + (eventTypes?.includes('mouseWheelDown') && e.button === 1) + ) + } + protected allowMouseWheel(e: WheelEvent) { return this.pannable && !e.ctrlKey }