Градиент холста html5 в 4 углах

Есть ли какой-то трюк для создания градиента с несколькими остановками в 2D-пространстве? То, что я хотел бы сделать, это создать прямоугольник на моем холсте, а затем иметь разные цветные точки в каждом углу.

Я попытался создать 4 градиента, по одному в каждом углу, которые указывают на противоположный угол. (пробовал линейный и круговой). но это не дает желаемого эффекта, потому что центр всегда не в цвете по кругу.

Эффект, который я хочу, будет похож на два линейных горизонтальных градиента, расположенных друг над другом. а затем третий вертикальный линейный градиент, который не влияет на цвета первых двух градиентов, а просто затухает нижний градиент до верхнего градиента по мере его снижения. так что два верхних угла — это первый линейный градиент, а два нижних угла — второй линейный градиент.

Я пробовал играть с globalCompositeOperation, но самое близкое, что мне удалось достичь, это трехсторонний градиент. не 4.

Единственный способ, который я могу придумать для этого, — это построение моего прямоугольника по одной строке за раз. с каждой линией, имеющей линейный градиент, который пересчитывается и слегка изменяется, так что это второй градиент к тому времени, когда рисуется нижняя линия. но это не похоже на самый эффективный (или самый простой для программирования) способ сделать это.

Изображения

Наверное, я слишком новичок здесь, чтобы давать ссылки на фотографии. Но вот ссылка на 3 изображения на моих фотографиях Google.

https://plus.google.com/photos/116764547896287695338/albums/6094993027344790369?authkey=CJnZ0I3JxbOMag

изображение 1: первый градиент (настройка двух верхних угловых цветов)

изображение 2: второй градиент (установка двух нижних угловых цветов)

изображение 3: оба изображения 1 и 2 смешаны друг с другом по вертикали, так что два верхних цвета плавно переходят в два нижних цвета.


person tyler mackenzie    schedule 20.12.2014    source источник
comment
Можете ли вы сделать что-нибудь с помощью GIMP или PS, чтобы показать, что вы хотите создать?   -  person David    schedule 20.12.2014
comment
fillRect построчно должен быть быстрым. Сохраните результат в виде изображения или сохраните градиенты, если у вас есть проблемы с производительностью.   -  person GameAlchemist    schedule 21.12.2014


Ответы (1)


Прямой операции для чего-то подобного нет. В некоторых особых случаях (например, colorpicker) вы можете обойтись двумя отдельными градиентами.

Если вам нужен произвольный цвет для каждого угла, вам придется выполнять его попиксельно. Другими словами, выполняйте линейную интерполяцию как по x, так и по y для каждого пикселя. Я сделал нечто подобное для треугольных градиентов. .

По сравнению с тем четырехугольный вариант без особой трансформации был бы прост. Вам просто нужно будет пройти через каждый x и y холста, отслеживая состояние (два lerps на пиксель).

Пример кода

HTML

<canvas id="canvas" width="300" height="300"></canvas>

JS

main();

function main() {
    var canvas = document.getElementById("canvas");

    quadGradient(canvas, {
      topLeft: [1, 1, 1, 1],
      topRight: [0, 0, 0, 1],
      bottomLeft: [0, 0, 0, 1],
      bottomRight: [1, 1, 1, 1]
    });
}

function quadGradient(canvas, corners) {
    var ctx = canvas.getContext('2d');
    var w = canvas.width;
    var h = canvas.height;
    var gradient, startColor, endColor, fac;

    for(var i = 0; i < h; i++) {
        gradient = ctx.createLinearGradient(0, i, w, i);
        fac = i / (h - 1);

        startColor = arrayToRGBA(
          lerp(corners.topLeft, corners.bottomLeft, fac)
        );
        endColor = arrayToRGBA(
          lerp(corners.topRight, corners.bottomRight, fac)
        );

        gradient.addColorStop(0, startColor);
        gradient.addColorStop(1, endColor);

        ctx.fillStyle = gradient;
        ctx.fillRect(0, i, w, i);
    }
}

function arrayToRGBA(arr) {
    var ret = arr.map(function(v) {
        // map to [0, 255] and clamp
        return Math.max(Math.min(Math.round(v * 255), 255), 0);
    });

    // alpha should retain its value
    ret[3] = arr[3];

    return 'rgba(' + ret.join(',') + ')';
}

function lerp(a, b, fac) {
    return a.map(function(v, i) {
        return v * (1 - fac) + b[i] * fac;
    });
}

JSbin

person Juho Vepsäläinen    schedule 20.12.2014
comment
не будет ли это медленно? из того, что я читал, Canvas на самом деле не был разработан для манипулирования пикселем за пикселем. Я пытался что-то сделать с созданием моего прямоугольника построчно. вроде бы дает хорошие результаты, просто не очень быстро. - person tyler mackenzie; 21.12.2014
comment
да. Это очень медленный вариант, но, насколько я знаю, нет лучшего способа справиться с ним. - person Juho Vepsäläinen; 21.12.2014
comment
Вы можете попытаться отобразить отдельные линии градиента с помощью Canvas API. Это может дать какое-то ускорение. Вам все равно придется оценивать каждую строку отдельно. - person Juho Vepsäläinen; 21.12.2014
comment
@markE Готово. Я, вероятно, преобразовать это в сообщение в блоге, а также. - person Juho Vepsäläinen; 23.12.2014