-
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #585 from tuanchauict/canvas
[Port to JS] Port canvas drawing
- Loading branch information
Showing
13 changed files
with
576 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import type { Pixel } from '$mono/monobitmap/board/pixel'; | ||
|
||
/** | ||
* An interface for the board of the Mono Bitmap. | ||
*/ | ||
export interface MonoBoard { | ||
get(left: number, top: number): Pixel; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import type { Char } from '$libs/char'; | ||
|
||
/** | ||
* An interface for the pixel of the Mono Bitmap. | ||
*/ | ||
export interface Pixel { | ||
visualChar: Char; | ||
directionChar: Char; | ||
highlight: HighlightType; | ||
|
||
isTransparent: boolean; | ||
} | ||
|
||
export enum HighlightType { | ||
NO, | ||
SELECTED, | ||
TEXT_EDITING, | ||
LINE_CONNECT_FOCUSING | ||
} |
147 changes: 147 additions & 0 deletions
147
monosketch-svelte/src/lib/mono/shape/interaction-bound.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
import type { Rect } from '$libs/graphics-geo/rect'; | ||
import { MouseCursor } from '$mono/workspace/mouse/cursor-type'; | ||
|
||
export enum InteractionBoundType { | ||
LINE, | ||
SCALABLE_SHAPE, | ||
} | ||
|
||
/** | ||
* An interface to define all possible interaction bound types | ||
*/ | ||
export interface InteractionBound { | ||
readonly type: InteractionBoundType; | ||
readonly interactionPoints: InteractionPoint[]; | ||
} | ||
|
||
export class ScalableInteractionBound implements InteractionBound { | ||
readonly type = InteractionBoundType.SCALABLE_SHAPE; | ||
|
||
constructor( | ||
public readonly interactionPoints: InteractionPoint[], | ||
public readonly left: number, | ||
public readonly top: number, | ||
public readonly right: number, | ||
public readonly bottom: number, | ||
) {} | ||
|
||
static of = (targetedShapeId: string, shapeBound: Rect): ScalableInteractionBound => { | ||
const left = shapeBound.left - 0.25; | ||
const top = shapeBound.top - 0.25; | ||
const right = shapeBound.right + 0.25; | ||
const bottom = shapeBound.bottom + 0.25; | ||
const horizontalMiddle = (left + right) / 2; | ||
const verticalMiddle = (top + bottom) / 2; | ||
return new ScalableInteractionBound( | ||
[ | ||
{ | ||
shapeId: targetedShapeId, | ||
type: InteractionPointType.TOP_LEFT, | ||
left: left, | ||
top: top, | ||
}, | ||
{ | ||
shapeId: targetedShapeId, | ||
type: InteractionPointType.TOP_MIDDLE, | ||
left: horizontalMiddle, | ||
top: top, | ||
}, | ||
{ | ||
shapeId: targetedShapeId, | ||
type: InteractionPointType.TOP_RIGHT, | ||
left: right, | ||
top: top, | ||
}, | ||
{ | ||
shapeId: targetedShapeId, | ||
type: InteractionPointType.MIDDLE_LEFT, | ||
left: left, | ||
top: verticalMiddle, | ||
}, | ||
{ | ||
shapeId: targetedShapeId, | ||
type: InteractionPointType.MIDDLE_RIGHT, | ||
left: right, | ||
top: verticalMiddle, | ||
}, | ||
{ | ||
shapeId: targetedShapeId, | ||
type: InteractionPointType.BOTTOM_LEFT, | ||
left: left, | ||
top: bottom, | ||
}, | ||
{ | ||
shapeId: targetedShapeId, | ||
type: InteractionPointType.BOTTOM_MIDDLE, | ||
left: horizontalMiddle, | ||
top: bottom, | ||
}, | ||
{ | ||
shapeId: targetedShapeId, | ||
type: InteractionPointType.BOTTOM_RIGHT, | ||
left: right, | ||
top: bottom, | ||
}, | ||
], | ||
left, | ||
top, | ||
right, | ||
bottom, | ||
); | ||
}; | ||
} | ||
|
||
export class LineInteractionBound implements InteractionBound { | ||
readonly type = InteractionBoundType.LINE; | ||
|
||
constructor(public readonly interactionPoints: InteractionPoint[]) {} | ||
} | ||
|
||
/** | ||
* An interface to define the interaction point for a shape and common APIs. | ||
* | ||
* @left the center position of the interaction point in the x-axis, in board-related unit. | ||
* @top the center position of the interaction point in the y-axis, in board-related unit. | ||
*/ | ||
export interface InteractionPoint { | ||
shapeId: string; | ||
type: InteractionPointType; | ||
left: number; | ||
top: number; | ||
} | ||
|
||
/** | ||
* An enum to define the type of the interaction point for a shape. | ||
*/ | ||
export enum InteractionPointType { | ||
TOP_LEFT, | ||
TOP_MIDDLE, | ||
TOP_RIGHT, | ||
MIDDLE_LEFT, | ||
MIDDLE_RIGHT, | ||
BOTTOM_LEFT, | ||
BOTTOM_MIDDLE, | ||
BOTTOM_RIGHT, | ||
LINE_HORIZONTAL, | ||
LINE_VERTICAL, | ||
LINE_ANCHOR, | ||
} | ||
|
||
export const scalableInteractionPointTypeToCursor = (type: InteractionPointType): MouseCursor => { | ||
switch (type) { | ||
case InteractionPointType.TOP_LEFT: | ||
case InteractionPointType.BOTTOM_RIGHT: | ||
return MouseCursor.RESIZE_NWSE; | ||
case InteractionPointType.TOP_MIDDLE: | ||
case InteractionPointType.BOTTOM_MIDDLE: | ||
return MouseCursor.RESIZE_NS; | ||
case InteractionPointType.TOP_RIGHT: | ||
case InteractionPointType.BOTTOM_LEFT: | ||
return MouseCursor.RESIZE_NESW; | ||
case InteractionPointType.MIDDLE_LEFT: | ||
case InteractionPointType.MIDDLE_RIGHT: | ||
return MouseCursor.RESIZE_EW; | ||
default: | ||
return MouseCursor.DEFAULT; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
monosketch-svelte/src/lib/mono/workspace/canvas/board-canvas-view-controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { BaseCanvasViewController } from '$mono/workspace/canvas/base-canvas-controller'; | ||
import { type ThemeManager } from '$mono/ui-state-manager/theme-manager'; | ||
import { HighlightType, type Pixel } from '$mono/monobitmap/board/pixel'; | ||
import { ThemeColors } from '$mono/ui-state-manager/states'; | ||
import type { MonoBoard } from '$mono/monobitmap/board/board'; | ||
|
||
/** | ||
* A class for managing the board canvas. | ||
*/ | ||
export class BoardCanvasViewController extends BaseCanvasViewController { | ||
|
||
constructor( | ||
canvas: HTMLCanvasElement, | ||
private board: MonoBoard, | ||
private themeManager: ThemeManager, | ||
) { | ||
super(canvas); | ||
} | ||
|
||
protected drawInternal() { | ||
const drawingInfo = this.drawingInfo; | ||
this.context.font = drawingInfo.font; | ||
for (let row of drawingInfo.boardRowRange) { | ||
for (let column of drawingInfo.boardColumnRange) { | ||
this.drawPixel(this.board.get(row, column), row, column); | ||
} | ||
} | ||
} | ||
|
||
private drawPixel = (pixel: Pixel, row: number, column: number) => { | ||
if (pixel.isTransparent) { | ||
return; | ||
} | ||
this.context.fillStyle = this.themeManager.getThemedColorCode(this.getPixelColor(pixel)); | ||
this.drawText(pixel.visualChar, row, column); | ||
}; | ||
|
||
private getPixelColor = (pixel: Pixel) => { | ||
switch (pixel.highlight) { | ||
case HighlightType.NO: | ||
return ThemeColors.Shape; | ||
case HighlightType.SELECTED: | ||
return ThemeColors.ShapeSelected; | ||
case HighlightType.TEXT_EDITING: | ||
return ThemeColors.ShapeTextEditing; | ||
case HighlightType.LINE_CONNECT_FOCUSING: | ||
return ThemeColors.ShapeLineConnectTarget; | ||
default: | ||
throw new Error(`Unknown highlight type: ${pixel.highlight}`); | ||
} | ||
}; | ||
} |
44 changes: 44 additions & 0 deletions
44
monosketch-svelte/src/lib/mono/workspace/canvas/grid-canvas-view-controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { BaseCanvasViewController } from '$mono/workspace/canvas/base-canvas-controller'; | ||
import type { ThemeManager } from '$mono/ui-state-manager/theme-manager'; | ||
import { ThemeColors } from '$mono/ui-state-manager/states'; | ||
|
||
/** | ||
* A class for managing the grid canvas. | ||
*/ | ||
export class GridCanvasViewController extends BaseCanvasViewController { | ||
constructor( | ||
canvas: HTMLCanvasElement, | ||
private themeManager: ThemeManager, | ||
) { | ||
super(canvas); | ||
} | ||
|
||
protected drawInternal = () => { | ||
const context = this.context; | ||
context.strokeStyle = this.themeManager.getThemedColorCode(ThemeColors.GridLine); | ||
context.lineWidth = 0.25; | ||
context.stroke(this.createGridPath()); | ||
}; | ||
|
||
private createGridPath = (): Path2D => { | ||
const drawingInfo = this.drawingInfo; | ||
const zeroX = drawingInfo.toXPx(drawingInfo.boardColumnRange.start - 1.0); | ||
const maxX = drawingInfo.toXPx(drawingInfo.boardColumnRange.endExclusive + 1.0); | ||
const zeroY = drawingInfo.toYPx(drawingInfo.boardRowRange.start - 1.0); | ||
const maxY = drawingInfo.toYPx(drawingInfo.boardRowRange.endExclusive + 1.0); | ||
|
||
const path = new Path2D(); | ||
|
||
for (let row of drawingInfo.boardRowRange) { | ||
const yPx = drawingInfo.toYPx(row); | ||
this.addHLine(path, zeroX, yPx, maxX - zeroX); | ||
} | ||
|
||
for (let column of drawingInfo.boardColumnRange) { | ||
const xPx = drawingInfo.toXPx(column); | ||
this.addVLine(path, xPx, zeroY, maxY - zeroY); | ||
} | ||
|
||
return path; | ||
}; | ||
} |
Oops, something went wrong.