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:
|
||||
class App {
|
||||
static get BRUSHES() {
|
||||
return {
|
||||
"PenBrush": new PenBrush(),
|
||||
"DiscBrush": new DiscBrush(),
|
||||
"StarBrush": new StarBrush(),
|
||||
};
|
||||
}
|
||||
|
||||
constructor(conf) {
|
||||
if (!(typeof conf === 'object' && conf)) {
|
||||
throw new Error('Argument conf different from specification');
|
||||
|
@ -15,12 +23,17 @@ class App {
|
|||
|
||||
if (typeof conf.buttons === 'object' && conf.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]);
|
||||
|
||||
if (this.buttons.clear)
|
||||
this.buttons.clear.addEventListener('click', () =>
|
||||
this.ctx.clearRect(0, 0, canvas.width, canvas.height));
|
||||
this.buttons.clear.addEventListener('click', () => {
|
||||
this.erase();
|
||||
history.clear();
|
||||
});
|
||||
|
||||
if (this.buttons.undo)
|
||||
this.buttons.undo.addEventListener('click', () => history.pop(this));
|
||||
|
||||
if (this.buttons.camera)
|
||||
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.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.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() {
|
||||
|
@ -74,12 +80,63 @@ class App {
|
|||
this.ctx.strokeStyle = style;
|
||||
}
|
||||
|
||||
draw(e) {
|
||||
console.log(e);
|
||||
this.ctx.lineTo(e.offsetX, e.offsetY);
|
||||
this.ctx.stroke();
|
||||
get brush() {
|
||||
return this._brush.name;
|
||||
}
|
||||
|
||||
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.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() {
|
||||
this.opacity = 1;
|
||||
this.name = "PenBrush";
|
||||
|
@ -11,9 +12,42 @@ class PenBrush {
|
|||
ctx.lineTo(x, y);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//TODO DiscBrush
|
||||
//TODO StarBrush
|
||||
class DiscBrush extends PenBrush {
|
||||
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 = {
|
||||
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