Анимация: создание градиентного изображения изображения из стороны в сторону (в непрозрачности)(так называемый эффект "мягкой очистки")
Извините, если название сбивает с толку. Я старался изо всех сил составить это, если вы поймете, о чем я прошу, не стесняйтесь предложить лучший заголовок в комментарии.
Анимацию, которую я пытаюсь сделать, легко можно сделать с помощью видеоредакторов, но мне кажется, что с CSS/JS мне не так просто: Прежде всего, я не говорю о скольжении изображения, изображение вообще не движется. Я хочу, чтобы он появлялся из стороны в сторону, но градиентно прозрачно. Представьте, что на изображении есть маска непрозрачности градиента, в результате чего непрозрачность его левого конца равна 1, а непрозрачности его правого конца - 0. Когда эта маска перемещается слева направо, это анимация, которую я хочу достичь.
Я могу разделить изображение на несколько частей и управлять непрозрачностью каждого, должно быть определенное количество частей, чтобы сделать всю анимацию гладкой и привлекательной.
Другой способ, которым я думаю, состоит в том, чтобы использовать canvas, где вы можете манипулировать изображением по пикселям, как на этой странице, я могу сделать
// get the image data object
var image = ctx.getImageData(0, 0, 500, 200);
// get the image data values
var imageData = image.data,
length = imageData.length;
// set every fourth value to 50
for(var i=3; i < length; i+=4){
imageData[i] = 50;
}
// after the manipulation, reset the data
image.data = imageData;
// and put the imagedata back to the canvas
ctx.putImageData(image, 0, 0);
Однако страница принимает только статическое изображение, но не анимацию. Мне интересно, не подорвет ли это производительность, если я воспользуюсь этим подходом. Кроме того, этот подход включает в себя много уродливых расчетов.
Я думаю, что то, чего я хочу достичь, не очень странно, так есть ли какой-нибудь плагин javascript для этого?
3 ответа
Анимацию, которую я пытаюсь сделать, легко можно сделать с помощью видеоредакторов, [...] изображение вообще не движется. Я хочу, чтобы это появилось из стороны в сторону
В видеоиндустрии мы называем это мягкой очисткой (AKA с мягкой кромкой), и это не слишком сложно сделать.
Все, что вам нужно, это альфа-маска, которую вы можете сделать, используя линейный градиент. Затем используйте свойства translate с контекстом в сочетании с составным режимом xor для его анимации.
Что делает режим xor, так это инвертирует альфа-канал на основе нарисованного к нему альфа-канала. Преимущество этого в том, что элемент canvas также становится прозрачным, поэтому любой фон может просвечивать. Вы можете сохранить комп по умолчанию. режим, который сделает черный фон вместо этого.
Градиент сделан следующим образом (значения цвета не имеют значения в режиме xor, только значения альфа-канала):
var g = ctx.createLinearGradient(0, 0, ctx.canvas.width, 0);
g.addColorStop(0, "rgba(0,0,0,0)");
g.addColorStop(1, "rgba(0,0,0,1)");
ctx.fillStyle = g;
(см. этот ответ о том, как избежать артефактов "ярких линий" путем создания сглаженного градиента).
Теперь создайте функцию, которая рисует полный кадр на основе позиции t
это нормализованное значение в сочетании с шириной холста - имейте в виду, что нам нужна двойная ширина: градиент + пространство для выхода градиента -
function render(t) {
var w = t * ctx.canvas.width; // width based on t
ctx.drawImage(img, 0, 0); // render bg. image
ctx.translate(-ctx.canvas.width + w, 0); // translate on x-axis
ctx.fillRect(0, 0, ctx.canvas.width * 2, ctx.canvas.height); // render gradient mask
}
Вызовите это в цикле анимации до t=2
, но при желании установить globalCompositeOperation
в xor
и мы готовы идти Сам цикл анимации сбросит преобразование для нас:
демонстрация
var ctx = c.getContext("2d"),
img = new Image,
t = 0, step = 0.02
// alpha mask
var g = ctx.createLinearGradient(0, 0, ctx.canvas.width, 0);
g.addColorStop(0, "rgba(0,0,0,0)");
g.addColorStop(1, "rgba(0,0,0,1)");
ctx.fillStyle = g;
ctx.globalCompositeOperation = "xor";
// load bg image
img.onload = animate;
img.src = "http://i.imgur.com/d0tZU7n.png";
function animate() {
ctx.setTransform(1,0,0,1,0,0); // reset any transformations
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
render(t);
t += step;
if (t <= 2) requestAnimationFrame(animate); // 2 since we need double width
else {t=0; setTimeout(animate, 2000)}; // just to repeat anim. for demo
}
function render(t) {
var w = t * ctx.canvas.width; // width based on t
ctx.drawImage(img, 0, 0);
ctx.translate(-ctx.canvas.width + w, 0); // translate on x-axis
ctx.fillRect(0, 0, ctx.canvas.width*2, ctx.canvas.height);
}
body {background:url(http://i.imgur.com/OT99vSA.jpg) repeat}
<canvas width=658 height=325 id=c></canvas>
Используйте составное свойство контекста, чтобы выполнить маскирование с помощью градиента. Создайте внеэкранный холст того же размера, что и изображение, или размер отображаемого холста, какой бы ни был наименьший.
Для каждого кадра создайте градиент с подходящими цветовыми ограничителями (цветовой формат CSS rgba(red, green, blue, alpha)
), чтобы установить альфа-значения.
Очистить экран за пределами экрана
ctxOffScreen.clearRect( 0, 0, ctxOffScreen.canvas.width, ctxOffScreen.canvas.height);
Затем установите составное значение для экрана холста в
ctxOffScreen.globalCompositeOperation = "source-over";
Рендеринг изображения на него
ctxOffScreen.drawImage(image, 0, 0, ctxOffScreen.canvas.width, ctxOffScreen.canvas.height);
Затем установите комп
ctxOffScreen.globalCompositeOperation = "destination-in";
Это будет соответствовать пикселям, уже нарисованным с тем же альфа-значением, которое есть у каждого, что вы рисуете дальше (маска градиента)
Затем установите стиль заливки для созданного вами градиента и нарисуйте прямоугольник поверх
ctxOffScreen.fillStyle = gradient;
ctxOffScreen.fillRect( 0, 0, ctxOffScreen.canvas.width, ctxOffScreen.canvas.height);
Затем просто визуализируйте экранный холст на экранный холст
ctx.drawImage(ctxOffScreen.canvas, 0, 0);
Если вы используете
ctxOffScreen.globalCompositeOperation = "destination-out";
вместо "destination-in"
Вы будете инвертировать маску, которую вы создали с градиентом.
В качестве альтернативы canvas
, ты можешь использовать svg
, CSS-градиенты не подлежат анимации, однако другие свойства svg
Есть, так что вы можете найти некоторые творческие способы для анимации градиентов в конце концов.
#Mask rect {
x: 400px;
transition: 1s;
}
svg:hover #Mask rect {
x: -400px;
}
svg {
border: 2px solid black;
background-color: #ee3377;
}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400">
<defs>
<linearGradient id="Gradient">
<stop offset="0" stop-color="white" stop-opacity="0" />
<stop offset=".5" stop-color="white" stop-opacity="1" />
</linearGradient>
<mask id="Mask">
<rect width="800" height="400" fill="url(#Gradient)" />
</mask>
</defs>
<image xlink:href="http://i.imgur.com/g3D5jNz.jpg" width="400" height="400" mask="url(#Mask)"></image>
</svg>
Вы могли бы, вероятно, оживить offset
собственности напрямую, я еще не проверял.