refactor: split engine from mixin/event for @idraw/core

This commit is contained in:
chenshenhai 2021-11-26 20:48:31 +08:00
parent 78a47280ac
commit e17195ee5e
10 changed files with 339 additions and 593 deletions

View file

@ -62,8 +62,8 @@ const data = {
borderColor: "#bd0b64",
},
operation: {
disbaleScale: true,
disbaleRotate: true,
// disbaleScale: true,
// disbaleRotate: true,
}
},
],

View file

@ -9,12 +9,12 @@ import Renderer from '@idraw/renderer';
import is, { TypeIs } from './lib/is';
import check, { TypeCheck } from './lib/check';
import {
Element, Helper, Mapper, mergeConfig, CoreEvent,
Element, mergeConfig, CoreEvent,
TypeCoreEventArgMap, parseData, TempData, diffElementResourceChangeList,
} from './lib';
import {
_board, _data, _opts, _config, _renderer, _element, _helper, _tempData, _draw, _coreEvent,
_mapper, _emitChangeScreen, _emitChangeData, _todo
_board, _data, _opts, _config, _renderer, _element, _tempData, _draw, _coreEvent,
_mapper, _emitChangeScreen, _emitChangeData, _engine,
} from './names';
import { getSelectedElements, updateElement, selectElementByIndex, getElement, getElementByIndex,
selectElement, moveUpElement, moveDownElement, addElement, deleteElement,
@ -33,10 +33,9 @@ class Core {
private [_config]: TypeConfigStrict;
private [_renderer]: Renderer;
private [_element]: Element;
private [_helper]: Helper;
private [_mapper]: Mapper;
private [_coreEvent]: CoreEvent = new CoreEvent();
private [_tempData]: TempData = new TempData();
private [_engine]: Engine;
static is: TypeIs = is;
static check: TypeCheck = check;
@ -44,7 +43,6 @@ class Core {
constructor(mount: HTMLDivElement, opts: TypeCoreOptions, config?: TypeConfig) {
this[_data] = { elements: [] };
this[_opts] = opts;
this[_tempData].set('onlyRender', opts.onlyRender === true)
this[_config] = mergeConfig(config || {});
this[_board] = new Board(mount, {
...this[_opts],
@ -57,7 +55,7 @@ class Core {
this[_renderer] = new Renderer();
const drawFrame = () => {
const helperCtx = this[_board].getHelperContext();
const helperConfig = this[_helper].getConfig();
const helperConfig = this[_engine].getHelperConfig();
this[_board].clear();
const { contextWidth, contextHeight, devicePixelRatio } = this[_opts];
helperCtx.clearRect(0, 0, contextWidth * devicePixelRatio, contextHeight * devicePixelRatio)
@ -73,15 +71,27 @@ class Core {
drawFrame();
})
this[_element] = new Element(this[_board].getContext());
this[_helper] = new Helper(this[_board], this[_config]);
this[_mapper] = new Mapper({
this[_engine] = new Engine({
coreEvent: this[_coreEvent],
board: this[_board],
helper: this[_helper],
element: this[_element]
element: this[_element],
config: this[_config],
drawFeekback: this[_draw].bind(this),
getDataFeekback: () => this[_data],
selectElementByIndex: this.selectElementByIndex.bind(this),
emitChangeScreen: this[_emitChangeScreen].bind(this),
emitChangeData: this[_emitChangeData].bind(this),
});
// initEvent(this);
const engine = new Engine(this);
engine.init();
this[_engine].init();
this[_renderer].on('drawFrame', () => {
this[_coreEvent].trigger('drawFrame', undefined);
});
this[_renderer].on('drawFrameComplete', () => {
this[_coreEvent].trigger('drawFrameComplete', undefined);
})
this[_tempData].set('hasInited', true);
}
[_draw](
@ -89,18 +99,12 @@ class Core {
resourceChangeUUIDs?: string[],
}
): void {
const transfrom = this[_board].getTransform();
this[_helper].updateConfig(this[_data], {
this[_engine].updateHelperConfig({
width: this[_opts].width,
height: this[_opts].height,
canScroll: this[_config]?.scrollWrapper?.use === true,
selectedUUID: this[_tempData].get('selectedUUID'),
selectedUUIDList: this[_tempData].get('selectedUUIDList'),
devicePixelRatio: this[_opts].devicePixelRatio,
scale: transfrom.scale,
scrollX: transfrom.scrollX,
scrollY: transfrom.scrollY,
});
this[_renderer].thaw();
this[_renderer].render(this[_board].getContext(), this[_data], {
changeResourceUUIDs: opts?.resourceChangeUUIDs || []
@ -214,7 +218,6 @@ class Core {
clearOperation() {
this[_tempData].clear();
this[_tempData].set('onlyRender', this[_opts].onlyRender === true)
this[_draw]();
}
@ -234,22 +237,6 @@ class Core {
return this[_board].pointContextToScreen(p);
}
setOnlyRender() {
this[_tempData].set('onlyRender', true);
}
cancelOnlyRender() {
this[_tempData].set('onlyRender', false);
}
// stopRender() {
// this[_renderer].stop();
// }
// restartRender() {
// this[_renderer].restart();
// }
__getBoardContext(): TypeContext {
return this[_board].getContext();
}
@ -267,9 +254,6 @@ class Core {
if (this[_coreEvent].has('changeScreen')) {
this[_coreEvent].trigger('changeScreen', {
...this.getScreenTransform(),
// ...{
// selectedElementUUID: this[_tempData].get('selectedUUID')
// }
});
}
}
@ -279,12 +263,6 @@ class Core {
this[_coreEvent].trigger('changeData', deepClone(this[_data]));
}
}
[_todo]() {
// TODO
// To avoid TS error
console.log(this[_mapper]);
}
}
export default Core;

View file

@ -0,0 +1,49 @@
import { TypeHelperWrapperControllerDirection, TypePoint } from '@idraw/types';
import { Mode, CursorStatus } from '../constant/static';
type TempDataDesc = {
hasInited: boolean;
mode: Mode,
cursorStatus: CursorStatus
selectedUUID: string | null,
selectedUUIDList: string[],
hoverUUID: string | null,
selectedControllerDirection: TypeHelperWrapperControllerDirection | null,
hoverControllerDirection: TypeHelperWrapperControllerDirection | null,
prevPoint: TypePoint | null,
}
function createData(): TempDataDesc {
return {
hasInited: false,
mode: Mode.NULL,
cursorStatus: CursorStatus.NULL,
selectedUUID: null,
selectedUUIDList: [],
hoverUUID: null,
selectedControllerDirection: null,
hoverControllerDirection: null,
prevPoint: null,
}
}
export class TempData {
private _temp: TempDataDesc
constructor() {
this._temp = createData();
}
set<T extends keyof TempDataDesc >(name: T, value: TempDataDesc[T]) {
this._temp[name] = value;
}
get<T extends keyof TempDataDesc >(name: T): TempDataDesc[T] {
return this._temp[name];
}
clear() {
this._temp = createData();
}
}

View file

@ -1,229 +1,283 @@
import {
TypePoint, TypeHelperWrapperControllerDirection,InterfaceHelperPlugin
TypePoint, TypeHelperWrapperControllerDirection,InterfaceHelperPlugin,
TypeConfigStrict, TypeData, TypeHelperConfig,
} 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 Board from '@idraw/board';
import { Mode, CursorStatus } from './../constant/static';
import Core from './../index';
import { TempData } from './engine-temp';
import { Helper } from './helper';
import { Mapper } from './mapper';
import { Element } from './element';
import { CoreEvent } from './core-event';
const { time } = util;
const { deepClone } = util.data;
// type Options = {
// ctx: TypeContext,
// helperCtx: TypeContext,
// }
type Options = {
coreEvent: CoreEvent,
board: Board,
element: Element,
config: TypeConfigStrict,
drawFeekback: () => void,
getDataFeekback: () => TypeData;
selectElementByIndex: (index: number, opts?: { useMode?: boolean }) => void,
emitChangeScreen: () => void,
emitChangeData: () => void,
}
export class Engine {
private _plugins: InterfaceHelperPlugin[] = [];
private _core: Core;
private _opts: Options;
private _mapper: Mapper;
constructor(core: Core) {
this._core = core;
public temp: TempData;
public helper: Helper;
constructor(opts: Options) {
const { board, config, element } = opts;
const helper = new Helper(board, config);
this._opts = opts;
this.temp = new TempData();
this.helper = helper;
this._mapper = new Mapper({ board, helper, element });
}
addPlugin(plugin: InterfaceHelperPlugin) {
this._plugins.push(plugin);
}
getHelperConfig(): TypeHelperConfig {
return this.helper.getConfig();
}
updateHelperConfig(opts: {
width: number, height: number, devicePixelRatio: number
}) {
const { board, getDataFeekback, config } = this._opts;
const data = getDataFeekback();
const transform = board.getTransform();
this.helper.updateConfig(data,{
width: opts.width,
height: opts.height,
devicePixelRatio: opts.devicePixelRatio,
canScroll: config?.scrollWrapper?.use === true,
selectedUUID: this.temp.get('selectedUUID'),
selectedUUIDList: this.temp.get('selectedUUIDList'),
scale: transform.scale,
scrollX: transform.scrollX,
scrollY: transform.scrollY,
})
}
init() {
initEvent(this._core);
this._initEvent();
}
}
function initEvent(core: Core): void {
if (core[_tempData].get('hasInited') === true) {
return;
private _initEvent(): void {
if (this.temp.get('hasInited') === true) {
return;
}
const { board } = this._opts;
board.on('hover', time.throttle(this._handleHover.bind(this), 32));
board.on('leave', time.throttle(this._handleLeave.bind(this), 32));
board.on('point', time.throttle(this._handleClick.bind(this), 16));
board.on('doubleClick', this._handleDoubleClick.bind(this));
board.on('point', this._handlePoint.bind(this));
board.on('moveStart', this._handleMoveStart.bind(this));
board.on('move', time.throttle(this._handleMove.bind(this), 16));
board.on('moveEnd', this._handleMoveEnd.bind(this));
}
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]);
private _handleDoubleClick (point: TypePoint) {
const { element, getDataFeekback, drawFeekback, coreEvent } = this._opts;
const data = getDataFeekback();
const [index, uuid] = element.isPointInElement(point, data);
if (index >= 0 && uuid) {
const elem = deepClone(core[_data].elements?.[index]);
const elem = deepClone(data.elements?.[index]);
if (elem?.operation?.invisible !== true) {
core[_coreEvent].trigger(
coreEvent.trigger(
'screenDoubleClickElement',
{ index, uuid, element: deepClone(core[_data].elements?.[index])}
{ index, uuid, element: deepClone(data.elements?.[index])}
);
}
}
core[_draw]();
drawFeekback();
}
}
function handlePoint(core: Core) {
return function(point: TypePoint): void {
if (!core[_mapper].isEffectivePoint(point)) {
_handlePoint(point: TypePoint): void {
if (!this._mapper.isEffectivePoint(point)) {
return;
}
if (core[_helper].isPointInElementList(point, core[_data])) {
const {
element, getDataFeekback, selectElementByIndex, coreEvent,
emitChangeScreen, drawFeekback
} = this._opts;
const helper = this.helper;
const data = getDataFeekback();
if (helper.isPointInElementList(point, data)) {
// Coontroll Element-List
core[_tempData].set('mode', Mode.SELECT_ELEMENT_LIST);
this.temp.set('mode', Mode.SELECT_ELEMENT_LIST);
} else {
const {
uuid, selectedControllerDirection
} = core[_helper].isPointInElementWrapperController(point, core[_data]);
} = helper.isPointInElementWrapperController(point, 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);
this.temp.set('mode', Mode.SELECT_ELEMENT_WRAPPER_CONTROLLER);
this.temp.set('selectedControllerDirection', selectedControllerDirection);
this.temp.set('selectedUUID', uuid);
} else {
const [index, uuid] = core[_element].isPointInElement(point, core[_data]);
if (index >= 0 && core[_data].elements[index]?.operation?.invisible !== true) {
const [index, uuid] = element.isPointInElement(point, data);
if (index >= 0 && data.elements[index]?.operation?.invisible !== true) {
// Controll Element
core.selectElementByIndex(index, { useMode: true });
if (typeof uuid === 'string' && core[_coreEvent].has('screenSelectElement')) {
core[_coreEvent].trigger(
selectElementByIndex(index, { useMode: true });
if (typeof uuid === 'string' && coreEvent.has('screenSelectElement')) {
coreEvent.trigger(
'screenSelectElement',
{ index, uuid, element: deepClone(core[_data].elements?.[index])}
{ index, uuid, element: deepClone(data.elements?.[index])}
);
core[_emitChangeScreen]();
emitChangeScreen();
}
core[_tempData].set('mode', Mode.SELECT_ELEMENT);
this.temp.set('mode', Mode.SELECT_ELEMENT);
} else {
// Controll Area
core[_tempData].set('selectedUUIDList', []);
core[_tempData].set('selectedUUID', null);
core[_tempData].set('mode', Mode.SELECT_AREA);
this.temp.set('selectedUUIDList', []);
this.temp.set('selectedUUID', null);
this.temp.set('mode', Mode.SELECT_AREA);
}
}
}
core[_draw]();
drawFeekback();
}
}
function handleClick(core: Core) {
return function(point: TypePoint): void {
const [index, uuid] = core[_element].isPointInElement(point, core[_data]);
private _handleClick(point: TypePoint): void {
const {
element, getDataFeekback, coreEvent, drawFeekback
} = this._opts;
const data = getDataFeekback();
const [index, uuid] = element.isPointInElement(point, data);
if (index >= 0 && uuid) {
core[_coreEvent].trigger(
coreEvent.trigger(
'screenClickElement',
{ index, uuid, element: deepClone(core[_data].elements?.[index])}
{ index, uuid, element: deepClone(data.elements?.[index])}
);
}
core[_draw]();
drawFeekback();
}
}
function handleMoveStart(core: Core) {
return function(point: TypePoint): void {
core[_tempData].set('prevPoint', point);
const uuid = core[_tempData].get('selectedUUID');
private _handleMoveStart(point: TypePoint): void {
const {
element, getDataFeekback, coreEvent
} = this._opts;
const data = getDataFeekback();
const helper = this.helper;
this.temp.set('prevPoint', point);
const uuid = this.temp.get('selectedUUID');
if (core[_tempData].get('mode') === Mode.SELECT_ELEMENT_LIST) {
if (this.temp.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),
} else if (this.temp.get('mode') === Mode.SELECT_ELEMENT) {
if (typeof uuid === 'string' && coreEvent.has('screenMoveElementStart')) {
coreEvent.trigger('screenMoveElementStart', {
index: element.getElementIndex(data, uuid),
uuid,
x: point.x,
y: point.y
});
}
} else if (core[_tempData].get('mode') === Mode.SELECT_AREA) {
core[_helper].startSelectArea(point);
} else if (this.temp.get('mode') === Mode.SELECT_AREA) {
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,
private _handleMove(point: TypePoint): void {
const { drawFeekback } = this._opts;
const helper = this.helper;
if (this.temp.get('mode') === Mode.SELECT_ELEMENT_LIST) {
this._dragElements(this.temp.get('selectedUUIDList'), point, this.temp.get('prevPoint'));
drawFeekback();
this.temp.set('cursorStatus', CursorStatus.DRAGGING);
} else if (typeof this.temp.get('selectedUUID') === 'string') {
if (this.temp.get('mode') === Mode.SELECT_ELEMENT) {
this._dragElements([this.temp.get('selectedUUID') as string], point, this.temp.get('prevPoint'));
drawFeekback();
this.temp.set('cursorStatus', CursorStatus.DRAGGING);
} else if (this.temp.get('mode') === Mode.SELECT_ELEMENT_WRAPPER_CONTROLLER && this.temp.get('selectedControllerDirection')) {
this._transfromElement(
this.temp.get('selectedUUID') as string,
point,
core[_tempData].get('prevPoint'),
core[_tempData].get('selectedControllerDirection') as TypeHelperWrapperControllerDirection
this.temp.get('prevPoint'),
this.temp.get('selectedControllerDirection') as TypeHelperWrapperControllerDirection
);
core[_tempData].set('cursorStatus', CursorStatus.DRAGGING)
this.temp.set('cursorStatus', CursorStatus.DRAGGING)
}
} else if (core[_tempData].get('mode') === Mode.SELECT_AREA) {
core[_helper].changeSelectArea(point);
core[_draw]();
} else if (this.temp.get('mode') === Mode.SELECT_AREA) {
helper.changeSelectArea(point);
drawFeekback();
}
core[_tempData].set('prevPoint', point)
this.temp.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);
private _dragElements(uuids: string[], point: TypePoint, prevPoint: TypePoint|null): void {
if (!prevPoint) {
return;
}
});
core[_draw]();
}
const {
board, element, getDataFeekback, drawFeekback
} = this._opts;
const data = getDataFeekback();
const helper = this.helper;
uuids.forEach((uuid) => {
const idx = helper.getElementIndexByUUID(uuid);
if (idx === null) return;
const elem = data.elements[idx];
if (elem?.operation?.lock !== true && elem?.operation?.invisible !== true) {
element.dragElement(data, uuid, point, prevPoint, board.getContext().getTransform().scale);
}
});
drawFeekback();
}
private _transfromElement(
uuid: string, point: TypePoint, prevPoint: TypePoint|null, direction: TypeHelperWrapperControllerDirection
): null | { width: number, height: number, angle: number, } {
if (!prevPoint) {
return null;
}
const {
board, element, getDataFeekback, drawFeekback
} = this._opts;
const data = getDataFeekback();
const result = element.transformElement(data, uuid, point, prevPoint, board.getContext().getTransform().scale, direction);
drawFeekback();
return result;
}
function handleMoveEnd(core: Core) {
return function (point: TypePoint): void {
const uuid = core[_tempData].get('selectedUUID');
private _handleMoveEnd(point: TypePoint): void {
const {
element, getDataFeekback, coreEvent, drawFeekback, emitChangeData
} = this._opts;
const data = getDataFeekback();
const helper = this.helper;
const uuid = this.temp.get('selectedUUID');
if (typeof uuid === 'string') {
const index = core[_element].getElementIndex(core[_data], uuid);
const elem = core[_data].elements[index];
const index = element.getElementIndex(data, uuid);
const elem = data.elements[index];
if (elem) {
if (core[_coreEvent].has('screenMoveElementEnd')) {
core[_coreEvent].trigger('screenMoveElementEnd', {
if (coreEvent.has('screenMoveElementEnd')) {
coreEvent.trigger('screenMoveElementEnd', {
index,
uuid,
x: point.x,
y: point.y
});
}
if (core[_coreEvent].has('screenChangeElement')) {
core[_coreEvent].trigger('screenChangeElement', {
if (coreEvent.has('screenChangeElement')) {
coreEvent.trigger('screenChangeElement', {
index,
uuid,
width: elem.w,
@ -231,93 +285,82 @@ function handleMoveEnd(core: Core) {
angle: elem.angle || 0
});
}
core[_emitChangeData]();
emitChangeData();
}
} else if (core[_tempData].get('mode') === Mode.SELECT_AREA) {
const uuids = core[_helper].calcSelectedElements(core[_data]);
} else if (this.temp.get('mode') === Mode.SELECT_AREA) {
const uuids = helper.calcSelectedElements(data);
if (uuids.length > 0) {
core[_tempData].set('selectedUUIDList', uuids);
core[_tempData].set('selectedUUID', null);
this.temp.set('selectedUUIDList', uuids);
this.temp.set('selectedUUID', null);
} else {
core[_tempData].set('mode', Mode.NULL);
this.temp.set('mode', Mode.NULL);
}
core[_helper].clearSelectedArea();
core[_draw]();
helper.clearSelectedArea();
drawFeekback();
}
if (core[_tempData].get('mode') !== Mode.SELECT_ELEMENT) {
core[_tempData].set('selectedUUID', null);
if (this.temp.get('mode') !== Mode.SELECT_ELEMENT) {
this.temp.set('selectedUUID', null);
}
core[_tempData].set('cursorStatus', CursorStatus.NULL);
core[_tempData].set('mode', Mode.NULL);
this.temp.set('cursorStatus', CursorStatus.NULL);
this.temp.set('mode', Mode.NULL);
}
}
function handleHover(core: Core) {
return function (point: TypePoint): void {
private _handleHover(point: TypePoint): void {
let isMouseOverElement: boolean = false;
const { board, getDataFeekback, coreEvent, } = this._opts;
const data = getDataFeekback();
const helper = this.helper;
const mapper = this._mapper;
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 (this.temp.get('mode') === Mode.SELECT_AREA) {
board.resetCursor();
} else if (this.temp.get('cursorStatus') === CursorStatus.NULL) {
const { cursor, elementUUID } = mapper.judgePointCursor(point, data);
board.setCursor(cursor);
if (elementUUID) {
const index: number | null = core[_helper].getElementIndexByUUID(elementUUID);
const index: number | null = helper.getElementIndexByUUID(elementUUID);
if (index !== null && index >= 0) {
const elem = core[_data].elements[index];
const elem = data.elements[index];
if (elem?.operation?.lock === true || elem?.operation?.invisible === true) {
core[_board].resetCursor();
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'),
if (this.temp.get('hoverUUID') !== elem.uuid) {
const preIndex = helper.getElementIndexByUUID(this.temp.get('hoverUUID') || '');
if (preIndex !== null && data.elements[preIndex]) {
coreEvent.trigger('mouseLeaveElement', {
uuid: this.temp.get('hoverUUID'),
index: preIndex,
element: core[_data].elements[preIndex]
element: data.elements[preIndex]
});
}
}
if (elem) {
core[_coreEvent].trigger('mouseOverElement', { uuid: elem.uuid, index, element: elem, });
core[_tempData].set('hoverUUID', elem.uuid);
coreEvent.trigger('mouseOverElement', { uuid: elem.uuid, index, element: elem, });
this.temp.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 (isMouseOverElement !== true && this.temp.get('hoverUUID') !== null) {
const uuid = this.temp.get('hoverUUID');
const index: number | null = helper.getElementIndexByUUID(uuid || '');
if (index !== null) coreEvent.trigger('mouseLeaveElement', { uuid, index, element: data.elements[index] })
this.temp.set('hoverUUID', null);
}
if (core[_coreEvent].has('mouseOverScreen')) core[_coreEvent].trigger('mouseOverScreen', point);
if (coreEvent.has('mouseOverScreen')) coreEvent.trigger('mouseOverScreen', point);
}
}
function handleLeave(core: Core) {
return function(): void {
if (core[_coreEvent].has('mouseLeaveScreen')) {
core[_coreEvent].trigger('mouseLeaveScreen', undefined);
private _handleLeave(): void {
const { coreEvent } = this._opts;
if (coreEvent.has('mouseLeaveScreen')) {
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;
}
}

View file

@ -121,13 +121,13 @@ export class Helper implements TypeHelper {
hoverDirectionNames = hoverDirectionNames.slice(-angleMoveNum).concat(hoverDirectionNames.slice(0, -angleMoveNum))
}
rotateContext(ctx, wrapper.translate, wrapper.radian || 0, () => {
for (let i = 0; i < controllers.length; i ++) {
const controller = controllers[i];
if (controller.invisible === true) {
continue;
}
ctx.beginPath();
ctx.arc(controller.x, controller.y, wrapper.controllerSize, 0, Math.PI * 2);
ctx.closePath();
@ -141,6 +141,7 @@ export class Helper implements TypeHelper {
}
}
});
if (selectedControllerDirection === null) {
const controller = wrapper.controllers.rotate;
if (controller.invisible !== true) {
@ -155,6 +156,7 @@ export class Helper implements TypeHelper {
});
}
}
return {uuid, selectedControllerDirection, hoverControllerDirection, directIndex};
}

View file

@ -47,7 +47,6 @@ export class Mapper {
return { cursor, elementUUID};
}
const { uuid, hoverControllerDirection } = this[_helper].isPointInElementWrapperController(p, data);
const direction = hoverControllerDirection;
if (uuid && direction) {
switch (direction) {

View file

@ -1,31 +1,10 @@
import { TypeHelperWrapperControllerDirection, TypePoint } from '@idraw/types';
import { Mode, CursorStatus } from './../constant/static';
type TempDataDesc = {
hasInited: boolean;
onlyRender: boolean;
mode: Mode,
cursorStatus: CursorStatus
selectedUUID: string | null,
selectedUUIDList: string[],
hoverUUID: string | null,
selectedControllerDirection: TypeHelperWrapperControllerDirection | null,
hoverControllerDirection: TypeHelperWrapperControllerDirection | null,
prevPoint: TypePoint | null,
}
function createData(): TempDataDesc {
return {
onlyRender: false,
hasInited: false,
mode: Mode.NULL,
cursorStatus: CursorStatus.NULL,
selectedUUID: null,
selectedUUIDList: [],
hoverUUID: null,
selectedControllerDirection: null,
hoverControllerDirection: null,
prevPoint: null,
}
}

View file

@ -3,7 +3,7 @@ import {
} from '@idraw/types';
import util from '@idraw/util';
import {
_board, _data, _opts, _config, _renderer, _element, _helper,
_board, _data, _opts, _config, _renderer, _element, _engine,
_tempData, _draw, _coreEvent, _emitChangeScreen, _emitChangeData,
} from './../names';
import { diffElementResourceChange } from './../lib/diff';
@ -17,14 +17,14 @@ const { createUUID } = util.uuid;
export function getSelectedElements(core: Core): TypeElement<keyof TypeElemDesc>[] {
const elems: TypeElement<keyof TypeElemDesc>[] = [];
let list: string[] = [];
const uuid = core[_tempData].get('selectedUUID');
const uuid = core[_engine].temp.get('selectedUUID');
if (typeof uuid === 'string' && uuid) {
list.push(uuid);
} else {
list = core[_tempData].get('selectedUUIDList');
list = core[_engine].temp.get('selectedUUIDList');
}
list.forEach((uuid) => {
const index = core[_helper].getElementIndexByUUID(uuid);
const index = core[_engine].helper.getElementIndexByUUID(uuid);
if (index !== null && index >= 0) {
const elem = core[_data]?.elements[index];
if (elem) elems.push(elem);
@ -35,7 +35,7 @@ export function getSelectedElements(core: Core): TypeElement<keyof TypeElemDesc>
export function getElement(core: Core, uuid: string): TypeElement<keyof TypeElemDesc>|null {
let elem: TypeElement<keyof TypeElemDesc>|null = null;
const index = core[_helper].getElementIndexByUUID(uuid);
const index = core[_engine].helper.getElementIndexByUUID(uuid);
if (index !== null && core[_data].elements[index]) {
elem = deepClone(core[_data].elements[index]);
}
@ -69,17 +69,16 @@ export function updateElement(core: Core, elem: TypeElement<keyof TypeElemDesc>)
}
export function selectElementByIndex(core: Core, index: number, opts?: { useMode?: boolean }): void {
if (core[_tempData].get('onlyRender') === true) return;
if (core[_data].elements[index]) {
const uuid = core[_data].elements[index].uuid;
if (opts?.useMode === true) {
core[_tempData].set('mode', Mode.SELECT_ELEMENT);
core[_engine].temp.set('mode', Mode.SELECT_ELEMENT);
} else {
core[_tempData].set('mode', Mode.NULL);
core[_engine].temp.set('mode', Mode.NULL);
}
if (typeof uuid === 'string') {
core[_tempData].set('selectedUUID', uuid);
core[_tempData].set('selectedUUIDList', []);
core[_engine].temp.set('selectedUUID', uuid);
core[_engine].temp.set('selectedUUIDList', []);
}
core[_draw]();
}
@ -87,16 +86,14 @@ export function selectElementByIndex(core: Core, index: number, opts?: { useMode
export function selectElement(core: Core, uuid: string, opts?: { useMode?: boolean }): void {
if (core[_tempData].get('onlyRender') === true) return;
const index = core[_helper].getElementIndexByUUID(uuid);
const index = core[_engine].helper.getElementIndexByUUID(uuid);
if (typeof index === 'number' && index >= 0) {
core.selectElementByIndex(index, opts);
}
}
export function moveUpElement(core: Core, uuid: string): void {
// if (this[_onlyRender] === true) return;
const index = core[_helper].getElementIndexByUUID(uuid);
const index = core[_engine].helper.getElementIndexByUUID(uuid);
if (typeof index === 'number' && index >= 0 && index < core[_data].elements.length - 1) {
const temp = core[_data].elements[index];
core[_data].elements[index] = core[_data].elements[index + 1];
@ -107,8 +104,7 @@ export function moveUpElement(core: Core, uuid: string): void {
}
export function moveDownElement(core: Core, uuid: string): void {
// if (this[_onlyRender] === true) return;
const index = core[_helper].getElementIndexByUUID(uuid);
const index = core[_engine].helper.getElementIndexByUUID(uuid);
if (typeof index === 'number' && index > 0 && index < core[_data].elements.length) {
const temp = core[_data].elements[index];
core[_data].elements[index] = core[_data].elements[index - 1];
@ -120,7 +116,6 @@ export function moveDownElement(core: Core, uuid: string): void {
export function addElement(core: Core, elem: TypeElementBase<keyof TypeElemDesc>): string | null {
// if (this[_onlyRender] === true) return null;
const _elem = deepClone(elem);
_elem.uuid = createUUID();
core[_data].elements.push(_elem);
@ -130,7 +125,6 @@ export function addElement(core: Core, elem: TypeElementBase<keyof TypeElemDesc>
}
export function deleteElement(core: Core, uuid: string) {
// if (this[_onlyRender] === true) return;
const index = core[_element].getElementIndex(core[_data], uuid);
if (index >= 0) {
core[_data].elements.splice(index, 1);
@ -140,7 +134,7 @@ export function deleteElement(core: Core, uuid: string) {
}
export function insertElementBefore(core: Core, elem: TypeElementBase<keyof TypeElemDesc>, beforeUUID: string) {
const index = core[_helper].getElementIndexByUUID(beforeUUID);
const index = core[_engine].helper.getElementIndexByUUID(beforeUUID);
if (index !== null) {
return core.insertElementBeforeIndex(elem, index);
}
@ -162,7 +156,7 @@ export function insertElementBeforeIndex(core: Core, elem: TypeElementBase<keyof
export function insertElementAfter(core: Core, elem: TypeElementBase<keyof TypeElemDesc>, beforeUUID: string) {
const index = core[_helper].getElementIndexByUUID(beforeUUID);
const index = core[_engine].helper.getElementIndexByUUID(beforeUUID);
if (index !== null) {
return core.insertElementAfterIndex(elem, index);
}

View file

@ -1,298 +0,0 @@
import { TypePoint, TypeHelperWrapperControllerDirection } from '@idraw/types';
import util from '@idraw/util';
import Core from './../index';
import {
_board, _data, _opts, _config, _renderer, _element, _helper,
_tempData, _draw, _coreEvent, _mapper,
_emitChangeScreen, _emitChangeData,
} from './../names';
import { Mode, CursorStatus } from './../constant/static';
const { time } = util;
const { deepClone } = util.data;
export 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;
}

View file

@ -11,10 +11,10 @@ const _coreEvent = Symbol('_coreEvent');
const _mapper = Symbol('_mapper');
const _emitChangeScreen = Symbol('_emitChangeScreen');
const _emitChangeData = Symbol('_emitChangeData');
const _todo = Symbol('_todo');
const _engine = Symbol('_engine');
export {
_board, _data, _opts, _config, _renderer, _element, _helper,
_tempData, _draw, _coreEvent, _mapper,
_emitChangeScreen, _emitChangeData, _todo,
_emitChangeScreen, _emitChangeData, _engine,
};