mirror of
https://github.com/idrawjs/idraw
synced 2026-05-24 10:08:34 +00:00
feat: @idraw/core implement select area
This commit is contained in:
parent
83ecc22a7e
commit
50191464b7
8 changed files with 105 additions and 24 deletions
|
|
@ -209,6 +209,10 @@ class Context implements TypeContext {
|
|||
this._ctx.textBaseline = baseline;
|
||||
}
|
||||
|
||||
setGlobalAlpha(alpha: number): void {
|
||||
this._ctx.globalAlpha = alpha;
|
||||
}
|
||||
|
||||
private _doSize(num: number) {
|
||||
return this._opts.devicePixelRatio * num;
|
||||
}
|
||||
|
|
@ -224,6 +228,7 @@ class Context implements TypeContext {
|
|||
const _y = (y - scrollY) / scale;
|
||||
return this._doSize(_y);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ enum Mode {
|
|||
NULL = 'null',
|
||||
SELECT_ELEMENT = 'select-element',
|
||||
SELECT_ELEMENT_WRAPPER_DOT = 'select-element-wrapper-dot',
|
||||
SELECT_AREA = 'select-area',
|
||||
}
|
||||
|
||||
enum CursorStatus {
|
||||
|
|
@ -264,18 +265,25 @@ class Core {
|
|||
const [uuid, direction] = this[_helper].isPointInElementWrapperDot(point);
|
||||
|
||||
if (uuid && direction) {
|
||||
// Controll Element-Wrapper
|
||||
this[_mode] = Mode.SELECT_ELEMENT_WRAPPER_DOT;
|
||||
this[_selectedDotDirection] = direction;
|
||||
this[_selectedUUID] = uuid;
|
||||
} else {
|
||||
const [index, uuid] = this[_element].isPointInElement(point, this[_data]);
|
||||
this.selectElement(index, { useMode: true });
|
||||
if (typeof uuid === 'string' && this[_coreEvent].has('screenSelectElement')) {
|
||||
this[_coreEvent].trigger(
|
||||
'screenSelectElement',
|
||||
{ index, uuid, element: deepClone(this[_data].elements?.[index])}
|
||||
);
|
||||
this[_emitChangeScreen]();
|
||||
if (index >= 0) {
|
||||
// Controll Element
|
||||
this.selectElement(index, { useMode: true });
|
||||
if (typeof uuid === 'string' && this[_coreEvent].has('screenSelectElement')) {
|
||||
this[_coreEvent].trigger(
|
||||
'screenSelectElement',
|
||||
{ index, uuid, element: deepClone(this[_data].elements?.[index])}
|
||||
);
|
||||
this[_emitChangeScreen]();
|
||||
}
|
||||
} else {
|
||||
// Controll Area
|
||||
this[_mode] = Mode.SELECT_AREA;
|
||||
}
|
||||
}
|
||||
this.draw();
|
||||
|
|
@ -284,6 +292,7 @@ class Core {
|
|||
private [_handleMoveStart](point: TypePoint): void {
|
||||
this[_prevPoint] = point;
|
||||
const uuid = this[_selectedUUID];
|
||||
|
||||
if (typeof uuid === 'string' && this[_coreEvent].has('screenMoveElementStart')) {
|
||||
this[_coreEvent].trigger('screenMoveElementStart', {
|
||||
index: this[_element].getElementIndex(this[_data], uuid),
|
||||
|
|
@ -291,11 +300,12 @@ class Core {
|
|||
x: point.x,
|
||||
y: point.y
|
||||
});
|
||||
} else if (this[_mode] === Mode.SELECT_AREA) {
|
||||
this[_helper].startSelectArea(point);
|
||||
}
|
||||
}
|
||||
|
||||
private [_handleMove](point: TypePoint): void {
|
||||
|
||||
if (typeof this[_selectedUUID] === 'string') {
|
||||
if (this[_mode] === Mode.SELECT_ELEMENT) {
|
||||
this[_dragElement](this[_selectedUUID] as string, point, this[_prevPoint]);
|
||||
|
|
@ -305,6 +315,9 @@ class Core {
|
|||
this[_transfromElement](this[_selectedUUID] as string, point, this[_prevPoint], this[_selectedDotDirection] as TypeHelperWrapperDotDirection);
|
||||
this[_cursorStatus] = CursorStatus.DRAGGING;
|
||||
}
|
||||
} else if (this[_mode] === Mode.SELECT_AREA) {
|
||||
this[_helper].changeSelectArea(point);
|
||||
this.draw();
|
||||
}
|
||||
this[_prevPoint] = point;
|
||||
}
|
||||
|
|
@ -334,10 +347,13 @@ class Core {
|
|||
}
|
||||
this[_emitChangeData]();
|
||||
}
|
||||
} else if (this[_mode] === Mode.SELECT_AREA) {
|
||||
this[_helper].clearSelectedArea();
|
||||
}
|
||||
this[_selectedUUID] = null;
|
||||
this[_prevPoint] = null;
|
||||
this[_cursorStatus] = CursorStatus.NULL;
|
||||
this[_mode] = Mode.NULL;
|
||||
}
|
||||
|
||||
private [_handleHover](point: TypePoint): void {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ const { istype, color } = util;
|
|||
export function clearContext(ctx: TypeContext) {
|
||||
ctx.setFillStyle('rgb(0 0 0 / 0%)');
|
||||
ctx.setStrokeStyle('rgb(0 0 0 / 0%)');
|
||||
ctx.setLineDash([]);
|
||||
}
|
||||
|
||||
export function drawBgColor(ctx: TypeContext, color: string) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { drawSVG } from './svg';
|
|||
import { drawText } from './text';
|
||||
import {
|
||||
drawElementWrapper,
|
||||
drawAreaWrapper,
|
||||
// drawDisplayContextScrollWrapper,
|
||||
} from './wrapper';
|
||||
|
||||
|
|
@ -32,6 +33,9 @@ export function drawContext(
|
|||
if (typeof data.bgColor === 'string' && isColorStr(data.bgColor)) {
|
||||
drawBgColor(ctx, data.bgColor);
|
||||
}
|
||||
|
||||
drawAreaWrapper(ctx, helperConfig);
|
||||
|
||||
if (!(data.elements.length > 0)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,14 +57,25 @@ export function drawElementWrapper(ctx: TypeContext, config: TypeHelperConfig) {
|
|||
}
|
||||
|
||||
|
||||
// export function drawDisplayContextScrollWrapper(displayCtx: TypeContext, config: TypeHelperConfig) {
|
||||
// // console.log('config?.displayContextScrollWrapper = ', config?.displayContextScrollWrapper);
|
||||
// // if (!config?.displayContextScrollWrapper) {
|
||||
// // return;
|
||||
// // }
|
||||
|
||||
// // draw scroll x-line
|
||||
|
||||
// // draw scroll y-line
|
||||
|
||||
// }
|
||||
export function drawAreaWrapper(ctx: TypeContext, config: TypeHelperConfig) {
|
||||
if (!config?.selectedAreaWrapper) {
|
||||
return;
|
||||
}
|
||||
const wrapper = config.selectedAreaWrapper;
|
||||
if (wrapper && wrapper.w > 0 && wrapper.h > 0) {
|
||||
clearContext(ctx);
|
||||
// draw wrapper's box
|
||||
ctx.beginPath();
|
||||
ctx.setLineDash([]);
|
||||
ctx.setLineWidth(wrapper.lineWidth);
|
||||
ctx.setStrokeStyle(wrapper.color);
|
||||
ctx.moveTo(wrapper.x, wrapper.y);
|
||||
ctx.lineTo(wrapper.x + wrapper.w, wrapper.y);
|
||||
ctx.lineTo(wrapper.x + wrapper.w, wrapper.y + wrapper.h);
|
||||
ctx.lineTo(wrapper.x, wrapper.y + wrapper.h);
|
||||
ctx.lineTo(wrapper.x, wrapper.y);
|
||||
ctx.stroke();
|
||||
ctx.closePath();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,17 @@ import { rotateContext, } from './transform';
|
|||
|
||||
const { deepClone } = util.data;
|
||||
|
||||
const areaLineWidth = 2;
|
||||
const areaColor = '#2ab6f1';
|
||||
|
||||
export class Helper implements TypeHelper {
|
||||
|
||||
private _helperConfig: TypeHelperConfig;
|
||||
private _coreConfig: TypeConfigStrict;
|
||||
private _ctx: TypeContext;
|
||||
private _board: Board;
|
||||
private _areaStart: TypePoint = { x: 0, y: 0};
|
||||
private _areaEnd: TypePoint = { x: 0, y: 0};
|
||||
|
||||
constructor(board: Board, config: TypeConfigStrict) {
|
||||
this._board = board;
|
||||
|
|
@ -89,6 +94,37 @@ export class Helper implements TypeHelper {
|
|||
return [uuid, direction];
|
||||
}
|
||||
|
||||
startSelectArea(p: TypePoint) {
|
||||
this._areaStart = p;
|
||||
}
|
||||
|
||||
changeSelectArea(p: TypePoint) {
|
||||
this._areaEnd = p;
|
||||
this._calcSelectedArea();
|
||||
}
|
||||
|
||||
clearSelectedArea() {
|
||||
this._areaStart = {x: 0, y: 0};
|
||||
this._areaStart = {x: 0, y: 0};
|
||||
this._calcSelectedArea();
|
||||
}
|
||||
|
||||
private _calcSelectedArea() {
|
||||
const start = this._areaStart;
|
||||
const end = this._areaEnd;
|
||||
|
||||
this._helperConfig.selectedAreaWrapper = {
|
||||
x: Math.min(start.x, end.x),
|
||||
y: Math.min(start.y, end.y),
|
||||
w: Math.abs(end.x - start.x),
|
||||
h: Math.abs(end.y - start.y),
|
||||
startPoint: {x: start.x, y: start.y},
|
||||
endPoint: {x: end.x, y: end.y},
|
||||
lineWidth: areaLineWidth,
|
||||
color: areaColor,
|
||||
}
|
||||
}
|
||||
|
||||
private _updateElementIndex(data: TypeData) {
|
||||
this._helperConfig.elementIndexMap = {};
|
||||
data.elements.forEach((elem: TypeElement<keyof TypeElemDesc>, i) => {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@ interface TypeContext {
|
|||
|
||||
drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;
|
||||
drawImage(image: CanvasImageSource, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void;
|
||||
createPattern(image: CanvasImageSource, repetition: string | null): CanvasPattern | null
|
||||
createPattern(image: CanvasImageSource, repetition: string | null): CanvasPattern | null;
|
||||
setGlobalAlpha(alpha: number): void;
|
||||
}
|
||||
|
||||
export {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,16 @@ import { TypePoint } from './board';
|
|||
|
||||
type TypeHelperConfig = {
|
||||
elementIndexMap: {[key: string]: number},
|
||||
selectedAreaWrapper?: {
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
startPoint: TypePoint;
|
||||
endPoint: TypePoint;
|
||||
lineWidth: number;
|
||||
color: string;
|
||||
};
|
||||
selectedElementWrapper?: {
|
||||
uuid: string;
|
||||
dotSize: number;
|
||||
|
|
@ -19,10 +29,6 @@ type TypeHelperConfig = {
|
|||
left: TypePoint,
|
||||
rotate: TypePoint,
|
||||
},
|
||||
// limit: {
|
||||
// minWidth: number;
|
||||
// minHeight: number;
|
||||
// },
|
||||
lineDash: number[];
|
||||
lineWidth: number;
|
||||
color: string;
|
||||
|
|
@ -39,6 +45,7 @@ type TypeHelperConfig = {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
type TypeHelperUpdateOpts = {
|
||||
width: number;
|
||||
height: number;
|
||||
|
|
|
|||
Loading…
Reference in a new issue