HTML Canvas — переход цвета между фигурами (фигуры не перекрываются)

#javascript #html5-canvas

#javascript #html5-холст

Вопрос:

Изображение — это то, чего я с нетерпением жду, используя html canvas, без использования размытия или тени.

введите описание изображения здесь

Вопрос: Есть ли способ получить правую часть изображения из левой части изображения?

Причина проблемы (базовый рисунок) здесь

 var canvas = document.createElement('canvas'),
d = canvas.width = canvas.height = 400,
sq_size = d / 10,
ctx = canvas.getContext('2d');
document.body.appendChild(canvas); 

var color=["rgb(10,110,10)", "rgb(81,169,255)","rgb(81,239,255)", 
"rgb(81,255,202)", 
"rgb(81,255,132)","rgb(99,255,81)","rgb(169,255,81)", 
"rgb(239,255,81)", "rgb(255,202,81)","rgb(255,132,81)"];

var x=0, len=color.length;
for(var i=0; i < d; i  ){
  while(x < d) {
    var c = Math.floor(Math.random() * len);
    
    ctx.fillStyle = color[c];
    ctx.fillRect(x,i,sq_size,sq_size);
    x = x   sq_size;
  }
  x = 0;
  i = i sq_size;
}
  

Комментарии:

1. Вы изменили вопрос «Должен работать с набором данных в миллионах». Миллионы чего? Вместо того, чтобы менять вопрос после принятия ответа, задайте новый вопрос.

2. @Blindman67 В ответе было редактирование. Это было отклонено. Решение работает. Я не принял это, потому что время рендеринга значительно увеличилось по сравнению с большим набором данных.

3. Я отклонил редактирование, потому что оно было неправильным, Ответ — O (1), а не O (2 * n), как утверждает ваше редактирование. Ваша правка должна была быть комментарием. Ответ рисует только 2 изображения.

Ответ №1:

Самое близкое, что вы можете получить, не применяя размытие.

Вы можете использовать сглаживание изображения ctx.imageSmoothingEnabled для размытия изображения с очень низким разрешением. Затем смешайте размытые и незамутненные изображения, используя ctx.globalAlpha

Пример

pixelSize управляет степенью размытия. Значение 1 является максимальным значением и уменьшается по мере увеличения этого значения. Должно быть целочисленное значение, например 1, 2, 3, 4, …

Примечание результаты будут отличаться в зависимости от используемого устройства и браузера / версии.

 requestAnimationFrame(animationLoop);
const size = canvas.width;
const ctx = canvas.getContext('2d');
var mix = 123; // amount to transition 
const transitionTime = 2; // seconds per transition
const swatches = [0,1,2];
const pixelSize = 2;
// eCurve p = 1 linear curve [default p = 2] is quadratic curve p = 3 cubic curve and so on.
const eCurve = (v, p = 2) =>  v < 0 ? 0 : v > 1 ? 1 : v ** p / (v ** p   (1 - v) ** p);
const cols = [
   [10, 110, 10], [81, 169, 255], [81, 239, 255], [81, 255, 202], [81, 255, 132], 
   [99, 255, 81], [169, 255, 81], [239, 255, 81], [255,202, 81], [255,132,81]
];
const img = document.createElement("canvas");
img.height = img.width = swatches.length * pixelSize;
const imgCtx = img.getContext('2d');
function randomSwatch() {
    swatches.forEach(y => { swatches.forEach(x => {
          imgCtx.fillStyle = "rgb(" cols[Math.random() * cols.length | 0].join(",") ")";
          imgCtx.fillRect(x * pixelSize, y * pixelSize, pixelSize, pixelSize);
     }); });
}
function animationLoop() {
     mix = (mix >= 4 ? (randomSwatch(), 0) : mix)   1 / (transitionTime * 60);
     ctx.globalAlpha = 1;
     ctx.imageSmoothingEnabled = false;
     ctx.drawImage(img, 0, 0, size, size);
     ctx.imageSmoothingEnabled = true;
     const a = mix % 2;
     ctx.globalAlpha = eCurve(a > 1 ? 2 - a : a, 3);
     ctx.drawImage(img, 0, 0, size, size);
     requestAnimationFrame(animationLoop);
}  
 <canvas id="canvas" height="300" width="300"></canvas>  

Ответ №2:

Это решение работает лучше всего для меня. Соответствует моему большому набору данных. Не O (1), и я не могу думать, что это может быть, или даже O (n) (незначительный стеб).

P.s: Код может быть оптимизирован дополнительно.

Скрипка здесь

 var canvas = document.createElement('canvas'),
d = canvas.width = canvas.height = 250,
sq_size = d / 5,
ctx = canvas.getContext('2d');
document.body.appendChild(canvas);
canvas.setAttribute('id','cav');

var color=["rgb(10,110,10)", "rgb(81,169,255)","rgb(81,239,255)", "rgb(81,255,202)", "rgb(81,255,132)","rgb(99,255,81)","rgb(169,255,81)", "rgb(239,255,81)", "rgb(255,202,81)","rgb(255,132,81)"];

var x=0, len=color.length;
var prevcolorh;
var colorobj = {};
for(var i=0; i < d;){
    colorobj[i] = {};
    while(x < d) {
        var c = Math.floor(Math.random() * len);
        colorobj[i][x] = color[c];
    
        var gradient = ctx.createLinearGradient(x, 0, x sq_size, 0);
    
        var a = (prevcolorh !== undefined) ? prevcolorh : colorobj[i][x];
    
        gradient.addColorStop(0, a);
        gradient.addColorStop(1, colorobj[i][x]);
    
        prevcolorh = colorobj[i][x];
    
        ctx.fillStyle = gradient;
        ctx.fillRect(x, i, d, d);
    
        x = x   sq_size;
    }
    x = 0;
    i = i sq_size;
}

var rgbs = {};
for(var i=0; i<d; i =sq_size) {
    var imgd = ctx.getImageData(0, i (sq_size/2), d, sq_size);
    rgbs[i] = {};
    var arr = [];

    for (var j = 0, c = 0, n = imgd.data.length; j < n; j  = 4, c  ) {
        if(j > 0 amp;amp; j < d*4) {
         arr.push([imgd.data[j],imgd.data[j 1],imgd.data[j 2],imgd.data[ 3]]);
        }
    }
    rgbs[i] = arr;
}

for(var k in rgbs) {
    for(var i=0; i<rgbs[k].length; i  ) {
        if(rgbs[parseInt(k) sq_size] !== undefined) {
            var gradient2 = ctx.createLinearGradient(0, parseInt(k) (sq_size/2), 0, parseInt(k) (sq_size/2)   sq_size);

            gradient2.addColorStop(0, 'rgba(' rgbs[k][i].join(',') ')');
            gradient2.addColorStop(1, 'rgba(' rgbs[parseInt(k) sq_size][i].join(',') ')');
        
            ctx.fillStyle = gradient2;
            ctx.fillRect(i, parseInt(k) (3*sq_size/4), 1, sq_size/2);
         
      }
   }
}