html5 градиент на платно в 4 ъгъла

Има ли някакъв трик за създаване на градиент с множество спирки в 2d пространство? Това, което бих искал да направя, е да създам правоъгълник в моето платно и след това да поставя различен цвят на всеки ъгъл.

Опитах се да създам 4 градиента, по един във всеки ъгъл, който сочи към противоположния ъгъл. (пробвани линейни и кръгови). но това не създава ефекта, който искам, защото центърът винаги е без цвят по кръгъл начин.

Ефектът, който искам, би бил подобен на 2 линейни хоризонтални градиента, поставени един върху друг. и след това 3-ти вертикален линеен градиент, който не засяга цветовете на първите два градиента, а просто избледнява долния градиент в горния градиент, докато върви надолу. така че горните два ъгъла са първият линеен градиент, а долните два ъгъла са вторият линеен градиент.

Опитах да си играя с globalCompositeOperation, но най-близкото, което успях да постигна, е 3-странен градиент. не 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