2015-03-13 9 views
1

Я делаю приложение с узлом, js и т. Д. Я хотел бы заполнить пользовательские формы, которые я могу создать либо через точки данных, либо в другой формат с разными многослойными цветами. Например, у меня есть треугольник. Я хочу заполнить нижний 1/3 красным, средний 1/3 с синим, а верхний 1/3 - зеленым. Как я могу это сделать?Заполнение формы процедурно более чем одним цветом

Я смотрю Paper.js и основное полотно, но у них, похоже, есть только одноцветные заливки.

Спасибо за любой совет!

ответ

4

Я знаю, что ответ принят, но я хотел представить очень простой подход для будущих читателей.Который, в качестве бонуса, автоматически вычисляет высоту каждой части и быстро, используя линейный градиент -

Результат будет

snap

код и демо

var ctx = document.querySelector("canvas").getContext("2d"), 
 
    grad = ctx.createLinearGradient(0, 0, 0, 150); 
 

 
grad.addColorStop(0, "red");  // start of red 
 
grad.addColorStop(1/3, "red"); // end of red at 1/3 
 

 
grad.addColorStop(1/3, "gold"); // start of gold at 1/3 
 
grad.addColorStop(2/3, "gold"); // end of gold at 2/3 
 

 
grad.addColorStop(2/3, "blue"); // start of blue at 2/3 
 
grad.addColorStop(1, "blue"); // end of blue at 3/3 
 

 
// Fill a triangle: 
 
ctx.moveTo(75, 0); ctx.lineTo(150, 150); ctx.lineTo(0, 150); 
 
ctx.fillStyle = grad; 
 
ctx.fill();
<canvas/>

Анимат ред версии с использованием метода композитинга

var ctx = document.querySelector("canvas").getContext("2d"), 
 
    grad = ctx.createLinearGradient(0, 0, 0, 150), 
 
    step = grad.addColorStop.bind(grad), // function reference to simplify 
 
    dlt = -3, y = 150; 
 

 
step(0, "red");  // start of red 
 
step(1/3, "red"); // end of red at 1/3 
 
step(1/3, "gold"); // start of gold at 1/3 
 
step(2/3, "gold"); // end of gold at 2/3 
 
step(2/3, "blue"); // start of blue at 2/3 
 
step(1, "blue"); // end of blue at 3/3 
 

 
// store a triangle path - we'll reuse this for the demo loop 
 
ctx.moveTo(75, 0); ctx.lineTo(150, 150); ctx.lineTo(0, 150); 
 

 
(function loop() { 
 
    ctx.globalCompositeOperation = "copy"; // will clear canvas with next draw 
 

 
    // Fill the previously defined triangle path with any color: 
 
    ctx.fillStyle = "#000"; // fill some solid color for performance 
 
    ctx.fill(); 
 
    
 
    // draw a rectangle to clip the top using the following comp mode: 
 
    ctx.globalCompositeOperation = "destination-in"; 
 
    ctx.fillRect(0, y, 150, 150 - y); 
 

 
    // now that we have the shape we want, just replace it with the gradient: 
 
    // to do that we use a new comp. mode 
 
    ctx.globalCompositeOperation = "source-in"; 
 
    ctx.fillStyle = grad; 
 
    ctx.fillRect(0, 0, 150, 150); 
 
    
 
    y += dlt; if (y <= 0 || y >= 150) dlt = -dlt; 
 
    requestAnimationFrame(loop); 
 
})();
<canvas/>

кэширования данных градиентного изображения для анимации (рекомендуется)

var ctx = document.querySelector("canvas").getContext("2d"), 
 
    tcanvas = document.createElement("canvas"), // to cache triangle 
 
    tctx = tcanvas.getContext("2d"), 
 
    grad = tctx.createLinearGradient(0, 0, 0, 150), 
 
    step = grad.addColorStop.bind(grad), // function reference to simplify 
 
    dlt = -3, y = 150; 
 

 
step(0, "red");  // start of red 
 
step(1/3, "red"); // end of red at 1/3 
 
step(1/3, "gold"); // start of gold at 1/3 
 
step(2/3, "gold"); // end of gold at 2/3 
 
step(2/3, "blue"); // start of blue at 2/3 
 
step(1, "blue"); // end of blue at 3/3 
 

 
// draw triangle to off-screen canvas once. 
 
tctx.moveTo(75, 0); tctx.lineTo(150, 150); tctx.lineTo(0, 150); 
 
