mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-07 04:20:11 +08:00
chore: merge blocksuite source code (#9213)
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
import type {
|
||||
Config,
|
||||
Drawable,
|
||||
OpSet,
|
||||
Options,
|
||||
ResolvedOptions,
|
||||
} from './core.js';
|
||||
import { RoughGenerator } from './generator.js';
|
||||
import type { Point } from './geometry.js';
|
||||
|
||||
export class RoughCanvas {
|
||||
private canvas: HTMLCanvasElement;
|
||||
|
||||
private ctx: CanvasRenderingContext2D;
|
||||
|
||||
private gen: RoughGenerator;
|
||||
|
||||
get generator(): RoughGenerator {
|
||||
return this.gen;
|
||||
}
|
||||
|
||||
constructor(canvas: HTMLCanvasElement, config?: Config) {
|
||||
this.canvas = canvas;
|
||||
|
||||
this.ctx = this.canvas.getContext('2d')!;
|
||||
this.gen = new RoughGenerator(config);
|
||||
}
|
||||
|
||||
private _drawToContext(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
drawing: OpSet,
|
||||
fixedDecimals?: number,
|
||||
rule: CanvasFillRule = 'nonzero'
|
||||
) {
|
||||
ctx.beginPath();
|
||||
for (const item of drawing.ops) {
|
||||
const data =
|
||||
typeof fixedDecimals === 'number' && fixedDecimals >= 0
|
||||
? item.data.map(d => +d.toFixed(fixedDecimals))
|
||||
: item.data;
|
||||
switch (item.op) {
|
||||
case 'move':
|
||||
ctx.moveTo(data[0], data[1]);
|
||||
break;
|
||||
case 'bcurveTo':
|
||||
ctx.bezierCurveTo(
|
||||
data[0],
|
||||
data[1],
|
||||
data[2],
|
||||
data[3],
|
||||
data[4],
|
||||
data[5]
|
||||
);
|
||||
break;
|
||||
case 'lineTo':
|
||||
ctx.lineTo(data[0], data[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (drawing.type === 'fillPath') {
|
||||
ctx.fill(rule);
|
||||
} else {
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
private fillSketch(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
drawing: OpSet,
|
||||
o: ResolvedOptions
|
||||
) {
|
||||
let fweight = o.fillWeight;
|
||||
if (fweight < 0) {
|
||||
fweight = o.strokeWidth / 2;
|
||||
}
|
||||
ctx.save();
|
||||
if (o.fillLineDash) {
|
||||
ctx.setLineDash(o.fillLineDash);
|
||||
}
|
||||
if (o.fillLineDashOffset) {
|
||||
ctx.lineDashOffset = o.fillLineDashOffset;
|
||||
}
|
||||
ctx.strokeStyle = o.fill || '';
|
||||
ctx.lineWidth = fweight;
|
||||
this._drawToContext(ctx, drawing, o.fixedDecimalPlaceDigits);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
arc(
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
start: number,
|
||||
stop: number,
|
||||
closed = false,
|
||||
options?: Options
|
||||
): Drawable {
|
||||
const d = this.gen.arc(x, y, width, height, start, stop, closed, options);
|
||||
this.draw(d);
|
||||
return d;
|
||||
}
|
||||
|
||||
circle(x: number, y: number, diameter: number, options?: Options): Drawable {
|
||||
const d = this.gen.circle(x, y, diameter, options);
|
||||
this.draw(d);
|
||||
return d;
|
||||
}
|
||||
|
||||
curve(points: Point[], options?: Options): Drawable {
|
||||
const d = this.gen.curve(points, options);
|
||||
this.draw(d);
|
||||
return d;
|
||||
}
|
||||
|
||||
draw(drawable: Drawable): void {
|
||||
const sets = drawable.sets || [];
|
||||
const o = drawable.options || this.getDefaultOptions();
|
||||
const ctx = this.ctx;
|
||||
const precision = drawable.options.fixedDecimalPlaceDigits;
|
||||
|
||||
for (const drawing of sets) {
|
||||
switch (drawing.type) {
|
||||
case 'path':
|
||||
ctx.save();
|
||||
ctx.strokeStyle = o.stroke === 'none' ? 'transparent' : o.stroke;
|
||||
ctx.lineWidth = o.strokeWidth;
|
||||
if (o.strokeLineDash) {
|
||||
ctx.setLineDash(o.strokeLineDash);
|
||||
}
|
||||
if (o.strokeLineDashOffset) {
|
||||
ctx.lineDashOffset = o.strokeLineDashOffset;
|
||||
}
|
||||
this._drawToContext(ctx, drawing, precision);
|
||||
ctx.restore();
|
||||
break;
|
||||
case 'fillPath': {
|
||||
ctx.save();
|
||||
ctx.fillStyle = o.fill || '';
|
||||
const fillRule: CanvasFillRule =
|
||||
drawable.shape === 'curve' ||
|
||||
drawable.shape === 'polygon' ||
|
||||
drawable.shape === 'path'
|
||||
? 'evenodd'
|
||||
: 'nonzero';
|
||||
this._drawToContext(ctx, drawing, precision, fillRule);
|
||||
ctx.restore();
|
||||
break;
|
||||
}
|
||||
case 'fillSketch':
|
||||
this.fillSketch(ctx, drawing, o);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ellipse(
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
options?: Options
|
||||
): Drawable {
|
||||
const d = this.gen.ellipse(x, y, width, height, options);
|
||||
this.draw(d);
|
||||
return d;
|
||||
}
|
||||
|
||||
getDefaultOptions(): ResolvedOptions {
|
||||
return this.gen.defaultOptions;
|
||||
}
|
||||
|
||||
line(
|
||||
x1: number,
|
||||
y1: number,
|
||||
x2: number,
|
||||
y2: number,
|
||||
options?: Options
|
||||
): Drawable {
|
||||
const d = this.gen.line(x1, y1, x2, y2, options);
|
||||
this.draw(d);
|
||||
return d;
|
||||
}
|
||||
|
||||
linearPath(points: Point[], options?: Options): Drawable {
|
||||
const d = this.gen.linearPath(points, options);
|
||||
this.draw(d);
|
||||
return d;
|
||||
}
|
||||
|
||||
path(d: string, options?: Options): Drawable {
|
||||
const drawing = this.gen.path(d, options);
|
||||
this.draw(drawing);
|
||||
return drawing;
|
||||
}
|
||||
|
||||
polygon(points: Point[], options?: Options): Drawable {
|
||||
const d = this.gen.polygon(points, options);
|
||||
this.draw(d);
|
||||
return d;
|
||||
}
|
||||
|
||||
rectangle(
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
options?: Options
|
||||
): Drawable {
|
||||
const d = this.gen.rectangle(x, y, width, height, options);
|
||||
this.draw(d);
|
||||
return d;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user