Цель этого проекта — сделать классный фон с произвольными фигурами и возможностью настройки.
Демонстрация: https://canvas-shapes-background.netlify.app/
Код: https://github.com/MaurerKrisztian/CanvasShapesBackground
Простой пример использования:
https://codepen.io/maurerkrisztian/pen/rNdGerb
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type='text/javascript' src="https://canvas-shapes-background.netlify.app/bundle.js"></script>
</head>
<body>
<canvas id="myCanvas"></canvas>
<script>
createShapeCanvas("myCanvas", {
modelNumbers: 11,
colors: ['blue', 'red', 'green', 'yellow'],
backgroundColor: 'black', //'none',
enabledModels: ['Triangle', 'Circle', 'Rect'],
minSpeed: 11,
maxSpeed: 11,
lineWidth: 3,
sizeMultiplier: 2,
startPosition: 'random' // 'middle' | 'random',
isFullScreen: true,
})
</script>
</body>
</html>
Я добавил конфигуратор в демо-версию: https://canvas-shapes-background.netlify.app/.
- Легко тестировать различные конфигурации и копировать настроенные параметры.
«createShapeCanvas» имеет 2 аргумента
- идентификатор холста
- конфигурация
config
- startPosition: ‘middle’ | ‘random’ начальная позиция модели
- enabledModels: типы фигур будут генерироваться случайным образом
- modelNumbers: генерировать это количество моделей из массива «enabledModels»
- colors: выбрать случайный цвет из этого массива для фигур
- backgroundColor: цвет фона холста, может быть «none»
- minSpeed: минимальная скорость фигуры
- maxSpeed: максимальная скорость фигуры
- lineWidth: ширина линии границы фигуры
- sizeMultiplier: умножение сгенерированного размера на это значение
- isFullScreen: полноэкранный или размер элемента
Как я это сделал?
Я использовал HTML Canvas.
Я хотел, чтобы он был легко расширяемым, поэтому абстрагировал некоторые вещи:
Animator:
- отвечает за настройку каждого кадра и вызов модели update().
Модель:
- имеет 2 основные функции:
- draw() — рисовать фигуру,
- update()
- как вести себя, основываясь на текущей позиции x,y и
- xd, dy aka куда двигаться и как быстро.Если вы запутались, как dx, dy работает, это в основном вектор.Он имеет направление (это будет направление модели) и длину (это будет скорость модели).
Пример модели:
export class CircleModel implements IModel {
static MODEL_NAME = 'Circle'
color: string;
constructor(private x: number, private y: number, private dx: number, private dy: number, private radius: number, private lineWidth: number = Setup.CONFIG.lineWidth) {
this.color = Utils.pickRandomFromArray<string>(Setup.CONFIG.colors)
}
draw(context: CanvasRenderingContext2D) {
context.lineWidth = this.lineWidth;
context.beginPath();
context.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
context.strokeStyle = this.color;
context.stroke();
context.lineWidth = DEFAULT_LINE_WIDTH;
}
update(context: CanvasRenderingContext2D) {
if (this.x > Context.canvasWidth - this.radius || this.x < 0 + this.radius) {
this.dx = -this.dx;
}
if (this.y > Context.canvasHeight - this.radius || this.y < 0 + this.radius) {
this.dy = -this.dy;
}
this.x = this.x + this.dx;
this.y = this.y + this.dy;
this.draw(context);
}
}
Я хотел сделать баунс со стороны холста, поэтому
Хорошо знать, где находится сторона холста.
Система координат:
x(0) — левая минимальная позиция, x(canvasWidth) — правая позиция, аналогично с y.
if (this.x > Context.canvasWidth - this.radius || this.x < 0 + this.radius) {
this.dx = -this.dx;
}
Если текущая позиция (центр круга) больше, чем ширина холста — радиус, измените направление x.
Аналогично с y.
В конце нужно установить новую позицию:
this.x = this.x + this.dx;
this.y = this.y + this.dy;
Я создал 3 модели: Cirle, Rect, Triangle.
Но вы можете легко добавить свою модель:
- создать модель
- добавить в ModelFactory
private static createRandomModel() {
const speed = Utils.generateRandom(Setup.CONFIG.minSpeed, Setup.CONFIG.maxSpeed)
const randoModelName = Utils.pickRandomFromArray(Setup.CONFIG.enabledModels)
switch (randoModelName) {
case CircleModel.MODEL_NAME:
return this.createRandomCircle(speed)
break;
case TriangleModel.MODEL_NAME:
return this.createRandomTriangle(speed)
break;
case RectModel.MODEL_NAME:
return this.createRandomRect(speed)
break;
default:
throw new Error(`Model not found with name: ${randoModelName}`)
}
}
Как создать импортируемый скрипт?
Я просто добавил функцию init в окно, поэтому вы можете импортировать скрипт пакета и вызвать эту функцию.
window.createShapeCanvas = createShapeCanvas
Планы на будущее:
- добавить больше моделей
- добавить больше опций конфигурации
- создать компонент react и опубликовать в npm