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() diff --git a/packages/x6-plugin-selection/src/index.ts b/packages/x6-plugin-selection/src/index.ts index 55892841e95..3e7dba6fc2b 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,11 +41,12 @@ export class Selection constructor(options: Selection.Options = {}) { super() - this.options = ObjectExt.merge( - { enabled: true }, - Selection.defaultOptions, - options, - ) + this.options = { + enabled: true, + ...Selection.defaultOptions, + ...options, + } + CssLoader.ensure(this.name, content) } @@ -320,6 +320,10 @@ export class Selection } protected onBlankMouseDown({ e }: EventArgs['blank:mousedown']) { + if (!this.allowBlankMouseDown(e)) { + return + } + const allowGraphPanning = this.graph.panning.allowPanning(e, true) const scroller = this.graph.getPlugin('scroller') const allowScrollerPanning = scroller && scroller.allowPanning(e, true) @@ -331,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() } @@ -475,5 +487,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 { diff --git a/packages/x6/src/graph/panning.ts b/packages/x6/src/graph/panning.ts index 6e3f30de2ea..26e67fb9945 100644 --- a/packages/x6/src/graph/panning.ts +++ b/packages/x6/src/graph/panning.ts @@ -101,10 +101,10 @@ export class PanningManager extends Base { } protected onMouseDown({ e }: { e: Dom.MouseDownEvent }) { - const eventTypes = this.widgetOptions.eventTypes - if (!(eventTypes && eventTypes.includes('leftMouseDown'))) { + if (!this.allowBlankMouseDown(e)) { return } + const selection = this.graph.getPlugin('selection') const allowRubberband = selection && selection.allowRubberband(e, true) if ( @@ -117,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) { @@ -135,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 } @@ -187,7 +195,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 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`: 按下鼠标滚轮进行拖拽 ## 方法 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(...)