HW3: all mandatory done except color
This commit is contained in:
parent
d2fe8d9f90
commit
fd6874744c
3 changed files with 170 additions and 44 deletions
|
@ -1,5 +1,13 @@
|
||||||
// vim: set ts=2 sw=2 et tw=80:
|
// vim: set ts=2 sw=2 et tw=80:
|
||||||
class App {
|
class App {
|
||||||
|
static get BRUSHES() {
|
||||||
|
return {
|
||||||
|
"PenBrush": new PenBrush(),
|
||||||
|
"DiscBrush": new DiscBrush(),
|
||||||
|
"StarBrush": new StarBrush(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constructor(conf) {
|
constructor(conf) {
|
||||||
if (!(typeof conf === 'object' && conf)) {
|
if (!(typeof conf === 'object' && conf)) {
|
||||||
throw new Error('Argument conf different from specification');
|
throw new Error('Argument conf different from specification');
|
||||||
|
@ -15,12 +23,17 @@ class App {
|
||||||
|
|
||||||
if (typeof conf.buttons === 'object' && conf.buttons) {
|
if (typeof conf.buttons === 'object' && conf.buttons) {
|
||||||
this.buttons = {}
|
this.buttons = {}
|
||||||
for (const b of ['clear', 'button', 'camera'])
|
for (const b of ['clear', 'undo', 'camera'])
|
||||||
this.buttons[b] = document.getElementById(conf.buttons[b]);
|
this.buttons[b] = document.getElementById(conf.buttons[b]);
|
||||||
|
|
||||||
if (this.buttons.clear)
|
if (this.buttons.clear)
|
||||||
this.buttons.clear.addEventListener('click', () =>
|
this.buttons.clear.addEventListener('click', () => {
|
||||||
this.ctx.clearRect(0, 0, canvas.width, canvas.height));
|
this.erase();
|
||||||
|
history.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.buttons.undo)
|
||||||
|
this.buttons.undo.addEventListener('click', () => history.pop(this));
|
||||||
|
|
||||||
if (this.buttons.camera)
|
if (this.buttons.camera)
|
||||||
this.buttons.camera.addEventListener('click', () => {
|
this.buttons.camera.addEventListener('click', () => {
|
||||||
|
@ -34,29 +47,22 @@ class App {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.canvas.addEventListener('mousedown', (e) => {
|
|
||||||
this.ctx.save();
|
|
||||||
this.ctx.lineWidth = 1;
|
this.ctx.lineWidth = 1;
|
||||||
this.ctx.moveTo(e.offsetX, e.offsetY);
|
|
||||||
this.ctx.beginPath();
|
|
||||||
this.mousedown = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.canvas.addEventListener('mousemove', (e) => this.mousedown && this.draw(e));
|
|
||||||
|
|
||||||
const endPath = (e) => {
|
|
||||||
if (this.mousedown) {
|
|
||||||
this.ctx.lineTo(e.offsetX, e.offsetY);
|
|
||||||
this.ctx.stroke();
|
|
||||||
this.ctx.restore();
|
|
||||||
this.mousedown = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.canvas.addEventListener('mouseup', endPath);
|
|
||||||
this.canvas.addEventListener('mouseout', endPath);
|
|
||||||
|
|
||||||
this.strokeStyle = this.constructor.defaultStrokeStyle;
|
this.strokeStyle = this.constructor.defaultStrokeStyle;
|
||||||
|
this.brush = "PenBrush";
|
||||||
|
|
||||||
|
const brushToolbar = document.querySelector('#brush-toolbar');
|
||||||
|
for (const name in App.BRUSHES) {
|
||||||
|
const b = document.createElement('button');
|
||||||
|
b.innerText = name;
|
||||||
|
b.addEventListener('click', () => this.brush = name);
|
||||||
|
brushToolbar.appendChild(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.canvas.addEventListener('mousedown', this.startPath.bind(this));
|
||||||
|
this.canvas.addEventListener('mousemove', this.draw.bind(this));
|
||||||
|
this.canvas.addEventListener('mouseup', this.endPath.bind(this));
|
||||||
|
this.canvas.addEventListener('mouseout', this.endPath.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
static get defaultStrokeStyle() {
|
static get defaultStrokeStyle() {
|
||||||
|
@ -74,12 +80,63 @@ class App {
|
||||||
this.ctx.strokeStyle = style;
|
this.ctx.strokeStyle = style;
|
||||||
}
|
}
|
||||||
|
|
||||||
draw(e) {
|
get brush() {
|
||||||
console.log(e);
|
return this._brush.name;
|
||||||
this.ctx.lineTo(e.offsetX, e.offsetY);
|
}
|
||||||
this.ctx.stroke();
|
|
||||||
|
set brush(brushName) {
|
||||||
|
this._brush = App.BRUSHES[brushName];
|
||||||
|
}
|
||||||
|
|
||||||
|
erase() {
|
||||||
|
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
startPath(e, record = true) {
|
||||||
this.ctx.beginPath();
|
this.ctx.beginPath();
|
||||||
this.ctx.moveTo(e.offsetX, e.offsetY);
|
this.ctx.moveTo(e.offsetX, e.offsetY);
|
||||||
|
|
||||||
|
if (record) {
|
||||||
|
history.initializeNewPath();
|
||||||
|
history.push(new Stroke(this.brush, e.offsetX, e.offsetY));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mousedown = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
draw(e, beginNew = true, record = true) {
|
||||||
|
if (this.mousedown) {
|
||||||
|
this._brush.draw(this.ctx, this.strokeStyle, e.offsetX, e.offsetY);
|
||||||
|
|
||||||
|
if (record) {
|
||||||
|
history.push(new Stroke(this.brush, e.offsetX, e.offsetY));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beginNew) {
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.moveTo(e.offsetX, e.offsetY);
|
||||||
|
} else {
|
||||||
|
this.mousedown = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
endPath(e, record = true) {
|
||||||
|
this.draw(e, false, record);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawPath(path) {
|
||||||
|
const last = path.length - 1;
|
||||||
|
const lastBrush = this.brush;
|
||||||
|
for (let i = 0; i <= last; i++) {
|
||||||
|
this.brush = path[i].brushName;
|
||||||
|
switch(i) {
|
||||||
|
case 0: this.startPath(path[i], false); break;
|
||||||
|
case last: this.endPath(path[i], false); break;
|
||||||
|
default: this.draw(path[i], true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.brush = lastBrush;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
class PenBrush {
|
// vim: set ts=2 sw=2 et tw=80:
|
||||||
|
|
||||||
|
class PenBrush {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.opacity = 1;
|
this.opacity = 1;
|
||||||
this.name = "PenBrush";
|
this.name = "PenBrush";
|
||||||
|
@ -11,9 +12,42 @@ class PenBrush {
|
||||||
ctx.lineTo(x, y);
|
ctx.lineTo(x, y);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO DiscBrush
|
class DiscBrush extends PenBrush {
|
||||||
//TODO StarBrush
|
static get RADIUS() { return 10; }
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.name = "DiscBrush";
|
||||||
|
}
|
||||||
|
|
||||||
|
draw(ctx, strokeStyle, x, y) {
|
||||||
|
ctx.beginPath(); // clear previous path starting
|
||||||
|
ctx.ellipse(x, y, 10, 10, 0, 0, 2 * Math.PI);
|
||||||
|
ctx.fill();
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StarBrush extends PenBrush {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.name = "StarBrush";
|
||||||
|
}
|
||||||
|
|
||||||
|
draw(ctx, strokeStyle, x, y) {
|
||||||
|
ctx.moveTo(x - 8, y - 3);
|
||||||
|
ctx.lineTo(x - 3, y - 3);
|
||||||
|
ctx.lineTo(x, y - 8);
|
||||||
|
ctx.lineTo(x + 3, y - 3);
|
||||||
|
ctx.lineTo(x + 8, y - 3);
|
||||||
|
ctx.lineTo(x + 4, y + 1);
|
||||||
|
ctx.lineTo(x + 4, y + 6);
|
||||||
|
ctx.lineTo(x, y + 3);
|
||||||
|
ctx.lineTo(x - 4, y + 6);
|
||||||
|
ctx.lineTo(x - 4, y + 1);
|
||||||
|
ctx.lineTo(x - 8, y - 3);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,39 @@
|
||||||
|
// vim: set ts=2 sw=2 et tw=80:
|
||||||
|
|
||||||
const history = {
|
const history = {
|
||||||
|
paths: []
|
||||||
|
}
|
||||||
|
|
||||||
|
history.pop = (app) => {
|
||||||
|
if (history.paths.length == 0) return;
|
||||||
|
history.paths.pop();
|
||||||
|
app.erase();
|
||||||
|
for (const path of history.paths) {
|
||||||
|
app.drawPath(path);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
history.initializeNewPath = () => {
|
||||||
|
history.paths.push([]);
|
||||||
|
};
|
||||||
|
|
||||||
|
history.push = (stroke) => {
|
||||||
|
if (!stroke instanceof Stroke) {
|
||||||
|
throw new Error(JSON.stringify(stroke) + ' is not a Stroke instance');
|
||||||
|
}
|
||||||
|
history.paths[history.paths.length - 1].push(stroke);
|
||||||
|
}
|
||||||
|
|
||||||
|
history.clear = () => {
|
||||||
|
history.paths = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Stroke {
|
||||||
|
constructor(brushName, x, y) {
|
||||||
|
this.brushName = brushName;
|
||||||
|
this.offsetX = x;
|
||||||
|
this.offsetY = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in a new issue