Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Lit-Element 2d Canvas
import { html, LitElement, property, query } from 'lit-element';
export abstract class Lit2DCanvas extends LitElement {
@query('#base') canvas!: HTMLCanvasElement;
@property({ type: Number }) width: number | undefined;
@property({ type: Number }) height: number | undefined;
canvasWidth = 400;
canvasHeight = 400;
render() {
return html`
<canvas
id="base"
width=${this.canvasWidth}
height=${this.canvasHeight}
></canvas>
`;
}
async firstUpdated() {
requestAnimationFrame((timestamp) => this._loop(timestamp));
this.canvas.addEventListener(
'touchstart',
(e) => {
e.preventDefault();
const touches = e.touches;
const points: TouchPoint[] = [];
for (let i = 0; i < touches.length; i++) {
const touch = touches[i];
points.push({ x: touch.clientX, y: touch.clientY });
}
this.onTap(points);
},
false,
);
this.canvas.addEventListener(
'mousedown',
(e) => {
e.preventDefault();
this.onTap([{ x: e.x, y: e.y }]);
return;
},
false,
);
window.addEventListener('resize', (e) => this._updateSize(), false);
this._updateSize();
}
_updateSize() {
this.canvasWidth = this.width || window.innerWidth;
this.canvasHeight = this.height || window.innerHeight;
this.canvas.width = this.canvasWidth;
this.canvas.height = this.canvasHeight;
}
_lastRender = 0;
_loop(timestamp: number) {
const progress = timestamp - this._lastRender;
this.loop(progress);
this._lastRender = timestamp;
const ctx = this.canvas.getContext('2d');
if (ctx) {
ctx.save();
ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.draw(ctx);
ctx.restore();
}
requestAnimationFrame((timestamp) => this._loop(timestamp));
}
loop(progress: number) {}
draw(context: CanvasRenderingContext2D) {}
onTap(points: TouchPoint[]) {}
}
export interface TouchPoint {
x: number;
y: number;
}
import { css, customElement } from 'lit-element';
import { Lit2DCanvas, TouchPoint } from './lit-2d-canvas';
@customElement('star-demo')
export class StarDemo extends Lit2DCanvas {
static styles = css``;
state = {
width: 20,
stars: [this.randomStar(40, 50)],
};
draw(ctx: CanvasRenderingContext2D) {
super.draw(ctx);
for (const star of this.state.stars) {
this.drawStar(
ctx,
star.centerX,
star.centerY,
star.points,
star.outerRadius,
star.innerRadius,
star.fillStyle,
star.stroke,
star.line,
);
}
}
loop(progress: number) {
super.loop(progress);
const change = progress * 0.005;
for (const star of this.state.stars) {
if (star.innerRadius < 20) star.forward = true;
if (star.innerRadius > 30) star.forward = false;
star.innerRadius += star.forward ? change : -change;
star.outerRadius += star.forward ? change : -change;
}
}
onTap(points: TouchPoint[]) {
super.onTap(points);
if (points.length > 0) {
const point = points[0];
this.state.stars.push(this.randomStar(point.x, point.y));
}
}
drawStar(
ctx: CanvasRenderingContext2D,
centerX: number,
centerY: number,
points: number,
outerRadius: number,
innerRadius: number,
fillStyle: string,
stroke: string,
line: number,
) {
ctx.save();
ctx.beginPath();
ctx.moveTo(centerX, centerY + outerRadius);
for (let i = 0; i < 2 * points + 1; i++) {
const r = i % 2 == 0 ? outerRadius : innerRadius;
const a = (Math.PI * i) / points;
ctx.lineTo(centerX + r * Math.sin(a), centerY + r * Math.cos(a));
}
ctx.closePath();
ctx.fillStyle = fillStyle;
ctx.fill();
ctx.strokeStyle = stroke;
ctx.lineWidth = line;
ctx.stroke();
ctx.restore();
}
randomStar(x: number, y: number) {
const radius = randomInt(40);
const colors = [
'red',
'green',
'blue',
'purple',
'yellow',
'black',
'grey',
'navy',
'orange',
];
return {
forward: true,
centerX: x,
centerY: y,
points: randomInt(12) < 3 ? 3 : randomInt(12),
outerRadius: radius + 10,
innerRadius: radius - 10,
fillStyle: colors[randomInt(colors.length)],
stroke: colors[randomInt(colors.length)],
line: randomInt(4),
};
}
}
function randomInt(max: number): number {
return Math.floor(Math.random() * Math.floor(max));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment