Skip to content

Instantly share code, notes, and snippets.

@gvergnaud
Last active April 13, 2020 09:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gvergnaud/01889a31815febcfb08aad93720a0d32 to your computer and use it in GitHub Desktop.
Save gvergnaud/01889a31815febcfb08aad93720a0d32 to your computer and use it in GitHub Desktop.
Some useful canvas utility functions to draw circles, lines and texts
type Point = { x: number; y: number };
type Circle = Point & { radius: number; color: string };
type StrokeCircle = Circle & {
width: number;
isDashed: boolean;
lineDash: number[];
};
type Line = { width: number; color: string; points: Point[] };
type Text = Point & {
text: string;
fontStyle: string;
color: string;
};
const drop = <T>(n: number, xs: T[]): T[] => xs.slice(n);
export const drawBackground = (
context: CanvasRenderingContext2D,
color: string
) => {
context.fillStyle = color;
context.fillRect(0, 0, context.canvas.width, context.canvas.height);
};
export const drawCircle = (
context: CanvasRenderingContext2D,
{ x = 0, y = 0, radius = 5, color = "#000" }: Partial<Circle> = {}
) => {
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fillStyle = color;
context.fill();
};
export const drawCircles = (
context: CanvasRenderingContext2D,
circles: Partial<Circle>[] = []
) => circles.forEach((c) => drawCircle(context, c));
export const drawStrokeCircle = (
context: CanvasRenderingContext2D,
{
x = 0,
y = 0,
radius = 10,
width = 1,
color = "#000",
isDashed = false,
lineDash = [5, 15],
}: Partial<StrokeCircle> = {}
) => {
if (isDashed) context.setLineDash(lineDash);
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.lineWidth = width;
context.strokeStyle = color;
context.stroke();
if (isDashed) context.setLineDash([]);
};
export const drawLine = (
context: CanvasRenderingContext2D,
{ width = 1, points = [], color = "#000" }: Partial<Line> = {}
) => {
if (points.length) {
context.beginPath();
context.moveTo(points[0].x, points[0].y);
drop(1, points).forEach(({ x, y }) => context.lineTo(x, y));
context.lineWidth = width;
context.strokeStyle = color;
context.stroke();
context.closePath();
}
};
export const drawLines = (
context: CanvasRenderingContext2D,
lines: Partial<Line>[] = []
) => lines.forEach((l) => drawLine(context, l));
export const drawSmoothedLine = (
context: CanvasRenderingContext2D,
{ width = 1, points = [], color = "#000" }: Partial<Line> = {}
) => {
if (points.length) {
context.beginPath();
context.moveTo(points[0].x, points[0].y);
let i: number;
for (i = 1; i < points.length - 2; i++) {
var xc = (points[i].x + points[i + 1].x) / 2;
var yc = (points[i].y + points[i + 1].y) / 2;
context.quadraticCurveTo(points[i].x, points[i].y, xc, yc);
}
// curve through the last two points
if (points[i] && points[i + 1]) {
context.quadraticCurveTo(
points[i].x,
points[i].y,
points[i + 1].x,
points[i + 1].y
);
}
context.lineWidth = width;
context.strokeStyle = color;
context.stroke();
context.closePath();
}
};
export const drawSmoothedLines = (
context: CanvasRenderingContext2D,
lines: Partial<Line>[] = []
) => lines.forEach((l) => drawSmoothedLine(context, l));
// getColorValue :: number -> number -> number
export const getColorValue = (color: number, ratio: number) =>
Math.round(color * ratio);
export const drawText = (
context: CanvasRenderingContext2D,
{ text, x, y, fontStyle, color }: Text
) => {
context.font = fontStyle;
context.fillStyle = color;
context.fillText(text, x, y);
};
export const drawTexts = (context: CanvasRenderingContext2D, texts: Text[]) =>
texts.forEach((t) => drawText(context, t));
export const scaleToRightRatio = (context: CanvasRenderingContext2D) => {
const { width, height } = context.canvas.getBoundingClientRect();
context.canvas.width = width * devicePixelRatio;
context.canvas.height = height * devicePixelRatio;
context.scale(devicePixelRatio, devicePixelRatio);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment