diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index a1dbaf1..7b403ab 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -14,13 +14,14 @@ import { } from './lib'; import { _board, _data, _opts, _config, _renderer, _element, _helper, _tempData, _draw, _coreEvent, - _mapper, _emitChangeScreen, _emitChangeData,_todo + _mapper, _emitChangeScreen, _emitChangeData, _todo } from './names'; import { getSelectedElements, updateElement, selectElementByIndex, getElement, getElementByIndex, selectElement, moveUpElement, moveDownElement, addElement, deleteElement, insertElementBefore, insertElementBeforeIndex, insertElementAfter, insertElementAfterIndex, } from './mixins/element'; -import { initEvent } from './mixins/event'; +// import { initEvent } from './mixins/event'; +import { Engine } from './lib/engine'; import { drawElementWrapper, drawAreaWrapper, drawElementListWrappers } from './lib/draw/wrapper' const { deepClone } = util.data; @@ -78,7 +79,9 @@ class Core { helper: this[_helper], element: this[_element] }); - initEvent(this); + // initEvent(this); + const engine = new Engine(this); + engine.init(); } [_draw]( diff --git a/packages/core/src/lib/engine.ts b/packages/core/src/lib/engine.ts index 2ed2194..20d5df2 100644 --- a/packages/core/src/lib/engine.ts +++ b/packages/core/src/lib/engine.ts @@ -1,5 +1,323 @@ +import { + TypePoint, TypeHelperWrapperControllerDirection,InterfaceHelperPlugin +} from '@idraw/types'; +import util from '@idraw/util'; +import { + _board, _data, _opts, _config, _renderer, _element, _helper, + _tempData, _draw, _coreEvent, _mapper, + _emitChangeScreen, _emitChangeData, +} from './../names'; +import { Mode, CursorStatus } from './../constant/static'; +import Core from './../index'; +const { time } = util; +const { deepClone } = util.data; + +// type Options = { +// ctx: TypeContext, +// helperCtx: TypeContext, +// } + + export class Engine { - constructor() { - + + private _plugins: InterfaceHelperPlugin[] = []; + private _core: Core; + + constructor(core: Core) { + this._core = core; } + + addPlugin(plugin: InterfaceHelperPlugin) { + this._plugins.push(plugin); + } + + init() { + initEvent(this._core); + } +} + +function initEvent(core: Core): void { + + if (core[_tempData].get('hasInited') === true) { + return; + } + + core[_board].on('hover', time.throttle(handleHover(core), 32)); + core[_board].on('leave', time.throttle(handleLeave(core), 32)); + core[_board].on('point', time.throttle(handleClick(core), 16)); + core[_board].on('doubleClick', handleDoubleClick(core)); + if (core[_tempData].get('onlyRender') === true) { + return; + } + core[_board].on('point', handlePoint(core)); + core[_board].on('moveStart', handleMoveStart(core)); + core[_board].on('move', time.throttle(handleMove(core), 16)); + core[_board].on('moveEnd', handleMoveEnd(core)); + + core[_renderer].on('drawFrame', () => { + core[_coreEvent].trigger('drawFrame', undefined); + }); + core[_renderer].on('drawFrameComplete', () => { + core[_coreEvent].trigger('drawFrameComplete', undefined); + }) + + core[_tempData].set('hasInited', true); +} + + +function handleDoubleClick(core: Core) { + return function ( point: TypePoint) { + const [index, uuid] = core[_element].isPointInElement(point, core[_data]); + if (index >= 0 && uuid) { + const elem = deepClone(core[_data].elements?.[index]); + if (elem?.operation?.invisible !== true) { + core[_coreEvent].trigger( + 'screenDoubleClickElement', + { index, uuid, element: deepClone(core[_data].elements?.[index])} + ); + } + } + core[_draw](); + } +} + + +function handlePoint(core: Core) { + return function(point: TypePoint): void { + if (!core[_mapper].isEffectivePoint(point)) { + return; + } + if (core[_helper].isPointInElementList(point, core[_data])) { + // Coontroll Element-List + core[_tempData].set('mode', Mode.SELECT_ELEMENT_LIST); + } else { + const { + uuid, selectedControllerDirection + } = core[_helper].isPointInElementWrapperController(point, core[_data]); + if (uuid && selectedControllerDirection) { + // Controll Element-Wrapper + core[_tempData].set('mode', Mode.SELECT_ELEMENT_WRAPPER_CONTROLLER); + core[_tempData].set('selectedControllerDirection', selectedControllerDirection); + core[_tempData].set('selectedUUID', uuid); + } else { + const [index, uuid] = core[_element].isPointInElement(point, core[_data]); + if (index >= 0 && core[_data].elements[index]?.operation?.invisible !== true) { + // Controll Element + core.selectElementByIndex(index, { useMode: true }); + if (typeof uuid === 'string' && core[_coreEvent].has('screenSelectElement')) { + core[_coreEvent].trigger( + 'screenSelectElement', + { index, uuid, element: deepClone(core[_data].elements?.[index])} + ); + core[_emitChangeScreen](); + } + core[_tempData].set('mode', Mode.SELECT_ELEMENT); + } else { + // Controll Area + core[_tempData].set('selectedUUIDList', []); + core[_tempData].set('selectedUUID', null); + core[_tempData].set('mode', Mode.SELECT_AREA); + } + } + } + + core[_draw](); + } +} + + +function handleClick(core: Core) { + return function(point: TypePoint): void { + const [index, uuid] = core[_element].isPointInElement(point, core[_data]); + if (index >= 0 && uuid) { + core[_coreEvent].trigger( + 'screenClickElement', + { index, uuid, element: deepClone(core[_data].elements?.[index])} + ); + } + core[_draw](); + } +} + +function handleMoveStart(core: Core) { + return function(point: TypePoint): void { + core[_tempData].set('prevPoint', point); + const uuid = core[_tempData].get('selectedUUID'); + + if (core[_tempData].get('mode') === Mode.SELECT_ELEMENT_LIST) { + // TODO + } else if (core[_tempData].get('mode') === Mode.SELECT_ELEMENT) { + if (typeof uuid === 'string' && core[_coreEvent].has('screenMoveElementStart')) { + core[_coreEvent].trigger('screenMoveElementStart', { + index: core[_element].getElementIndex(core[_data], uuid), + uuid, + x: point.x, + y: point.y + }); + } + } else if (core[_tempData].get('mode') === Mode.SELECT_AREA) { + core[_helper].startSelectArea(point); + } + } +} + + +function handleMove(core: Core) { + return function(point: TypePoint): void { + if (core[_tempData].get('mode') === Mode.SELECT_ELEMENT_LIST) { + dragElements(core, core[_tempData].get('selectedUUIDList'), point, core[_tempData].get('prevPoint')); + core[_draw](); + core[_tempData].set('cursorStatus', CursorStatus.DRAGGING); + } else if (typeof core[_tempData].get('selectedUUID') === 'string') { + if (core[_tempData].get('mode') === Mode.SELECT_ELEMENT) { + dragElements(core, [core[_tempData].get('selectedUUID') as string], point, core[_tempData].get('prevPoint')); + core[_draw](); + core[_tempData].set('cursorStatus', CursorStatus.DRAGGING); + } else if (core[_tempData].get('mode') === Mode.SELECT_ELEMENT_WRAPPER_CONTROLLER && core[_tempData].get('selectedControllerDirection')) { + transfromElement( + core, + core[_tempData].get('selectedUUID') as string, + point, + core[_tempData].get('prevPoint'), + core[_tempData].get('selectedControllerDirection') as TypeHelperWrapperControllerDirection + ); + core[_tempData].set('cursorStatus', CursorStatus.DRAGGING) + } + } else if (core[_tempData].get('mode') === Mode.SELECT_AREA) { + core[_helper].changeSelectArea(point); + core[_draw](); + } + core[_tempData].set('prevPoint', point) + } +} + +function dragElements(core: Core, uuids: string[], point: TypePoint, prevPoint: TypePoint|null): void { + if (!prevPoint) { + return; + } + uuids.forEach((uuid) => { + const idx = core[_helper].getElementIndexByUUID(uuid); + if (idx === null) return; + const elem = core[_data].elements[idx]; + if (elem?.operation?.lock !== true && elem?.operation?.invisible !== true) { + core[_element].dragElement(core[_data], uuid, point, prevPoint, core[_board].getContext().getTransform().scale); + } + }); + core[_draw](); +} + + +function handleMoveEnd(core: Core) { + return function (point: TypePoint): void { + const uuid = core[_tempData].get('selectedUUID'); + if (typeof uuid === 'string') { + const index = core[_element].getElementIndex(core[_data], uuid); + const elem = core[_data].elements[index]; + if (elem) { + if (core[_coreEvent].has('screenMoveElementEnd')) { + core[_coreEvent].trigger('screenMoveElementEnd', { + index, + uuid, + x: point.x, + y: point.y + }); + } + if (core[_coreEvent].has('screenChangeElement')) { + core[_coreEvent].trigger('screenChangeElement', { + index, + uuid, + width: elem.w, + height: elem.h, + angle: elem.angle || 0 + }); + } + core[_emitChangeData](); + } + } else if (core[_tempData].get('mode') === Mode.SELECT_AREA) { + const uuids = core[_helper].calcSelectedElements(core[_data]); + if (uuids.length > 0) { + core[_tempData].set('selectedUUIDList', uuids); + core[_tempData].set('selectedUUID', null); + } else { + core[_tempData].set('mode', Mode.NULL); + } + core[_helper].clearSelectedArea(); + core[_draw](); + } + + if (core[_tempData].get('mode') !== Mode.SELECT_ELEMENT) { + core[_tempData].set('selectedUUID', null); + } + core[_tempData].set('cursorStatus', CursorStatus.NULL); + core[_tempData].set('mode', Mode.NULL); + } +} + +function handleHover(core: Core) { + return function (point: TypePoint): void { + let isMouseOverElement: boolean = false; + + if (core[_tempData].get('mode') === Mode.SELECT_AREA) { + if (core[_tempData].get('onlyRender') !== true) core[_board].resetCursor(); + } else if (core[_tempData].get('cursorStatus') === CursorStatus.NULL) { + const { cursor, elementUUID } = core[_mapper].judgePointCursor(point, core[_data]); + if (core[_tempData].get('onlyRender') !== true) core[_board].setCursor(cursor); + if (elementUUID) { + const index: number | null = core[_helper].getElementIndexByUUID(elementUUID); + if (index !== null && index >= 0) { + const elem = core[_data].elements[index]; + if (elem?.operation?.lock === true || elem?.operation?.invisible === true) { + core[_board].resetCursor(); + return; + } + if (core[_tempData].get('hoverUUID') !== elem.uuid) { + const preIndex = core[_helper].getElementIndexByUUID(core[_tempData].get('hoverUUID') || ''); + if (preIndex !== null && core[_data].elements[preIndex]) { + core[_coreEvent].trigger('mouseLeaveElement', { + uuid: core[_tempData].get('hoverUUID'), + index: preIndex, + element: core[_data].elements[preIndex] + }); + } + } + if (elem) { + core[_coreEvent].trigger('mouseOverElement', { uuid: elem.uuid, index, element: elem, }); + core[_tempData].set('hoverUUID', elem.uuid); + isMouseOverElement = true; + } + } + } + } + if (isMouseOverElement !== true && core[_tempData].get('hoverUUID') !== null) { + const uuid = core[_tempData].get('hoverUUID'); + const index: number | null = core[_helper].getElementIndexByUUID(uuid || ''); + if (index !== null) core[_coreEvent].trigger('mouseLeaveElement', { uuid, index, element: core[_data].elements[index] }) + core[_tempData].set('hoverUUID', null); + } + if (core[_coreEvent].has('mouseOverScreen')) core[_coreEvent].trigger('mouseOverScreen', point); + } +} + +function handleLeave(core: Core) { + return function(): void { + if (core[_coreEvent].has('mouseLeaveScreen')) { + core[_coreEvent].trigger('mouseLeaveScreen', undefined); + } + } +} + +function transfromElement( + core: Core, + uuid: string, point: TypePoint, prevPoint: TypePoint|null, direction: TypeHelperWrapperControllerDirection +): null | { + width: number, + height: number, + angle: number, +} { + if (!prevPoint) { + return null; + } + const result = core[_element].transformElement(core[_data], uuid, point, prevPoint, core[_board].getContext().getTransform().scale, direction); + core[_draw](); + return result; } \ No newline at end of file