You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
4.1 KiB
JavaScript
132 lines
4.1 KiB
JavaScript
4 years ago
|
import { RoughGenerator } from './generator';
|
||
|
export class RoughCanvas {
|
||
|
constructor(canvas, config) {
|
||
|
this.canvas = canvas;
|
||
|
this.ctx = this.canvas.getContext('2d');
|
||
|
this.gen = new RoughGenerator(config);
|
||
|
}
|
||
|
draw(drawable) {
|
||
|
const sets = drawable.sets || [];
|
||
|
const o = drawable.options || this.getDefaultOptions();
|
||
|
const ctx = this.ctx;
|
||
|
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);
|
||
|
ctx.restore();
|
||
|
break;
|
||
|
case 'fillPath':
|
||
|
ctx.save();
|
||
|
ctx.fillStyle = o.fill || '';
|
||
|
const fillRule = (drawable.shape === 'curve' || drawable.shape === 'polygon') ? 'evenodd' : 'nonzero';
|
||
|
this._drawToContext(ctx, drawing, fillRule);
|
||
|
ctx.restore();
|
||
|
break;
|
||
|
case 'fillSketch':
|
||
|
this.fillSketch(ctx, drawing, o);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
fillSketch(ctx, drawing, o) {
|
||
|
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);
|
||
|
ctx.restore();
|
||
|
}
|
||
|
_drawToContext(ctx, drawing, rule = 'nonzero') {
|
||
|
ctx.beginPath();
|
||
|
for (const item of drawing.ops) {
|
||
|
const data = 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();
|
||
|
}
|
||
|
}
|
||
|
get generator() {
|
||
|
return this.gen;
|
||
|
}
|
||
|
getDefaultOptions() {
|
||
|
return this.gen.defaultOptions;
|
||
|
}
|
||
|
line(x1, y1, x2, y2, options) {
|
||
|
const d = this.gen.line(x1, y1, x2, y2, options);
|
||
|
this.draw(d);
|
||
|
return d;
|
||
|
}
|
||
|
rectangle(x, y, width, height, options) {
|
||
|
const d = this.gen.rectangle(x, y, width, height, options);
|
||
|
this.draw(d);
|
||
|
return d;
|
||
|
}
|
||
|
ellipse(x, y, width, height, options) {
|
||
|
const d = this.gen.ellipse(x, y, width, height, options);
|
||
|
this.draw(d);
|
||
|
return d;
|
||
|
}
|
||
|
circle(x, y, diameter, options) {
|
||
|
const d = this.gen.circle(x, y, diameter, options);
|
||
|
this.draw(d);
|
||
|
return d;
|
||
|
}
|
||
|
linearPath(points, options) {
|
||
|
const d = this.gen.linearPath(points, options);
|
||
|
this.draw(d);
|
||
|
return d;
|
||
|
}
|
||
|
polygon(points, options) {
|
||
|
const d = this.gen.polygon(points, options);
|
||
|
this.draw(d);
|
||
|
return d;
|
||
|
}
|
||
|
arc(x, y, width, height, start, stop, closed = false, options) {
|
||
|
const d = this.gen.arc(x, y, width, height, start, stop, closed, options);
|
||
|
this.draw(d);
|
||
|
return d;
|
||
|
}
|
||
|
curve(points, options) {
|
||
|
const d = this.gen.curve(points, options);
|
||
|
this.draw(d);
|
||
|
return d;
|
||
|
}
|
||
|
path(d, options) {
|
||
|
const drawing = this.gen.path(d, options);
|
||
|
this.draw(drawing);
|
||
|
return drawing;
|
||
|
}
|
||
|
}
|