mirror of
https://github.com/idrawjs/idraw
synced 2026-05-23 17:48:23 +00:00
feat: enhance image and path in renderer and optimize middleare ruler
This commit is contained in:
parent
75eb760b5f
commit
809c704ed9
14 changed files with 194 additions and 108 deletions
|
|
@ -405,9 +405,9 @@ export class Board<T extends BoardExtendEventMap = BoardExtendEventMap> {
|
|||
const { width, height, devicePixelRatio } = newViewSize;
|
||||
const { boardContent } = this.#opts;
|
||||
boardContent.viewContext.$resize({ width, height, devicePixelRatio });
|
||||
boardContent.helperContext.$resize({ width, height, devicePixelRatio });
|
||||
boardContent.overlayContext.$resize({ width, height, devicePixelRatio });
|
||||
boardContent.boardContext.$resize({ width, height, devicePixelRatio });
|
||||
boardContent.underContext.$resize({ width, height, devicePixelRatio });
|
||||
boardContent.underlayContext.$resize({ width, height, devicePixelRatio });
|
||||
this.#viewer.drawFrame();
|
||||
this.#watcher.trigger('resize', viewSize);
|
||||
this.#sharer.setActiveViewSizeInfo(newViewSize);
|
||||
|
|
@ -415,9 +415,9 @@ export class Board<T extends BoardExtendEventMap = BoardExtendEventMap> {
|
|||
|
||||
clear() {
|
||||
const { boardContent } = this.#opts;
|
||||
const { underContext, helperContext, viewContext, boardContext } = boardContent;
|
||||
underContext.clearRect(0, 0, underContext.canvas.width, underContext.canvas.height);
|
||||
helperContext.clearRect(0, 0, helperContext.canvas.width, helperContext.canvas.height);
|
||||
const { underlayContext, overlayContext, viewContext, boardContext } = boardContent;
|
||||
underlayContext.clearRect(0, 0, underlayContext.canvas.width, underlayContext.canvas.height);
|
||||
overlayContext.clearRect(0, 0, overlayContext.canvas.width, overlayContext.canvas.height);
|
||||
viewContext.clearRect(0, 0, viewContext.canvas.width, viewContext.canvas.height);
|
||||
boardContext.clearRect(0, 0, boardContext.canvas.width, boardContext.canvas.height);
|
||||
this.#handleClear();
|
||||
|
|
|
|||
|
|
@ -172,17 +172,17 @@ export class Viewer extends EventEmitter<BoardViewerEventMap> implements BoardVi
|
|||
const newViewSize = { ...originViewSize, ...viewSize };
|
||||
|
||||
const { width, height, devicePixelRatio } = newViewSize;
|
||||
const { underContext, boardContext, helperContext, viewContext } = this.#opts.boardContent;
|
||||
const { underlayContext, boardContext, overlayContext, viewContext } = this.#opts.boardContent;
|
||||
boardContext.canvas.width = width * devicePixelRatio;
|
||||
boardContext.canvas.height = height * devicePixelRatio;
|
||||
boardContext.canvas.style.width = `${width}px`;
|
||||
boardContext.canvas.style.height = `${height}px`;
|
||||
|
||||
underContext.canvas.width = width * devicePixelRatio;
|
||||
underContext.canvas.height = height * devicePixelRatio;
|
||||
underlayContext.canvas.width = width * devicePixelRatio;
|
||||
underlayContext.canvas.height = height * devicePixelRatio;
|
||||
|
||||
helperContext.canvas.width = width * devicePixelRatio;
|
||||
helperContext.canvas.height = height * devicePixelRatio;
|
||||
overlayContext.canvas.width = width * devicePixelRatio;
|
||||
overlayContext.canvas.height = height * devicePixelRatio;
|
||||
|
||||
viewContext.canvas.width = width * devicePixelRatio;
|
||||
viewContext.canvas.height = height * devicePixelRatio;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const infoLineHeight = 16;
|
|||
|
||||
export const MiddlewareInfo: BoardMiddleware<DeepInfoSharedStorage> = (opts) => {
|
||||
const { boardContent, calculator } = opts;
|
||||
const { helperContext } = boardContent;
|
||||
const { overlayContext } = boardContent;
|
||||
|
||||
return {
|
||||
name: '@middleware/info',
|
||||
|
|
@ -76,7 +76,7 @@ export const MiddlewareInfo: BoardMiddleware<DeepInfoSharedStorage> = (opts) =>
|
|||
const h = formatNumber(elem.h, { decimalPlaces: 2 });
|
||||
|
||||
// // test start ----
|
||||
// const ctx = helperContext;
|
||||
// const ctx = overlayContext;
|
||||
// ctx.beginPath();
|
||||
// ctx.moveTo(rectInfo.topLeft.x, rectInfo.topLeft.y);
|
||||
// ctx.lineTo(rectInfo.topRight.x, rectInfo.topRight.y);
|
||||
|
|
@ -91,7 +91,7 @@ export const MiddlewareInfo: BoardMiddleware<DeepInfoSharedStorage> = (opts) =>
|
|||
const whText = `${formatNumber(w, { decimalPlaces: 0 })}x${formatNumber(h, { decimalPlaces: 0 })}`;
|
||||
const angleText = `${formatNumber(elem.angle || 0, { decimalPlaces: 0 })}°`;
|
||||
|
||||
drawSizeInfoText(helperContext, {
|
||||
drawSizeInfoText(overlayContext, {
|
||||
point: {
|
||||
x: rectInfo.bottom.x,
|
||||
y: rectInfo.bottom.y + infoFontSize
|
||||
|
|
@ -105,7 +105,7 @@ export const MiddlewareInfo: BoardMiddleware<DeepInfoSharedStorage> = (opts) =>
|
|||
background: infoBackground
|
||||
});
|
||||
|
||||
drawPositionInfoText(helperContext, {
|
||||
drawPositionInfoText(overlayContext, {
|
||||
point: {
|
||||
x: rectInfo.topLeft.x,
|
||||
y: rectInfo.topLeft.y - infoFontSize * 2
|
||||
|
|
@ -119,7 +119,7 @@ export const MiddlewareInfo: BoardMiddleware<DeepInfoSharedStorage> = (opts) =>
|
|||
background: infoBackground
|
||||
});
|
||||
|
||||
drawAngleInfoText(helperContext, {
|
||||
drawAngleInfoText(overlayContext, {
|
||||
point: {
|
||||
x: rectInfo.top.x + infoFontSize,
|
||||
y: rectInfo.top.y - infoFontSize * 2
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { eventChange } from '../../config';
|
|||
|
||||
export const MiddlewareLayoutSelector: BoardMiddleware<LayoutSelectorSharedStorage> = (opts) => {
|
||||
const { sharer, boardContent, calculator, viewer, eventHub } = opts;
|
||||
const { helperContext } = boardContent;
|
||||
const { overlayContext } = boardContent;
|
||||
|
||||
let prevPoint: Point | null = null;
|
||||
|
||||
|
|
@ -244,7 +244,7 @@ export const MiddlewareLayoutSelector: BoardMiddleware<LayoutSelectorSharedStora
|
|||
const size = { x, y, w, h };
|
||||
const controller = calcLayoutSizeController(size, { viewScaleInfo, controllerSize: 10 });
|
||||
|
||||
drawLayoutController(helperContext, { controller, operations: activeStore.data.layout.operations || {} });
|
||||
drawLayoutController(overlayContext, { controller, operations: activeStore.data.layout.operations || {} });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import type { BoardMiddleware, CoreEventMap } from '@idraw/types';
|
||||
import { getViewScaleInfoFromSnapshot, getViewSizeInfoFromSnapshot } from '@idraw/util';
|
||||
import { drawRulerBackground, drawXRuler, drawYRuler, calcXRulerScaleList, calcYRulerScaleList, drawUnderGrid, drawScrollerSelectedArea } from './util';
|
||||
import { drawRulerBackground, drawXRuler, drawYRuler, calcXRulerScaleList, calcYRulerScaleList, drawGrid, drawScrollerSelectedArea } from './util';
|
||||
import type { DeepRulerSharedStorage } from './types';
|
||||
|
||||
export const middlewareEventRuler = '@middleware/show-ruler';
|
||||
|
||||
export const MiddlewareRuler: BoardMiddleware<DeepRulerSharedStorage, CoreEventMap> = (opts) => {
|
||||
const { boardContent, viewer, eventHub, calculator } = opts;
|
||||
const { helperContext, underContext } = boardContent;
|
||||
const { overlayContext, underlayContext } = boardContent;
|
||||
let show: boolean = true;
|
||||
let showGrid: boolean = true;
|
||||
|
||||
|
|
@ -36,18 +36,20 @@ export const MiddlewareRuler: BoardMiddleware<DeepRulerSharedStorage, CoreEventM
|
|||
if (show === true) {
|
||||
const viewScaleInfo = getViewScaleInfoFromSnapshot(snapshot);
|
||||
const viewSizeInfo = getViewSizeInfoFromSnapshot(snapshot);
|
||||
drawScrollerSelectedArea(helperContext, { snapshot, calculator });
|
||||
|
||||
drawRulerBackground(helperContext, { viewScaleInfo, viewSizeInfo });
|
||||
drawScrollerSelectedArea(overlayContext, { snapshot, calculator });
|
||||
|
||||
const xList = calcXRulerScaleList({ viewScaleInfo, viewSizeInfo });
|
||||
drawXRuler(helperContext, { scaleList: xList });
|
||||
drawRulerBackground(overlayContext, { viewScaleInfo, viewSizeInfo });
|
||||
|
||||
const yList = calcYRulerScaleList({ viewScaleInfo, viewSizeInfo });
|
||||
drawYRuler(helperContext, { scaleList: yList });
|
||||
const { list: xList, rulerUnit } = calcXRulerScaleList({ viewScaleInfo, viewSizeInfo });
|
||||
drawXRuler(overlayContext, { scaleList: xList });
|
||||
|
||||
const { list: yList } = calcYRulerScaleList({ viewScaleInfo, viewSizeInfo });
|
||||
drawYRuler(overlayContext, { scaleList: yList });
|
||||
|
||||
if (showGrid === true) {
|
||||
drawUnderGrid(underContext, {
|
||||
const ctx = rulerUnit === 1 ? overlayContext : underlayContext;
|
||||
drawGrid(ctx, {
|
||||
xList,
|
||||
yList,
|
||||
viewScaleInfo,
|
||||
|
|
|
|||
|
|
@ -28,14 +28,40 @@ interface RulerScale {
|
|||
isSubKeyNum: boolean;
|
||||
}
|
||||
|
||||
function calcRulerScaleList(opts: { axis: 'X' | 'Y'; scale: number; viewLength: number; viewOffset: number }): RulerScale[] {
|
||||
const limitRulerUnitList = [1, 2, 5, 10, 20, 50, 100, 200, 500];
|
||||
|
||||
function limitRulerUnit(unit: number): number {
|
||||
unit = Math.max(limitRulerUnitList[0], Math.min(unit, limitRulerUnitList[limitRulerUnitList.length - 1]));
|
||||
for (let i = 0; i < limitRulerUnitList.length - 1; i++) {
|
||||
const thisUnit = limitRulerUnitList[i];
|
||||
const nextUnit = limitRulerUnitList[i + 1];
|
||||
if (unit > nextUnit) {
|
||||
continue;
|
||||
}
|
||||
if (unit === thisUnit) {
|
||||
return unit;
|
||||
}
|
||||
if (unit === nextUnit) {
|
||||
return unit;
|
||||
}
|
||||
|
||||
const mid = (thisUnit + nextUnit) / 2;
|
||||
if (unit <= mid) {
|
||||
return thisUnit;
|
||||
}
|
||||
return nextUnit;
|
||||
}
|
||||
return unit;
|
||||
}
|
||||
|
||||
function calcRulerScaleList(opts: { axis: 'X' | 'Y'; scale: number; viewLength: number; viewOffset: number }): { list: RulerScale[]; rulerUnit: number } {
|
||||
const { scale, viewLength, viewOffset } = opts;
|
||||
const list: RulerScale[] = [];
|
||||
let rulerUnit = 10;
|
||||
|
||||
rulerUnit = formatNumber(rulerUnit / scale, { decimalPlaces: 0 });
|
||||
rulerUnit = Math.max(10, Math.min(rulerUnit, 1000));
|
||||
|
||||
// rulerUnit = Math.max(10, Math.min(rulerUnit, 1000));
|
||||
rulerUnit = limitRulerUnit(rulerUnit);
|
||||
const rulerKeyUnit = rulerUnit * 10;
|
||||
const rulerSubKeyUnit = rulerUnit * 5;
|
||||
|
||||
|
|
@ -46,6 +72,7 @@ function calcRulerScaleList(opts: { axis: 'X' | 'Y'; scale: number; viewLength:
|
|||
const remainderNum = startNum % viewUnit;
|
||||
const firstNum = (startNum - remainderNum + viewUnit) / scale;
|
||||
const firstPosition = startPosition + (viewUnit - remainderNum);
|
||||
|
||||
while (firstPosition + index * viewUnit < viewLength) {
|
||||
const num = formatNumber(firstNum + index * rulerUnit, { decimalPlaces: 0 });
|
||||
const position = formatNumber(firstPosition + index * viewUnit, { decimalPlaces: 0 });
|
||||
|
|
@ -60,10 +87,10 @@ function calcRulerScaleList(opts: { axis: 'X' | 'Y'; scale: number; viewLength:
|
|||
index++;
|
||||
}
|
||||
|
||||
return list;
|
||||
return { list, rulerUnit };
|
||||
}
|
||||
|
||||
export function calcXRulerScaleList(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): RulerScale[] {
|
||||
export function calcXRulerScaleList(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): { list: RulerScale[]; rulerUnit: number } {
|
||||
const { viewScaleInfo, viewSizeInfo } = opts;
|
||||
const { scale, offsetLeft } = viewScaleInfo;
|
||||
const { width } = viewSizeInfo;
|
||||
|
|
@ -75,7 +102,7 @@ export function calcXRulerScaleList(opts: { viewScaleInfo: ViewScaleInfo; viewSi
|
|||
});
|
||||
}
|
||||
|
||||
export function calcYRulerScaleList(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): RulerScale[] {
|
||||
export function calcYRulerScaleList(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): { list: RulerScale[]; rulerUnit: number } {
|
||||
const { viewScaleInfo, viewSizeInfo } = opts;
|
||||
const { scale, offsetTop } = viewScaleInfo;
|
||||
const { height } = viewSizeInfo;
|
||||
|
|
@ -195,7 +222,7 @@ export function drawRulerBackground(
|
|||
ctx.stroke();
|
||||
}
|
||||
|
||||
export function drawUnderGrid(
|
||||
export function drawGrid(
|
||||
ctx: ViewContext2D,
|
||||
opts: {
|
||||
xList: RulerScale[];
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import type { DeepScrollerSharedStorage } from './types';
|
|||
|
||||
export const MiddlewareScroller: BoardMiddleware<DeepScrollerSharedStorage> = (opts) => {
|
||||
const { viewer, boardContent, sharer } = opts;
|
||||
const { helperContext } = boardContent;
|
||||
const { overlayContext } = boardContent;
|
||||
sharer.setSharedStorage(keyXThumbRect, null); // null | ElementSize
|
||||
sharer.setSharedStorage(keyYThumbRect, null); // null | ElementSize
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ export const MiddlewareScroller: BoardMiddleware<DeepScrollerSharedStorage> = (o
|
|||
};
|
||||
|
||||
const getThumbType = (p: Point) => {
|
||||
return isPointInScrollThumb(helperContext, p, {
|
||||
return isPointInScrollThumb(overlayContext, p, {
|
||||
xThumbRect: sharer.getSharedStorage(keyXThumbRect),
|
||||
yThumbRect: sharer.getSharedStorage(keyYThumbRect)
|
||||
});
|
||||
|
|
@ -97,7 +97,7 @@ export const MiddlewareScroller: BoardMiddleware<DeepScrollerSharedStorage> = (o
|
|||
}
|
||||
},
|
||||
beforeDrawFrame({ snapshot }) {
|
||||
const { xThumbRect, yThumbRect } = drawScroller(helperContext, { snapshot });
|
||||
const { xThumbRect, yThumbRect } = drawScroller(overlayContext, { snapshot });
|
||||
sharer.setSharedStorage(keyXThumbRect, xThumbRect);
|
||||
sharer.setSharedStorage(keyYThumbRect, yThumbRect);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ const scrollConfig = {
|
|||
showScrollBar: false
|
||||
};
|
||||
|
||||
function isPointAtRect(helperContext: ViewContext2D, p: Point, rect: ElementSize): boolean {
|
||||
const ctx = helperContext;
|
||||
function isPointAtRect(overlayContext: ViewContext2D, p: Point, rect: ElementSize): boolean {
|
||||
const ctx = overlayContext;
|
||||
const { x, y, w, h } = rect;
|
||||
ctx.beginPath();
|
||||
ctx.rect(x, y, w, h);
|
||||
|
|
@ -28,7 +28,7 @@ function isPointAtRect(helperContext: ViewContext2D, p: Point, rect: ElementSize
|
|||
}
|
||||
|
||||
export function isPointInScrollThumb(
|
||||
helperContext: ViewContext2D,
|
||||
overlayContext: ViewContext2D,
|
||||
p: Point,
|
||||
opts: {
|
||||
xThumbRect?: ElementSize | null;
|
||||
|
|
@ -37,9 +37,9 @@ export function isPointInScrollThumb(
|
|||
): ScrollbarThumbType | null {
|
||||
let thumbType: ScrollbarThumbType | null = null;
|
||||
const { xThumbRect, yThumbRect } = opts;
|
||||
if (xThumbRect && isPointAtRect(helperContext, p, xThumbRect)) {
|
||||
if (xThumbRect && isPointAtRect(overlayContext, p, xThumbRect)) {
|
||||
thumbType = 'X';
|
||||
} else if (yThumbRect && isPointAtRect(helperContext, p, yThumbRect)) {
|
||||
} else if (yThumbRect && isPointAtRect(overlayContext, p, yThumbRect)) {
|
||||
thumbType = 'Y';
|
||||
}
|
||||
return thumbType;
|
||||
|
|
@ -194,8 +194,8 @@ function drawScrollerThumb(
|
|||
ctx.restore();
|
||||
}
|
||||
|
||||
function drawScrollerInfo(helperContext: ViewContext2D, opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo; scrollInfo: ScrollInfo }) {
|
||||
const ctx = helperContext;
|
||||
function drawScrollerInfo(overlayContext: ViewContext2D, opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo; scrollInfo: ScrollInfo }) {
|
||||
const ctx = overlayContext;
|
||||
const { viewScaleInfo, viewSizeInfo, scrollInfo } = opts;
|
||||
const { activeThumbType, prevPoint, activePoint } = scrollInfo;
|
||||
const { width, height } = viewSizeInfo;
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ export { middlewareEventSelect, middlewareEventSelectClear, middlewareEventSelec
|
|||
|
||||
export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, CoreEventMap> = (opts) => {
|
||||
const { viewer, sharer, boardContent, calculator, eventHub } = opts;
|
||||
const { helperContext } = boardContent;
|
||||
const { overlayContext } = boardContent;
|
||||
let prevPoint: Point | null = null;
|
||||
let inBusyMode: 'resize' | 'drag' | 'drag-list' | 'area' | null = null;
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
|
||||
const pointTargetBaseOptions = () => {
|
||||
return {
|
||||
ctx: helperContext,
|
||||
ctx: overlayContext,
|
||||
calculator,
|
||||
data: sharer.getActiveStorage('data'),
|
||||
selectedElements: getActiveElements(),
|
||||
|
|
@ -249,7 +249,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
if (groupQueue?.length > 0) {
|
||||
// in group
|
||||
const isInActiveGroup = isPointInViewActiveGroup(e.point, {
|
||||
ctx: helperContext,
|
||||
ctx: overlayContext,
|
||||
viewScaleInfo: sharer.getActiveViewScaleInfo(),
|
||||
viewSizeInfo: sharer.getActiveViewSizeInfo(),
|
||||
groupQueue: sharer.getSharedStorage(keyGroupQueue)
|
||||
|
|
@ -350,7 +350,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
if (groupQueue?.length > 0) {
|
||||
if (
|
||||
isPointInViewActiveGroup(e.point, {
|
||||
ctx: helperContext,
|
||||
ctx: overlayContext,
|
||||
viewScaleInfo: sharer.getActiveViewScaleInfo(),
|
||||
viewSizeInfo: sharer.getActiveViewSizeInfo(),
|
||||
groupQueue
|
||||
|
|
@ -750,10 +750,10 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
|
||||
if (groupQueue?.length > 0) {
|
||||
// in group
|
||||
drawGroupQueueVertexesWrappers(helperContext, groupQueueVertexesList, drawBaseOpts);
|
||||
drawGroupQueueVertexesWrappers(overlayContext, groupQueueVertexesList, drawBaseOpts);
|
||||
if (hoverElement && actionType !== 'drag') {
|
||||
if (isLock) {
|
||||
drawLockVertexesWrapper(helperContext, hoverElementVertexes, {
|
||||
drawLockVertexesWrapper(overlayContext, hoverElementVertexes, {
|
||||
...drawBaseOpts,
|
||||
controller: calcElementSizeController(hoverElement, {
|
||||
groupQueue,
|
||||
|
|
@ -762,11 +762,11 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
})
|
||||
});
|
||||
} else {
|
||||
drawHoverVertexesWrapper(helperContext, hoverElementVertexes, drawBaseOpts);
|
||||
drawHoverVertexesWrapper(overlayContext, hoverElementVertexes, drawBaseOpts);
|
||||
}
|
||||
}
|
||||
if (!isLock && elem && (['select', 'drag', 'resize'] as ActionType[]).includes(actionType)) {
|
||||
drawSelectedElementControllersVertexes(helperContext, selectedElementController, {
|
||||
drawSelectedElementControllersVertexes(overlayContext, selectedElementController, {
|
||||
...drawBaseOpts,
|
||||
element: elem,
|
||||
calculator,
|
||||
|
|
@ -775,7 +775,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
if (actionType === 'drag') {
|
||||
const xLines = sharer.getSharedStorage(keySelectedReferenceXLines);
|
||||
const yLines = sharer.getSharedStorage(keySelectedReferenceYLines);
|
||||
drawReferenceLines(helperContext, {
|
||||
drawReferenceLines(overlayContext, {
|
||||
xLines,
|
||||
yLines
|
||||
});
|
||||
|
|
@ -785,7 +785,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
// in root
|
||||
if (hoverElement && actionType !== 'drag') {
|
||||
if (isLock) {
|
||||
drawLockVertexesWrapper(helperContext, hoverElementVertexes, {
|
||||
drawLockVertexesWrapper(overlayContext, hoverElementVertexes, {
|
||||
...drawBaseOpts,
|
||||
controller: calcElementSizeController(hoverElement, {
|
||||
groupQueue,
|
||||
|
|
@ -794,11 +794,11 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
})
|
||||
});
|
||||
} else {
|
||||
drawHoverVertexesWrapper(helperContext, hoverElementVertexes, drawBaseOpts);
|
||||
drawHoverVertexesWrapper(overlayContext, hoverElementVertexes, drawBaseOpts);
|
||||
}
|
||||
}
|
||||
if (!isLock && elem && (['select', 'drag', 'resize'] as ActionType[]).includes(actionType)) {
|
||||
drawSelectedElementControllersVertexes(helperContext, selectedElementController, {
|
||||
drawSelectedElementControllersVertexes(overlayContext, selectedElementController, {
|
||||
...drawBaseOpts,
|
||||
element: elem,
|
||||
calculator,
|
||||
|
|
@ -807,13 +807,13 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
if (actionType === 'drag') {
|
||||
const xLines = sharer.getSharedStorage(keySelectedReferenceXLines);
|
||||
const yLines = sharer.getSharedStorage(keySelectedReferenceYLines);
|
||||
drawReferenceLines(helperContext, {
|
||||
drawReferenceLines(overlayContext, {
|
||||
xLines,
|
||||
yLines
|
||||
});
|
||||
}
|
||||
} else if (actionType === 'area' && areaStart && areaEnd) {
|
||||
drawArea(helperContext, { start: areaStart, end: areaEnd });
|
||||
drawArea(overlayContext, { start: areaStart, end: areaEnd });
|
||||
} else if ((['drag-list', 'drag-list-end'] as ActionType[]).includes(actionType)) {
|
||||
const listAreaSize = calcSelectedElementsArea(getActiveElements(), {
|
||||
viewScaleInfo: sharer.getActiveViewScaleInfo(),
|
||||
|
|
@ -821,7 +821,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
calculator
|
||||
});
|
||||
if (listAreaSize) {
|
||||
drawListArea(helperContext, { areaSize: listAreaSize });
|
||||
drawListArea(overlayContext, { areaSize: listAreaSize });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -834,28 +834,28 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
// const endHorizontal: any = sharer.getSharedStorage(keyDebugEndHorizontal);
|
||||
// const end0: any = sharer.getSharedStorage(keyDebugEnd0);
|
||||
// if (elemCenter && end0) {
|
||||
// helperContext.beginPath();
|
||||
// helperContext.moveTo(elemCenter.x, elemCenter.y);
|
||||
// helperContext.lineTo(end0.x, end0.y);
|
||||
// helperContext.closePath();
|
||||
// helperContext.strokeStyle = 'black';
|
||||
// helperContext.stroke();
|
||||
// overlayContext.beginPath();
|
||||
// overlayContext.moveTo(elemCenter.x, elemCenter.y);
|
||||
// overlayContext.lineTo(end0.x, end0.y);
|
||||
// overlayContext.closePath();
|
||||
// overlayContext.strokeStyle = 'black';
|
||||
// overlayContext.stroke();
|
||||
// }
|
||||
// if (elemCenter && endVertical) {
|
||||
// helperContext.beginPath();
|
||||
// helperContext.moveTo(elemCenter.x, elemCenter.y);
|
||||
// helperContext.lineTo(endVertical.x, endVertical.y);
|
||||
// helperContext.closePath();
|
||||
// helperContext.strokeStyle = 'red';
|
||||
// helperContext.stroke();
|
||||
// overlayContext.beginPath();
|
||||
// overlayContext.moveTo(elemCenter.x, elemCenter.y);
|
||||
// overlayContext.lineTo(endVertical.x, endVertical.y);
|
||||
// overlayContext.closePath();
|
||||
// overlayContext.strokeStyle = 'red';
|
||||
// overlayContext.stroke();
|
||||
// }
|
||||
// if (elemCenter && endHorizontal) {
|
||||
// helperContext.beginPath();
|
||||
// helperContext.moveTo(elemCenter.x, elemCenter.y);
|
||||
// helperContext.lineTo(endHorizontal.x, endHorizontal.y);
|
||||
// helperContext.closePath();
|
||||
// helperContext.strokeStyle = 'blue';
|
||||
// helperContext.stroke();
|
||||
// overlayContext.beginPath();
|
||||
// overlayContext.moveTo(elemCenter.x, elemCenter.y);
|
||||
// overlayContext.lineTo(endHorizontal.x, endHorizontal.y);
|
||||
// overlayContext.closePath();
|
||||
// overlayContext.strokeStyle = 'blue';
|
||||
// overlayContext.stroke();
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/types';
|
||||
import type { Element, RendererDrawElementOptions, ViewContext2D, LoadContent } from '@idraw/types';
|
||||
import { rotateElement, calcViewBoxSize, calcViewElementSize } from '@idraw/util';
|
||||
import { drawBox, drawBoxShadow, getOpacity } from './box';
|
||||
|
||||
export function drawImage(ctx: ViewContext2D, elem: Element<'image'>, opts: RendererDrawElementOptions) {
|
||||
const content = opts.loader.getContent(elem);
|
||||
const content: LoadContent | HTMLCanvasElement | OffscreenCanvas | null = opts.loader.getContent(elem);
|
||||
const { viewScaleInfo, viewSizeInfo, parentOpacity } = opts;
|
||||
const { x, y, w, h, angle } = calcViewElementSize(elem, { viewScaleInfo, viewSizeInfo }) || elem;
|
||||
const { x, y, w, h, angle } = calcViewElementSize(elem, { viewScaleInfo }) || elem;
|
||||
|
||||
const viewElem = { ...elem, ...{ x, y, w, h, angle } };
|
||||
rotateElement(ctx, { x, y, w, h, angle }, () => {
|
||||
|
|
@ -29,6 +29,10 @@ export function drawImage(ctx: ViewContext2D, elem: Element<'image'>, opts: Rend
|
|||
viewScaleInfo,
|
||||
viewSizeInfo
|
||||
});
|
||||
const { detail } = elem;
|
||||
const { scaleMode, originW = 0, originH = 0 } = detail;
|
||||
const imageW = ctx.$undoPixelRatio(originW);
|
||||
const imageH = ctx.$undoPixelRatio(originH);
|
||||
|
||||
ctx.save();
|
||||
ctx.fillStyle = 'transparent';
|
||||
|
|
@ -41,7 +45,56 @@ export function drawImage(ctx: ViewContext2D, elem: Element<'image'>, opts: Rend
|
|||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.clip();
|
||||
ctx.drawImage(content, x, y, w, h);
|
||||
|
||||
if (scaleMode && originH && originW) {
|
||||
let sx = 0;
|
||||
let sy = 0;
|
||||
let sWidth = imageW;
|
||||
let sHeight = imageH;
|
||||
const dx = x;
|
||||
const dy = y;
|
||||
const dWidth = w;
|
||||
const dHeight = h;
|
||||
|
||||
if (imageW > elem.w || imageH > elem.h) {
|
||||
if (scaleMode === 'fill') {
|
||||
const sourceScale = Math.max(elem.w / imageW, elem.h / imageH);
|
||||
const newImageWidth = imageW * sourceScale;
|
||||
const newImageHeight = imageH * sourceScale;
|
||||
sx = (newImageWidth - elem.w) / 2 / sourceScale;
|
||||
sy = (newImageHeight - elem.h) / 2 / sourceScale;
|
||||
sWidth = elem.w / sourceScale;
|
||||
sHeight = elem.h / sourceScale;
|
||||
} else if (scaleMode === 'tile') {
|
||||
sx = 0;
|
||||
sy = 0;
|
||||
sWidth = elem.w;
|
||||
sHeight = elem.h;
|
||||
} else if (scaleMode === 'fit') {
|
||||
const sourceScale = Math.min(elem.w / imageW, elem.h / imageH);
|
||||
sx = (imageW - elem.w / sourceScale) / 2;
|
||||
sy = (imageH - elem.h / sourceScale) / 2;
|
||||
sWidth = elem.w / sourceScale;
|
||||
sHeight = elem.h / sourceScale;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.drawImage(content, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
|
||||
} else {
|
||||
ctx.drawImage(content, x, y, w, h);
|
||||
|
||||
// const sx = 0;
|
||||
// const sy = 0;
|
||||
// const sWidth = imageW;
|
||||
// const sHeight = imageH;
|
||||
// const dx = x;
|
||||
// const dy = y;
|
||||
// const dWidth = w;
|
||||
// const dHeight = h;
|
||||
// ctx.drawImage(content, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
|
||||
}
|
||||
// content = null;
|
||||
|
||||
ctx.globalAlpha = parentOpacity;
|
||||
ctx.restore();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { drawBox, drawBoxShadow } from './box';
|
|||
|
||||
export function drawPath(ctx: ViewContext2D, elem: Element<'path'>, opts: RendererDrawElementOptions) {
|
||||
const { detail } = elem;
|
||||
const { originX, originY, originW, originH } = detail;
|
||||
const { originX, originY, originW, originH, fillRule } = detail;
|
||||
const { viewScaleInfo, viewSizeInfo, parentOpacity } = opts;
|
||||
const { x, y, w, h, angle } = calcViewElementSize(elem, { viewScaleInfo }) || elem;
|
||||
const scaleW = w / originW;
|
||||
|
|
@ -43,7 +43,7 @@ export function drawPath(ctx: ViewContext2D, elem: Element<'path'>, opts: Render
|
|||
const path2d = new Path2D(pathStr);
|
||||
if (detail.fill) {
|
||||
ctx.fillStyle = detail.fill;
|
||||
ctx.fill(path2d);
|
||||
ctx.fill(path2d, fillRule as CanvasFillRule);
|
||||
}
|
||||
|
||||
if (detail.stroke && detail.strokeWidth !== 0) {
|
||||
|
|
|
|||
|
|
@ -121,6 +121,9 @@ export interface ElementHTMLDetail extends ElementBaseDetail {
|
|||
|
||||
export interface ElementImageDetail extends ElementBaseDetail {
|
||||
src: string;
|
||||
originW?: number;
|
||||
originH?: number;
|
||||
scaleMode?: 'auto' | 'fill' | 'fit' | 'tile';
|
||||
}
|
||||
|
||||
export interface ElementSVGDetail extends ElementBaseDetail {
|
||||
|
|
@ -144,6 +147,7 @@ export interface ElementPathDetail extends ElementBaseDetail {
|
|||
stroke?: string;
|
||||
strokeWidth?: number;
|
||||
strokeLineCap?: 'butt' | 'round' | 'square';
|
||||
fillRule?: string; // "evenodd" | "nonzero"
|
||||
}
|
||||
|
||||
export interface ElementDetailMap {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ export interface ViewSizeInfo extends ViewContextSize {
|
|||
export interface BoardContent {
|
||||
boardContext: ViewContext2D;
|
||||
viewContext: ViewContext2D;
|
||||
helperContext: ViewContext2D;
|
||||
underContext: ViewContext2D;
|
||||
overlayContext: ViewContext2D;
|
||||
underlayContext: ViewContext2D;
|
||||
drawView: () => void;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,26 +50,26 @@ export function createBoardContent(
|
|||
if (createCustomContext2D) {
|
||||
// TODO
|
||||
const viewContext = createCustomContext2D(ctxOpts);
|
||||
const helperContext = createCustomContext2D(ctxOpts);
|
||||
const underContext = createCustomContext2D(ctxOpts);
|
||||
const overlayContext = createCustomContext2D(ctxOpts);
|
||||
const underlayContext = createCustomContext2D(ctxOpts);
|
||||
const boardContext = createContext2D({ ctx, ...ctxOpts });
|
||||
|
||||
const drawView = () => {
|
||||
const { width: w, height: h } = viewContext.$getSize();
|
||||
|
||||
boardContext.clearRect(0, 0, w, h);
|
||||
boardContext.drawImage(underContext.canvas, 0, 0, w, h);
|
||||
boardContext.drawImage(underlayContext.canvas, 0, 0, w, h);
|
||||
boardContext.drawImage(viewContext.canvas, 0, 0, w, h);
|
||||
boardContext.drawImage(helperContext.canvas, 0, 0, w, h);
|
||||
underContext.clearRect(0, 0, w, h);
|
||||
boardContext.drawImage(overlayContext.canvas, 0, 0, w, h);
|
||||
underlayContext.clearRect(0, 0, w, h);
|
||||
viewContext.clearRect(0, 0, w, h);
|
||||
helperContext.clearRect(0, 0, w, h);
|
||||
overlayContext.clearRect(0, 0, w, h);
|
||||
};
|
||||
|
||||
const content: BoardContent = {
|
||||
underContext,
|
||||
underlayContext,
|
||||
viewContext,
|
||||
helperContext,
|
||||
overlayContext,
|
||||
boardContext,
|
||||
drawView
|
||||
};
|
||||
|
|
@ -79,26 +79,26 @@ export function createBoardContent(
|
|||
if (offscreen === true) {
|
||||
// const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||
const viewContext = createOffscreenContext2D(ctxOpts);
|
||||
const helperContext = createOffscreenContext2D(ctxOpts);
|
||||
const underContext = createOffscreenContext2D(ctxOpts);
|
||||
const overlayContext = createOffscreenContext2D(ctxOpts);
|
||||
const underlayContext = createOffscreenContext2D(ctxOpts);
|
||||
const boardContext = createContext2D({ ctx, ...ctxOpts });
|
||||
|
||||
const drawView = () => {
|
||||
const { width: w, height: h } = viewContext.$getSize();
|
||||
|
||||
boardContext.clearRect(0, 0, w, h);
|
||||
boardContext.drawImage(underContext.canvas, 0, 0, w, h);
|
||||
boardContext.drawImage(underlayContext.canvas, 0, 0, w, h);
|
||||
boardContext.drawImage(viewContext.canvas, 0, 0, w, h);
|
||||
boardContext.drawImage(helperContext.canvas, 0, 0, w, h);
|
||||
underContext.clearRect(0, 0, w, h);
|
||||
boardContext.drawImage(overlayContext.canvas, 0, 0, w, h);
|
||||
underlayContext.clearRect(0, 0, w, h);
|
||||
viewContext.clearRect(0, 0, w, h);
|
||||
helperContext.clearRect(0, 0, w, h);
|
||||
overlayContext.clearRect(0, 0, w, h);
|
||||
};
|
||||
|
||||
const content: BoardContent = {
|
||||
underContext,
|
||||
underlayContext,
|
||||
viewContext,
|
||||
helperContext,
|
||||
overlayContext,
|
||||
boardContext,
|
||||
drawView
|
||||
};
|
||||
|
|
@ -106,24 +106,24 @@ export function createBoardContent(
|
|||
} else {
|
||||
// const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||
const viewContext = createContext2D(ctxOpts);
|
||||
const helperContext = createContext2D(ctxOpts);
|
||||
const underContext = createContext2D(ctxOpts);
|
||||
const overlayContext = createContext2D(ctxOpts);
|
||||
const underlayContext = createContext2D(ctxOpts);
|
||||
const boardContext = createContext2D({ ctx, ...ctxOpts });
|
||||
|
||||
const drawView = () => {
|
||||
boardContext.clearRect(0, 0, width, height);
|
||||
boardContext.drawImage(underContext.canvas, 0, 0, width, height);
|
||||
boardContext.drawImage(underlayContext.canvas, 0, 0, width, height);
|
||||
boardContext.drawImage(viewContext.canvas, 0, 0, width, height);
|
||||
boardContext.drawImage(helperContext.canvas, 0, 0, width, height);
|
||||
underContext.clearRect(0, 0, width, height);
|
||||
boardContext.drawImage(overlayContext.canvas, 0, 0, width, height);
|
||||
underlayContext.clearRect(0, 0, width, height);
|
||||
viewContext.clearRect(0, 0, width, height);
|
||||
helperContext.clearRect(0, 0, width, height);
|
||||
overlayContext.clearRect(0, 0, width, height);
|
||||
};
|
||||
|
||||
const content: BoardContent = {
|
||||
underContext,
|
||||
underlayContext,
|
||||
viewContext,
|
||||
helperContext,
|
||||
overlayContext,
|
||||
boardContext,
|
||||
drawView
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue