2013-12-09 3 views
5

Я пытаюсь дать пользователям указать область, нарисуя на ней инструмент «paint», который рисует полупрозрачные линии на холсте. Его цель - указать «маску» для изображения, которое будет показано ниже на холсте.Рисование полупрозрачных линий движения мыши в холсте HTML5

Это то, что я пытался до сих пор:

var canvas = document.getElementById('canvas'); 
var ctx = canvas.getContext('2d'); 
var canvasPos = canvas.getBoundingClientRect(); 

var dragging = false; 

drawImage(); 

$(canvas).mousedown(mouseDown); 
$(canvas).mouseup(mouseUp); 
$(canvas).mousemove(mouseMove); 

function drawImage() { 
    var img = new Image(); 
    img.src = 'http://img2.timeinc.net/health/img/web/2013/03/slides/cat-allergies-400x400.jpg'; 

    img.onload = function() { 
     ctx.drawImage(img, 0, 0); 
    }; 
} 

function mouseDown(e) { 
    var pos = getCursorPosition(e); 

    dragging = true; 

    ctx.strokeStyle = 'rgba(0, 100, 0, 0.25)'; 
    ctx.lineCap = 'round'; 
    ctx.lineJoin = 'round'; 
    ctx.lineWidth = 15; 
    ctx.beginPath(); 
    ctx.moveTo(pos.x, pos.y); 
} 

function mouseUp(e) { 
    dragging = false; 
} 

function mouseMove(e) { 
    var pos, i; 

    if (!dragging) { 
     return; 
    } 

    pos = getCursorPosition(e); 

    ctx.lineTo(pos.x, pos.y); 
    ctx.stroke(); 
} 

function getCursorPosition(e) { 
    return { 
     x: e.clientX - canvasPos.left, 
     y: e.clientY - canvasPos.top 
    }; 
} 

Проблема с этим примером кода является то, что последующее пиксели, которые нарисованы, делают прозрачность становится все менее заметной. Я думаю, что это потому, что линия имеет ширину 15 пикселей (но я хочу, чтобы это было широко, хотя).

Как я могу решить эту проблему?

Спасибо!

+0

Kangax [написал удивительное сообщение в блоге по этой теме] (http://perfectionkills.com/exploring-canvas-drawing-techniques/) недавно. – Pointy

+0

@Pointy, я действительно прочитал его, прежде чем публиковать этот вопрос. Действительно, серьезная статья, многому научилась - но я не видел решения для моей конкретной проблемы? – bartzy

ответ

7

Проблема заключается в том, что вы снова и снова рисовать весь путь:

function mouseMove(e) { 
    ... 
    ctx.stroke(); // Draws whole path which begins where mouseDown happened. 
} 

Вы должны сделать только новый сегмент пути (http://jsfiddle.net/jF9a6/). И тогда ... у вас есть проблема с шириной линии 15px.

Итак, как это решить? Мы должны нарисовать линию сразу, как вы, но избегайте рисования поверх существующих линий. Вот код: http://jsfiddle.net/yfDdC/

Самое большое изменение в массиве paths. Он содержит да, пути :-) Путь - это массив точек, хранящихся в mouseDown и mouseMove. Новый путь создается в функции MouseDown:

paths.push([pos]); // Add new path, the first point is current pos. 

В MouseMove добавить текущее положение мыши к последнему пути в paths массиве и refreshs изображения.

paths[paths.length-1].push(pos); // Append point tu current path. 
refresh(); 

refresh() функция очищает весь холст, опять рисует кот и рисует каждый путь.

function refresh() { 
    // Clear canvas and draw the cat. 
    ctx.clearRect(0, 0, ctx.width, ctx.height); 
    if (globImg) 
     ctx.drawImage(globImg, 0, 0); 

    for (var i=0; i<paths.length; ++i) { 
     var path = paths[i]; 

     if (path.length<1) 
      continue; // Need at least two points to draw a line. 

     ctx.beginPath(); 
     ctx.moveTo(path[0].x, path[0].y); 
     ... 
     for (var j=1; j<path.length; ++j) 
      ctx.lineTo(path[j].x, path[j].y); 
     ctx.stroke(); 

    } 
} 
+0

Спасибо! Я понимаю первую часть о том, чтобы не рисовать одни и те же «старые» пути снова и снова. Но в вашем фактическом решении (где вы сохраняете все дорожки, когда-либо записанные mousedown> mousemove events), нарисуйте все пути, включая изображение кота, снова и снова в каждом событии mousemove. Неужели это необходимо для решения этой проблемы? Последнее: возможно ли избежать переходов по старым путям с новым путем (что делает прозрачность менее прозрачной)? – bartzy

+0

Посмотрите на первый jsfiddle, который я разместил (http://jsfiddle.net/jF9a6/). Здесь я делаю именно то, что вы предлагаете, и возникает проблема с шириной линии. Это потому, что вы рисуете путь по одному сегменту в то время, так что перекрывающиеся области между сегментами становятся темнее. Если вы нарисуете весь путь сразу, перекрывающиеся области будут нарисованы только один раз, как ожидалось. – Strix

+0

Если вы не хотите, чтобы прозрачность была менее прозрачной при пересечении более старых путей, вы можете немного изменить функцию refresh() http://jsfiddle.net/Q6R3y/. Теперь все разные пути рисуются сразу. – Strix

1

Альтернативный подход состоит в том, чтобы нарисовать пути сплошным и сделать весь холст прозрачным. Конечно, вы должны перемещать изображение из холста и складывать его под ним. Вы можете найти код здесь: http://jsfiddle.net/fP297/

<div style="position: relative; border: 1px solid black; width: 400px; height: 400px;"> 
    <img src='cat.jpg' style="position: absolute; z-order: 1;"> 
    <canvas id="canvas" width="400" height="400" style="position: absolute; z-order: 2; opacity: 0.25;"></canvas> 
</div> 

Рисуя линии твердых вам не придется беспокоиться о рисовании на площади несколько раз, так что вам не придется беспокоиться о стирании изображения и перерисовывая все.

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