Skip to content

Commit

Permalink
Merge pull request #233 from idrawjs/dev-v0.4
Browse files Browse the repository at this point in the history
feat: add middleware ruler
  • Loading branch information
chenshenhai authored Nov 19, 2023
2 parents 281d533 + 878f3a2 commit 823c3b2
Show file tree
Hide file tree
Showing 15 changed files with 570 additions and 179 deletions.
3 changes: 2 additions & 1 deletion packages/board/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,8 @@ export class Board<T extends BoardExtendEvent = BoardExtendEvent> {

clear() {
const { viewContent } = this._opts;
const { helperContext, viewContext, boardContext } = viewContent;
const { underContext, helperContext, viewContext, boardContext } = viewContent;
underContext.clearRect(0, 0, underContext.canvas.width, underContext.canvas.height);
helperContext.clearRect(0, 0, helperContext.canvas.width, helperContext.canvas.height);
viewContext.clearRect(0, 0, viewContext.canvas.width, viewContext.canvas.height);
boardContext.clearRect(0, 0, boardContext.canvas.width, boardContext.canvas.height);
Expand Down
9 changes: 7 additions & 2 deletions packages/board/src/lib/viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class Viewer extends EventEmitter<BoardViewerEventMap> implements BoardVi

if (snapshot) {
const { scale, offsetTop, offsetBottom, offsetLeft, offsetRight, width, height, contextHeight, contextWidth, devicePixelRatio } = snapshot.activeStore;
const { viewContext, helperContext, boardContext } = viewContent;
const { underContext, viewContext, helperContext, boardContext } = viewContent;

if (snapshot?.activeStore.data) {
renderer.drawData(snapshot.activeStore.data, {
Expand All @@ -66,8 +66,10 @@ export class Viewer extends EventEmitter<BoardViewerEventMap> implements BoardVi
}
beforeDrawFrame({ snapshot });
boardContext.clearRect(0, 0, width, height);
boardContext.drawImage(underContext.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);
viewContext.clearRect(0, 0, width, height);
helperContext.clearRect(0, 0, width, height);
afterDrawFrame({ snapshot });
Expand Down Expand Up @@ -154,12 +156,15 @@ export class Viewer extends EventEmitter<BoardViewerEventMap> implements BoardVi
const newViewSize = { ...originViewSize, ...viewSize };

const { width, height, devicePixelRatio } = newViewSize;
const { boardContext, helperContext, viewContext } = this._opts.viewContent;
const { underContext, boardContext, helperContext, viewContext } = this._opts.viewContent;
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;

helperContext.canvas.width = width * devicePixelRatio;
helperContext.canvas.height = height * devicePixelRatio;

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Cursor } from './lib/cursor';
export { MiddlewareSelector } from './middleware/selector';
export { MiddlewareScroller } from './middleware/scroller';
export { MiddlewareScaler } from './middleware/scaler';
export { MiddlewareRuler } from './middleware/ruler';

export class Core {
private _board: Board<CoreEvent>;
Expand Down
32 changes: 32 additions & 0 deletions packages/core/src/middleware/ruler/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { BoardMiddleware, CoreEvent } from '@idraw/types';
import { getViewScaleInfoFromSnapshot, getViewSizeInfoFromSnapshot } from '@idraw/util';
import { drawRulerBackground, drawXRuler, drawYRuler, calcXRulerScaleList, calcYRulerScaleList, drawUnderGrid } from './util';

export const MiddlewareRuler: BoardMiddleware<Record<string, any>, CoreEvent> = (opts) => {
const key = 'RULE';
const { viewContent } = opts;
const { helperContext, underContext } = viewContent;

return {
mode: key,
isDefault: true,
beforeDrawFrame: ({ snapshot }) => {
const viewScaleInfo = getViewScaleInfoFromSnapshot(snapshot);
const viewSizeInfo = getViewSizeInfoFromSnapshot(snapshot);
drawRulerBackground(helperContext, { viewScaleInfo, viewSizeInfo });

const xList = calcXRulerScaleList({ viewScaleInfo, viewSizeInfo });
drawXRuler(helperContext, { scaleList: xList });

const yList = calcYRulerScaleList({ viewScaleInfo, viewSizeInfo });
drawYRuler(helperContext, { scaleList: yList });

drawUnderGrid(underContext, {
xList,
yList,
viewScaleInfo,
viewSizeInfo
});
}
};
};
231 changes: 231 additions & 0 deletions packages/core/src/middleware/ruler/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
import type { ViewScaleInfo, ViewSizeInfo, ViewContext2D } from '@idraw/types';
import { Context2D, formatNumber, rotateByCenter } from '@idraw/util';

const rulerSize = 16;
const background = '#FFFFFFA8';
const borderColor = '#00000080';
const scaleColor = '#000000';
const textColor = '#00000080';
const fontFamily = 'monospace';
const fontSize = 10;
const fontWeight = 100;
const gridColor = '#AAAAAA30';
const gridKeyColor = '#AAAAAA70';

// const rulerUnit = 10;
// const rulerKeyUnit = 100;
// const rulerSubKeyUnit = 50;

interface RulerScale {
num: number;
showNum: boolean;
position: number;
isKeyNum: boolean;
isSubKeyNum: boolean;
}

function calcRulerScaleList(opts: { scale: number; viewLength: number; viewOffset: number }): RulerScale[] {
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));

const rulerKeyUnit = rulerUnit * 10;
const rulerSubKeyUnit = rulerUnit * 5;

let index: number = 0;
const viewUnit = rulerUnit * scale;
const startNum = 0 - viewOffset;
const startPosition = 0;
const remainderNum = startNum % viewUnit;
const firstNum = (startNum - remainderNum + viewUnit) / scale;
const firstPosition = startPosition + (viewUnit - remainderNum);
while (firstPosition + index * viewUnit < viewLength) {
const num = firstNum + index * rulerUnit;
const position = firstPosition + index * viewUnit;
const rulerScale = {
num: formatNumber(num, { decimalPlaces: 0 }),
position,
showNum: num % rulerKeyUnit === 0,
isKeyNum: num % rulerKeyUnit === 0,
isSubKeyNum: num % rulerSubKeyUnit === 0
};
// if (viewUnit >= rulerSubKeyUnit) {
// rulerScale.isKeyNum = true;
// }
list.push(rulerScale);
index++;
}

return list;
}

export function calcXRulerScaleList(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): RulerScale[] {
const { viewScaleInfo, viewSizeInfo } = opts;
const { scale, offsetLeft } = viewScaleInfo;
const { width } = viewSizeInfo;
return calcRulerScaleList({
scale,
viewLength: width,
viewOffset: offsetLeft
});
}

export function calcYRulerScaleList(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): RulerScale[] {
const { viewScaleInfo, viewSizeInfo } = opts;
const { scale, offsetTop } = viewScaleInfo;
const { height } = viewSizeInfo;
return calcRulerScaleList({
scale,
viewLength: height,
viewOffset: offsetTop
});
}

export function drawXRuler(
ctx: ViewContext2D,
opts: {
scaleList: RulerScale[];
}
) {
const { scaleList } = opts;
const scaleDrawStart = rulerSize;
const scaleDrawEnd = (rulerSize * 4) / 5;
const subKeyScaleDrawEnd = (rulerSize * 2) / 5;
const keyScaleDrawEnd = (rulerSize * 1) / 5;
const fontStart = rulerSize / 5;
for (let i = 0; i < scaleList.length; i++) {
const item = scaleList[i];
if (item.position < rulerSize) {
continue;
}
ctx.beginPath();
ctx.moveTo(item.position, scaleDrawStart);
ctx.lineTo(item.position, item.isKeyNum ? keyScaleDrawEnd : item.isSubKeyNum ? subKeyScaleDrawEnd : scaleDrawEnd);
ctx.closePath();
ctx.fillStyle = scaleColor;
ctx.stroke();
if (item.isKeyNum) {
ctx.fillStyle = textColor;
ctx.textBaseline = 'top';
ctx.$setFont({
fontWeight,
fontSize,
fontFamily
});
ctx.fillText(`${item.num}`, item.position + fontStart, fontStart);
}
}
}

export function drawYRuler(
ctx: ViewContext2D,
opts: {
scaleList: RulerScale[];
}
) {
const { scaleList } = opts;
const scaleDrawStart = rulerSize;
const scaleDrawEnd = (rulerSize * 4) / 5;
const subKeyScaleDrawEnd = (rulerSize * 2) / 5;
const keyScaleDrawEnd = (rulerSize * 1) / 5;
const fontStart = rulerSize / 5;
for (let i = 0; i < scaleList.length; i++) {
const item = scaleList[i];
if (item.position < rulerSize) {
continue;
}
ctx.beginPath();
ctx.moveTo(scaleDrawStart, item.position);
ctx.lineTo(item.isKeyNum ? keyScaleDrawEnd : item.isSubKeyNum ? subKeyScaleDrawEnd : scaleDrawEnd, item.position);
ctx.closePath();
ctx.fillStyle = scaleColor;
ctx.stroke();
if (item.showNum === true) {
const textX = fontStart;
const textY = item.position + fontStart;
const numText = `${item.num}`;
rotateByCenter(ctx, -90, { x: textX, y: textY }, () => {
ctx.fillStyle = textColor;
ctx.textBaseline = 'top';
ctx.$setFont({
fontWeight,
fontSize,
fontFamily
});
ctx.fillText(numText, fontStart + fontSize, item.position + fontStart);
});
}
}
}

export function drawRulerBackground(
ctx: ViewContext2D,
opts: {
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
}
) {
const { viewSizeInfo } = opts;
const { width, height } = viewSizeInfo;

ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(width + 1, 0);
ctx.lineTo(width + 1, rulerSize);
ctx.lineTo(rulerSize, rulerSize);
ctx.lineTo(rulerSize, height + 1);
ctx.lineTo(0, height + 1);
ctx.lineTo(0, 0);
ctx.closePath();
ctx.fillStyle = background;
ctx.fill();
ctx.strokeStyle = borderColor;
ctx.stroke();
}

export function drawUnderGrid(
ctx: ViewContext2D,
opts: {
xList: RulerScale[];
yList: RulerScale[];
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
}
) {
const { xList, yList, viewSizeInfo } = opts;
const { width, height } = viewSizeInfo;
for (let i = 0; i < xList.length; i++) {
const item = xList[i];
ctx.beginPath();
ctx.moveTo(item.position, 0);
ctx.lineTo(item.position, height);
if (item.isKeyNum === true || item.isSubKeyNum === true) {
ctx.strokeStyle = gridKeyColor;
} else {
ctx.strokeStyle = gridColor;
}

ctx.lineWidth = 1;
ctx.closePath();
ctx.stroke();
}

for (let i = 0; i < yList.length; i++) {
const item = yList[i];
ctx.beginPath();
ctx.moveTo(0, item.position);
ctx.lineTo(width, item.position);
if (item.isKeyNum === true || item.isSubKeyNum === true) {
ctx.strokeStyle = gridKeyColor;
} else {
ctx.strokeStyle = gridColor;
}
ctx.lineWidth = 1;
ctx.closePath();
ctx.stroke();
}
// TODO
}
1 change: 0 additions & 1 deletion packages/core/src/middleware/scroller/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { ElementSize } from '@idraw/types';
import type { Point, BoardMiddleware, PointWatcherEvent, BoardWatherWheelXEvent, BoardWatherWheelYEvent } from '@idraw/types';
import { drawScroller, isPointInScrollThumb } from './util';
// import type { ScrollbarThumbType } from './util';
Expand Down
Loading

0 comments on commit 823c3b2

Please sign in to comment.