В проекте я использовал Canvas для реализации карты водных волн, и здесь я поделюсь принципом его реализации. Когда вы впервые видите волну, вы можете не знать, с чего начать. Давайте посмотрим на характеристики волны, и вы будете вдохновлены.
Да, кто-то наверняка думает, чтосинус косинус! Для колебаний с очень малой крутизной волны обычно выбирается синусоида или косинусоидальная кривая для представления формы волны, которая является наиболее простым и близким выражением к реальной форме волны. Здесь я выбрал синусоиду для достижения.
Прежде чем говорить об идее реализации, давайте вспомним основы синусоиды.
синусоидальный
Формула синусоиды:y = A sin(Bx + C) + D
Амплитуда равна A, и чем больше значение A, тем круче кривая:
Период равен 2π/B. Когда значение B больше 1, чем больше значение B, тем короче период. Когда значение B меньше 1 и больше 0, период становится длиннее:
Фазовый сдвиг равен -C / B. В случае постоянного B, когда C положителен, кривая движется влево, а когда C отрицателен, кривая движется вправо:
Вертикальное смещение равно D, а кривая управления движется вверх и вниз:
Реализовать идеи
Зная некоторые свойства синусоиды, мы можем использовать эти свойства для управления волной,
- Амплитуда: управляет высотой волн.
- Период: управляет шириной волны.
- Phase Shift: управляет горизонтальным движением волн.
- Вертикальное смещение: контроль высоты уровня воды
Реализация анимационного эффекта в основном осуществляется с помощьюсдвиг фазы, непрерывно перемещая кривую по горизонтали, чтобы создать ощущение движения волны, а затем вы можете нарисовать несколько кривых и управлять свойствами между кривыми (высота, ширина, скорость движения), что приводит к ухудшению зрения и ощущению волнистости.
С этими идеями, давайте помедленнее.
Рисование кривой
Инициализировать, определить ширину и высоту Canvas:
componentDidMount() {
const self = this;
const canvas = this.refs.canvas;
canvas.height = 500;
canvas.width = 500;
this.canvas = canvas;
this.canvasWidth = canvas.width;
this.canvasHeight = canvas.height;
const ctx = canvas.getContext('2d');
this.drawSin(ctx);
}
render() {
return (
<div className="content page">
<canvas ref="canvas"></canvas>
</div>
);
}
В соответствии с конфигурацией параметров, определяющих волну, по формуле:y = 波浪高度 * sin(x * 波浪宽度 + 水平位移)
, чтобы нарисовать синусоиду:
drawSin(ctx) {
const points = [];
const canvasWidth = this.canvasWidth;
const canvasHeight = this.canvasHeight;
const startX = 0;
const waveWidth = 0.05; // 波浪宽度,数越小越宽
const waveHeight = 20; // 波浪高度,数越大越高
const xOffset = 0; // 水平位移
ctx.beginPath();
for (let x = startX; x < startX + canvasWidth; x += 20 / canvasWidth) {
const y = waveHeight * Math.sin((startX + x) * waveWidth + xOffset);
points.push([x, (canvasHeight / 2) + y]);
ctx.lineTo(x, (canvasHeight / 2) + y);
}
ctx.lineTo(canvasWidth, canvasHeight);
ctx.lineTo(startX, canvasHeight);
ctx.lineTo(points[0][0], points[0][1]);
ctx.stroke();
}
После того, как кривая нарисована, кривая статична, как заставить ее двигаться? Как упоминалось в предыдущей идее, можно изменить смещение по горизонтали, постоянно меняя (xOffset) для перемещения кривой по горизонтали для создания динамического эффекта.
componentDidMount() {
...
this.xOffset = 0; // 初始偏移
this.speed = 0.1; // 偏移速度
requestAnimationFrame(this.draw.bind(this, canvas));
}
draw() {
const canvas = this.canvas;
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 曲线绘制
this.drawSin(ctx, this.xOffset);
this.xOffset += this.speed;
requestAnimationFrame(this.draw.bind(this));
}
drawSin(ctx, xOffset = 0) {
...
}
Шариковая тяга
Теперь, когда наш прототип вышел, кривые и динамические эффекты были реализованы.Видно, что вода установлена на прямоугольном параллелепипеде.Что, если вода установлена на сфере?
Здесь мы используем Canvasclip()
метод определенияобласть отсечения, после определения области отсечения браузер ограничит все операции рисования, выполняемые в этой области, поэтому мы можем сначала нарисовать круг, а затем определить, что область, нарисованная позже, может находиться только в пределах области этого круга, а лишняя часть не будет отображаться, это создаст эффект волны в сфере.
draw() {
...
if (!this.isDrawCircle) {
this.drawCircle(ctx);
}
this.drawSin(ctx, this.xOffset);
this.xOffset += this.speed;
requestAnimationFrame(this.draw.bind(this));
}
drawCircle(ctx) {
const r = this.canvasWidth / 2;
const lineWidth = 5;
const cR = r - (lineWidth);
ctx.lineWidth = lineWidth;
ctx.beginPath();
ctx.arc(r, r, cR, 0, 2 * Math.PI);
ctx.stroke();
ctx.clip();
this.isDrawCircle = true;
}
контроль уровня воды
Вы чувствуете немного, и это еще немного меньше, то есть контролировать уровень воды, то есть процент, отображаемый на данные. Если вы обратите внимание раньше, вы найдете вычисление координаты y синусоиды и, наконец, добавитеcanvasHeight / 2
, На самом деле, здесь нужно установить уровень воды.
Давайте взглянем:y = A sin(Bx + C) + D, высота кривой определяется A и D, A контролирует высоту волны, а фактический уровень воды по-прежнему определяетсяDконтролировать.
Высота уровня воды, визуальное значение данныхпроцент, предполагая, что текущий процент равен 80%, высота уровня воды равнаcanvasHeight * 0.8
, координаты, отображаемые в систему координат y, равныcanvasHeight * (1 - 0.8)
. (Начало координат находится в верхнем левом углу).
Помимо горизонтального движения синусоиды в анимационном эффекте мы добавляем анимационный эффект повышения уровня воды:
componentDidMount() {
...
this.xOffset = 0;
this.speed = 0.1;
// 水位数值
this.rangeValue = 0.6;
// 初始水位
this.nowRange = 0;
requestAnimationFrame(this.draw.bind(this, canvas));
}
draw() {
...
this.drawSin(ctx, this.xOffset, this.nowRange);
this.xOffset += this.speed;
if (this.nowRange < this.rangeValue) {
this.nowRange += 0.01;
}
requestAnimationFrame(this.draw.bind(this));
}
drawCircle(ctx) {
...
}
drawSin(ctx, xOffset = 0, nowRange = 0) {
...
for (let x = startX; x < startX + canvasWidth; x += 20 / canvasWidth) {
const y = waveHeight * Math.sin((startX + x) * waveWidth + xOffset);
points.push([x, (1 - nowRange) * canvasHeight + y]);
ctx.lineTo(x, (1 - nowRange) * canvasHeight + y);
}
...
}
окончательный эффект
Наконец, мы добавляем цвет и добавим кривую синусоиды, и будут волны.
При рисовании сферической формы выше мы использовали метод вырезания области, чтобы добиться этого.Некоторые люди определенно подумают, что в настоящее время мне не нужно использовать круг для вырезания, а использовать другие формы, чтобы создать эффект вода в разных емкостях.
Исходный код:GitHub.com/beyond гонконг б/ я…