Skip to content

Commit

Permalink
feat(deckgo#66): draw multiple circles
Browse files Browse the repository at this point in the history
Create Interface for drawables
Abstract x/y to point
Drawables know how to draw themselfes
Save currently Drawing element at last position in array and change on move
Clear Canvas and draw whole array at once
  • Loading branch information
janscheidegger committed Oct 23, 2019
1 parent 41f7b9e commit 5a6ad8f
Showing 1 changed file with 112 additions and 36 deletions.
148 changes: 112 additions & 36 deletions remote/src/app/components/app-draw/app-draw.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,74 @@
import {Component, Element, Method, Prop, State, Watch, EventEmitter, Event, h} from '@stencil/core';
import {Component, Element, Event, EventEmitter, h, Method, Prop, State, Watch} from '@stencil/core';

import {unifyEvent} from '@deckdeckgo/utils';

// Types
import {DeckdeckgoDrawAction, DeckdeckgoEventType, DeckdeckgoEventEmitter} from '@deckdeckgo/types';

import {DeckdeckgoDrawAction, DeckdeckgoEventEmitter, DeckdeckgoEventType} from '@deckdeckgo/types';
// Services
import {CommunicationService} from '../../services/communication/communication.service';

interface Point {
x: number;
y: number;
}

interface Drawable {
draw(ctx: CanvasRenderingContext2D)
}

class Circle implements Drawable {

private readonly from: Point;
private readonly to: Point;
private readonly color: string;

constructor(from: Point, to: Point, color: string) {
this.from = from;
this.to = to;
this.color = color;
}

draw(ctx: CanvasRenderingContext2D) {
ctx.beginPath();

ctx.moveTo(this.from.x, this.from.y + (this.to.y - this.from.y) / 2);
ctx.bezierCurveTo(this.from.x, this.from.y, this.to.x, this.from.y, this.to.x, this.from.y + (this.to.y - this.from.y) / 2);
ctx.bezierCurveTo(this.to.x, this.to.y, this.from.x, this.to.y, this.from.x, this.from.y + (this.to.y - this.from.y) / 2);

ctx.strokeStyle = this.color;
ctx.lineWidth = 3;

ctx.stroke();
ctx.closePath();
}
}

class Pencil implements Drawable {

private readonly from: Point;
private readonly to: Point;
private readonly color: string;

constructor(from: Point, to: Point, color: string) {
this.from = from;
this.to = to;
this.color = color;
}

draw(ctx: CanvasRenderingContext2D) {
ctx.beginPath();

ctx.moveTo(this.from.x, this.from.y);
ctx.lineTo(this.to.x, this.to.y);
ctx.strokeStyle = this.color;
ctx.lineWidth = 3;

ctx.stroke();
ctx.closePath();

}
}


@Component({
tag: 'app-draw',
styleUrl: 'app-draw.scss',
Expand All @@ -29,6 +90,8 @@ export class AppDraw {
private startX: number;
private startY: number;

private drawables: Drawable[] = [];

private leftOffset: number = 0;

private drawEvents: boolean = false;
Expand Down Expand Up @@ -144,12 +207,30 @@ export class AppDraw {
this.startX = unifyEvent(e).clientX - this.leftOffset;
this.startY = unifyEvent(e).clientY - this.heightOffset;

if (this.action === DeckdeckgoDrawAction.CIRCLE) {
this.drawables.push(new Circle({x: this.startX, y: this.startY}, {
x: this.startX,
y: this.startY
}, this.color))
}

this.drawEvents = true;
};

private endEvent = (e: MouseEvent) => {
this.emit(DeckdeckgoEventType.END_DRAWING, e);

const toX: number = unifyEvent(e).clientX - this.leftOffset;
const toY: number = unifyEvent(e).clientY - this.heightOffset;


if (this.action === DeckdeckgoDrawAction.CIRCLE) {
this.drawables[this.drawables.length - 1] = new Circle({x: this.startX, y: this.startY}, {
x: toX,
y: toY
}, this.color);
}

this.drawEvents = false;
};

Expand All @@ -163,40 +244,29 @@ export class AppDraw {
const toX: number = unifyEvent(e).clientX - this.leftOffset;
const toY: number = unifyEvent(e).clientY - this.heightOffset;

this.draw(toX, toY);
};

private draw(toX: number, toY: number) {
this.ctx.beginPath();
if (this.action === DeckdeckgoDrawAction.PENCIL) {
this.drawables.push(new Pencil({x: this.startX, y: this.startY}, {x: toX, y: toY}, this.color));
this.startX = toX;
this.startY = toY;
}

if (this.action === DeckdeckgoDrawAction.CIRCLE) {
this.drawCircle(toX, toY);
} else {
this.drawPencil(toX, toY);
this.drawables[this.drawables.length - 1] = new Circle({x: this.startX, y: this.startY}, {
x: toX,
y: toY
}, this.color);
}
this.draw();
};

this.ctx.strokeStyle = this.color;
this.ctx.lineWidth = 3;

this.ctx.stroke();
this.ctx.closePath();
}

private drawPencil(toX: number, toY: number) {
this.ctx.moveTo(this.startX, this.startY);
this.ctx.lineTo(toX, toY);

this.startX = toX;
this.startY = toY;
}

private drawCircle(toX: number, toY: number) {
private draw() {
this.ctx.clearRect(-1 * this.leftOffset, 0, this.width, this.height);
this.ctx.moveTo(this.startX, this.startY + (toY - this.startY) / 2);
this.ctx.bezierCurveTo(this.startX, this.startY, toX, this.startY, toX, this.startY + (toY - this.startY) / 2);
this.ctx.bezierCurveTo(toX, toY, this.startX, toY, this.startX, this.startY + (toY - this.startY) / 2);
for (const drawable of this.drawables) {
drawable.draw(this.ctx);
}
}


private switchTool(e: UIEvent, action: DeckdeckgoDrawAction) {
e.stopPropagation();

Expand Down Expand Up @@ -238,7 +308,10 @@ export class AppDraw {
return new Promise<void>((resolve) => {
e.stopPropagation();

this.communicationService.emit({type: DeckdeckgoEventType.CLEAR_SLIDE, emitter: DeckdeckgoEventEmitter.APP});
this.communicationService.emit({
type: DeckdeckgoEventType.CLEAR_SLIDE,
emitter: DeckdeckgoEventEmitter.APP
});

this.ctx.beginPath();
this.ctx.clearRect(-1 * this.leftOffset, 0, this.width, this.height);
Expand All @@ -252,7 +325,7 @@ export class AppDraw {
render() {

const styleColorPicker = {
color: this.color === 'red' ? 'black' : 'red'
color: this.color === 'red' ? 'black' : 'red'
};

return ([
Expand All @@ -265,7 +338,8 @@ export class AppDraw {
{this.renderPencilRubber()}
</ion-fab-list>
<ion-fab-list side="top">
<ion-fab-button color="medium" style={styleColorPicker} onClick={(e: UIEvent) => this.switchColor(e)}>
<ion-fab-button color="medium" style={styleColorPicker}
onClick={(e: UIEvent) => this.switchColor(e)}>
<ion-icon name="color-palette"></ion-icon>
</ion-fab-button>
<ion-fab-button color="medium" onClick={(e: UIEvent) => this.clear(e)}>
Expand All @@ -279,13 +353,15 @@ export class AppDraw {
private renderPencilRubber() {
if (this.action !== DeckdeckgoDrawAction.PENCIL) {
return (
<ion-fab-button color="medium" onClick={(e: UIEvent) => this.switchTool(e, DeckdeckgoDrawAction.PENCIL)}>
<ion-fab-button color="medium"
onClick={(e: UIEvent) => this.switchTool(e, DeckdeckgoDrawAction.PENCIL)}>
<ion-icon name="create"></ion-icon>
</ion-fab-button>
);
} else {
return (
<ion-fab-button color="medium" onClick={(e: UIEvent) => this.switchTool(e, DeckdeckgoDrawAction.CIRCLE)}>
<ion-fab-button color="medium"
onClick={(e: UIEvent) => this.switchTool(e, DeckdeckgoDrawAction.CIRCLE)}>
<ion-icon name="radio-button-off"></ion-icon>
</ion-fab-button>
);
Expand Down

0 comments on commit 5a6ad8f

Please sign in to comment.