HW3: all mandatory done except color

This commit is contained in:
Claudio Maggioni 2019-10-06 20:22:53 +02:00
parent d2fe8d9f90
commit fd6874744c
3 changed files with 170 additions and 44 deletions

View file

@ -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;
} }
} }

View file

@ -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();
}
}

View file

@ -1,4 +1,39 @@
const history = { // vim: set ts=2 sw=2 et tw=80:
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;
}
}