mirror of
https://gitee.com/ByteDance/flowgram.ai.git
synced 2025-07-07 17:43:29 +08:00
feat(minimap): support touch operation (#381)
* fix(core): touch end clear hover * feat(minimap): support touch operation * fix(demo): touch create comment should not trigger drag * feat(demo): comment node support touch resize
This commit is contained in:
parent
83ae052705
commit
fd423d9cb5
@ -1,6 +1,6 @@
|
||||
import { CSSProperties, type FC } from 'react';
|
||||
|
||||
import { useNodeRender, usePlayground } from '@flowgram.ai/free-layout-editor';
|
||||
import { MouseTouchEvent, useNodeRender, usePlayground } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import type { CommentEditorModel } from '../model';
|
||||
|
||||
@ -26,23 +26,27 @@ export const ResizeArea: FC<IResizeArea> = (props) => {
|
||||
|
||||
const { selectNode } = useNodeRender();
|
||||
|
||||
const handleMouseDown = (mouseDownEvent: React.MouseEvent) => {
|
||||
mouseDownEvent.preventDefault();
|
||||
mouseDownEvent.stopPropagation();
|
||||
const handleResizeStart = (
|
||||
startResizeEvent: React.MouseEvent | React.TouchEvent | MouseEvent
|
||||
) => {
|
||||
MouseTouchEvent.preventDefault(startResizeEvent);
|
||||
startResizeEvent.stopPropagation();
|
||||
if (!onResize) {
|
||||
return;
|
||||
}
|
||||
const { resizing, resizeEnd } = onResize();
|
||||
model.setFocus(false);
|
||||
selectNode(mouseDownEvent);
|
||||
selectNode(startResizeEvent as React.MouseEvent);
|
||||
playground.node.focus(); // 防止节点无法被删除
|
||||
|
||||
const startX = mouseDownEvent.clientX;
|
||||
const startY = mouseDownEvent.clientY;
|
||||
const { clientX: startX, clientY: startY } = MouseTouchEvent.getEventCoord(
|
||||
startResizeEvent as MouseEvent
|
||||
);
|
||||
|
||||
const handleMouseMove = (mouseMoveEvent: MouseEvent) => {
|
||||
const deltaX = mouseMoveEvent.clientX - startX;
|
||||
const deltaY = mouseMoveEvent.clientY - startY;
|
||||
const handleResizing = (mouseMoveEvent: MouseEvent | TouchEvent) => {
|
||||
const { clientX: moveX, clientY: moveY } = MouseTouchEvent.getEventCoord(mouseMoveEvent);
|
||||
const deltaX = moveX - startX;
|
||||
const deltaY = moveY - startY;
|
||||
const delta = getDelta?.({ x: deltaX, y: deltaY });
|
||||
if (!delta || !resizing) {
|
||||
return;
|
||||
@ -50,16 +54,22 @@ export const ResizeArea: FC<IResizeArea> = (props) => {
|
||||
resizing(delta);
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
const handleResizeEnd = () => {
|
||||
resizeEnd();
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', handleMouseUp);
|
||||
document.removeEventListener('click', handleMouseUp);
|
||||
document.removeEventListener('mousemove', handleResizing);
|
||||
document.removeEventListener('mouseup', handleResizeEnd);
|
||||
document.removeEventListener('click', handleResizeEnd);
|
||||
document.removeEventListener('touchmove', handleResizing);
|
||||
document.removeEventListener('touchend', handleResizeEnd);
|
||||
document.removeEventListener('touchcancel', handleResizeEnd);
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
document.addEventListener('click', handleMouseUp);
|
||||
document.addEventListener('mousemove', handleResizing);
|
||||
document.addEventListener('mouseup', handleResizeEnd);
|
||||
document.addEventListener('click', handleResizeEnd);
|
||||
document.addEventListener('touchmove', handleResizing, { passive: false });
|
||||
document.addEventListener('touchend', handleResizeEnd);
|
||||
document.addEventListener('touchcancel', handleResizeEnd);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -67,7 +77,8 @@ export const ResizeArea: FC<IResizeArea> = (props) => {
|
||||
className="workflow-comment-resize-area"
|
||||
style={style}
|
||||
data-flow-editor-selectable="false"
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseDown={handleResizeStart}
|
||||
onTouchStart={handleResizeStart}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -36,14 +36,17 @@ export const Comment = () => {
|
||||
async (mouseEvent: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setTooltipVisible(false);
|
||||
const canvasPosition = calcNodePosition(mouseEvent);
|
||||
// 创建节点
|
||||
// create comment node - 创建节点
|
||||
const node = document.createWorkflowNodeByType(WorkflowNodeType.Comment, canvasPosition);
|
||||
// 等待节点渲染
|
||||
// wait comment node render - 等待节点渲染
|
||||
await delay(16);
|
||||
// 选中节点
|
||||
// select comment node - 选中节点
|
||||
selectService.selectNode(node);
|
||||
// 开始拖拽
|
||||
dragService.startDragSelectedNodes(mouseEvent);
|
||||
// maybe touch event - 可能是触摸事件
|
||||
if (mouseEvent.detail !== 0) {
|
||||
// start drag -开始拖拽
|
||||
dragService.startDragSelectedNodes(mouseEvent);
|
||||
}
|
||||
},
|
||||
[selectService, calcNodePosition, document, dragService]
|
||||
);
|
||||
|
||||
@ -145,6 +145,12 @@ export class PlaygroundLayer extends Layer<PlaygroundLayerOptions> {
|
||||
// 这里必须监听 NORMAL_LAYER,该图层最先触发
|
||||
PipelineLayerPriority.NORMAL_LAYER
|
||||
),
|
||||
this.listenPlaygroundEvent('touchend', (e: TouchEvent) => {
|
||||
this.options.hoverService?.clearHovered();
|
||||
}),
|
||||
this.listenPlaygroundEvent('touchcancel', (e: TouchEvent) => {
|
||||
this.options.hoverService?.clearHovered();
|
||||
}),
|
||||
this.listenPlaygroundEvent(
|
||||
'mousedown',
|
||||
(e: MouseEvent) => {
|
||||
|
||||
@ -84,6 +84,12 @@ export const MinimapRender: React.FC<MinimapProps> = (props) => {
|
||||
onMouseLeave={() => {
|
||||
service.setActivate(false);
|
||||
}}
|
||||
onTouchStartCapture={() => {
|
||||
service.setActivate(true);
|
||||
}}
|
||||
onTouchEndCapture={() => {
|
||||
service.setActivate(false);
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -4,7 +4,7 @@ import { Disposable, DisposableCollection, IPoint, Rectangle } from '@flowgram.a
|
||||
import { FlowNodeEntity, FlowNodeTransformData } from '@flowgram.ai/document';
|
||||
import { FlowNodeBaseType } from '@flowgram.ai/document';
|
||||
import { FlowDocument } from '@flowgram.ai/document';
|
||||
import { EntityManager, PlaygroundConfigEntity } from '@flowgram.ai/core';
|
||||
import { EntityManager, MouseTouchEvent, PlaygroundConfigEntity } from '@flowgram.ai/core';
|
||||
|
||||
import type { MinimapRenderContext, MinimapServiceOptions, MinimapCanvasStyle } from './type';
|
||||
import { MinimapDraw } from './draw';
|
||||
@ -312,26 +312,29 @@ export class FlowMinimapService {
|
||||
private addEventListeners(): void {
|
||||
this.canvas.addEventListener('wheel', this.handleWheel);
|
||||
this.canvas.addEventListener('mousedown', this.handleStartDrag);
|
||||
this.canvas.addEventListener('touchstart', this.handleStartDrag, { passive: false });
|
||||
this.canvas.addEventListener('mousemove', this.handleCursor);
|
||||
}
|
||||
|
||||
private removeEventListeners(): void {
|
||||
this.canvas.removeEventListener('wheel', this.handleWheel);
|
||||
this.canvas.removeEventListener('mousedown', this.handleStartDrag);
|
||||
this.canvas.removeEventListener('touchstart', this.handleStartDrag);
|
||||
this.canvas.removeEventListener('mousemove', this.handleCursor);
|
||||
}
|
||||
|
||||
private handleWheel = (event: WheelEvent): void => {};
|
||||
|
||||
private handleStartDrag = (event: MouseEvent): void => {
|
||||
event.preventDefault();
|
||||
private handleStartDrag = (event: MouseEvent | TouchEvent): void => {
|
||||
MouseTouchEvent.preventDefault(event);
|
||||
event.stopPropagation();
|
||||
const renderContext = this.createRenderContext();
|
||||
const { viewRect, scale, offset } = renderContext;
|
||||
const canvasRect = this.canvas.getBoundingClientRect();
|
||||
const { clientX, clientY } = MouseTouchEvent.getEventCoord(event);
|
||||
const mousePoint: IPoint = {
|
||||
x: event.clientX - canvasRect.left,
|
||||
y: event.clientY - canvasRect.top,
|
||||
x: clientX - canvasRect.left,
|
||||
y: clientY - canvasRect.top,
|
||||
};
|
||||
|
||||
const viewRectOnCanvas = this.rectOnCanvas({
|
||||
@ -344,20 +347,26 @@ export class FlowMinimapService {
|
||||
}
|
||||
this.isDragging = true;
|
||||
this.dragStart = mousePoint;
|
||||
// click
|
||||
document.addEventListener('mousemove', this.handleDragging);
|
||||
document.addEventListener('mouseup', this.handleEndDrag);
|
||||
// touch
|
||||
document.addEventListener('touchmove', this.handleDragging, { passive: false });
|
||||
document.addEventListener('touchend', this.handleEndDrag);
|
||||
document.addEventListener('touchcancel', this.handleEndDrag);
|
||||
};
|
||||
|
||||
private handleDragging = (event: MouseEvent): void => {
|
||||
private handleDragging = (event: MouseEvent | TouchEvent): void => {
|
||||
if (!this.isDragging || !this.dragStart) return;
|
||||
event.preventDefault();
|
||||
MouseTouchEvent.preventDefault(event);
|
||||
event.stopPropagation();
|
||||
|
||||
const renderContext = this.createRenderContext();
|
||||
const { scale } = renderContext;
|
||||
const canvasRect = this.canvas.getBoundingClientRect();
|
||||
const mouseX = event.clientX - canvasRect.left;
|
||||
const mouseY = event.clientY - canvasRect.top;
|
||||
const { clientX, clientY } = MouseTouchEvent.getEventCoord(event);
|
||||
const mouseX = clientX - canvasRect.left;
|
||||
const mouseY = clientY - canvasRect.top;
|
||||
|
||||
const deltaX = (mouseX - this.dragStart.x) / scale;
|
||||
const deltaY = (mouseY - this.dragStart.y) / scale;
|
||||
@ -368,11 +377,16 @@ export class FlowMinimapService {
|
||||
this.render();
|
||||
};
|
||||
|
||||
private handleEndDrag = (event: MouseEvent): void => {
|
||||
event.preventDefault();
|
||||
private handleEndDrag = (event: MouseEvent | TouchEvent): void => {
|
||||
MouseTouchEvent.preventDefault(event);
|
||||
event.stopPropagation();
|
||||
// click
|
||||
document.removeEventListener('mousemove', this.handleDragging);
|
||||
document.removeEventListener('mouseup', this.handleEndDrag);
|
||||
// touch
|
||||
document.removeEventListener('touchmove', this.handleDragging);
|
||||
document.removeEventListener('touchend', this.handleEndDrag);
|
||||
document.removeEventListener('touchcancel', this.handleEndDrag);
|
||||
this.isDragging = false;
|
||||
this.dragStart = undefined;
|
||||
this.setActivate(this.isMouseInCanvas(event));
|
||||
@ -404,13 +418,14 @@ export class FlowMinimapService {
|
||||
}
|
||||
};
|
||||
|
||||
private isMouseInCanvas(event: MouseEvent): boolean {
|
||||
private isMouseInCanvas(event: MouseEvent | TouchEvent): boolean {
|
||||
const canvasRect = this.canvas.getBoundingClientRect();
|
||||
const { clientX, clientY } = MouseTouchEvent.getEventCoord(event);
|
||||
return (
|
||||
event.clientX >= canvasRect.left &&
|
||||
event.clientX <= canvasRect.right &&
|
||||
event.clientY >= canvasRect.top &&
|
||||
event.clientY <= canvasRect.bottom
|
||||
clientX >= canvasRect.left &&
|
||||
clientX <= canvasRect.right &&
|
||||
clientY >= canvasRect.top &&
|
||||
clientY <= canvasRect.bottom
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user