tctx.fillStyle = grad; tctx.fill(); 
 

 
(function loop() { 
 
    ctx.clearRect(0, 0, 150, 150); 
 

 
    // draw clipped version of the cached triangle image 
 
    if (150-y) ctx.drawImage(tcanvas, 0, y, 150, 150 - y, 0, y, 150, 150 - y); 
 

 
    y += dlt; if (y <= 0 || y >= 150) dlt = -dlt; 
 
    requestAnimationFrame(loop); 
 
})();
<canvas/>

Вы можете изменить направление с помощью градиента линии,который определяет угол градиента.

// vertical 
ctx.createLinearGradient(0, 0, 0, 150); // x1, y1, x2, y2 

// hortizontal 
ctx.createLinearGradient(0, 0, 150, 0); // x1, y1, x2, y2 

// 45° degrees 
ctx.createLinearGradient(0, 0, 150, 150); // x1, y1, x2, y2 

и т.д.

+1

Этот подход лучше, короче и не опасен для призрачных останков других рисованных пикселей. – dwana

+0

Мне это тоже нравится, я дам оба выстрела. Сможете ли вы использовать animate() для этого, чтобы заполнить его снизу? – xHocquet

+1

@xHocquet уверен, используя пару шагов компоновки, вы можете закрепить треугольную форму, а затем заполнить ее градиентом. Я добавил демо для удобства :) (вы можете кэшировать треугольник с градиентом на отдельном холсте и просто нарисовать обрезанную версию его обратно на основной холст). – K3N

1

Вы можете использовать собственный холст html, сделав ваши фигуры (например, треугольник) в области отсечения.

Это означает, что любое заполнение, которое вы впоследствии сделаете, не будет выходить за пределы вашего треугольника.

Все, что вам нужно сделать, это:

  • Draw вам треугольник

  • Сделать стартовой вырезанной

  • рисовать зеленый прямоугольник над верхней 1/3 вашего треугольник. Не волнуйся ... прямоугольник будет обрезаться, чтобы появиться только там, где он находится внутри треугольника.

  • рисовать синий прямоугольник на среднем 1/3 части треугольника

  • Нарисуйте красный прямоугольник в нижней 1/3 части треугольника

Вот пример кода и демо :

var canvas=document.getElementById("canvas"); 
 
var ctx=canvas.getContext("2d"); 
 
var cw=canvas.width; 
 
var ch=canvas.height; 
 

 
var points=[]; 
 
points.push({x:100,y:50}); 
 
points.push({x:150,y:150}); 
 
points.push({x:50,y:150}); 
 
points.push({x:100,y:50}); 
 

 
drawPoints(points); 
 

 
function drawPoints(pts){ 
 
    var minY= 100000; 
 
    var maxY=-100000; 
 
    ctx.save(); 
 
    ctx.beginPath(); 
 
    for(var i=0;i<pts.length;i++){ 
 
    var p=pts[i]; 
 
    if(i==0){ 
 
     ctx.moveTo(p.x,p.y); 
 
    }else{ 
 
     ctx.lineTo(p.x,p.y); 
 
    } 
 
    if(p.y<minY){minY=p.y;} 
 
    if(p.y>maxY){maxY=p.y;} 
 
    } 
 
    ctx.stroke(); 
 
    ctx.clip(); 
 

 
    var height=maxY-minY; 
 
    ctx.fillStyle='green'; 
 
    ctx.fillRect(0,minY,cw,minY,height/3); 
 
    ctx.fillStyle='blue'; 
 
    ctx.fillRect(0,minY+height/3,cw,height/3); 
 
    ctx.fillStyle='red'; 
 
    ctx.fillRect(0,minY+height*2/3,cw,height/3); 
 
    ctx.restore(); 
 
}
body{ background-color: ivory; } 
 
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>

+0

Yo! Этот ответ прекрасен. Большое спасибо, не знал о масках. Не могли бы вы посоветовать мне, как рассчитать проценты на основе массива или объекта чисел. Рассчитать общее количество, получить коэффициенты, перебрать коэффициенты и создать коэффициент прямоугольника * 100% высоты? – xHocquet

+0

Добро пожаловать! ** Вот как вычислять высоты: ** (1) Учитывая 'var data = [3,4,6];' вычисляет общее количество данных: 'var total = 0; для (var i = 0; i markE

Смежные вопросы