2014-12-06 3 views
3

Я написал этот код, чтобы нарисовать случайные графики. Я тщетно пытался найти, как я могу выбрать строку на графике, чтобы я мог применить алгоритм prim, когда вы выбираете строки и видите, нашли ли они минимальное дерево.выбрать и изменить цвет линии в холсте html5?

function draw(n,rep){ 
     var cvs=document.getElementsByTagName('canvas')[0]; 
     /** 
     * @type CanvasRenderingContext2D 
     **/ 
     var ctx=cvs.getContext('2d'); 
     ctx.beginPath(); 
     var randomX=[]; 
     var randomY=[]; 
     ctx.lineWidth=2; 
     ctx.font = '3'+' Arial'; 
     var weights=[]; 
     var lastRandomx=Math.random()*200; 
     var lastRandomy=Math.random()*200; 
     for (var i = 0; i <n ; i++) { 
      var cwidth = cvs.width; 
    var cheight = cvs.height;     
      randomX[i] = Math.random()*cwidth*2/3; 
    randomY[i] = Math.random()*cheight*2/3; 
      weights[i]=Math.round(Math.random()*20);       
      ctx.fillRect(randomX[i],randomY[i],5,5);   
    ctx.moveTo(lastRandomx,lastRandomy); 
    ctx.lineTo(randomX[i],randomY[i]);    
      lastRandomx=randomX[i]; 
      lastRandomy=randomY[i]; 
     } 
     for (var i = 0; i < rep; i++) { 
      var rand=Math.round(rep*Math.random()); 
      ctx.lineTo(randomX[rand],randomY[rand]); 
     } 
     ctx.closePath(); 
     ctx.stroke(); 
}; 

Я нашел это в stackoverflow, и это не очень помогает. How to select lines that are drawn on a HTML5 Canvas?. Мне было интересно, есть ли предварительно написанный код, чтобы я не писал его с нуля.

Я думал, могу ли я найти местоположение мыши при ее перемещении и каждый раз проверять, находится ли указатель мыши на линии, как здесь Finding if a point is on a line. Пожалуйста, помогите и предложите, есть ли какой-либо предварительно написанный код, потому что я ограничен временем. Спасибо заранее.

+0

http://stackoverflow.com/questions/15325283/is-there-a-way-to-detect-canvas- lines-with-jquery – EL3PHANTEN

+0

Время, чтобы дать отзыв? –

ответ

5

Вы должны петли через массив (ы) линии и для каждого отрезка сделать:

принцип Ядро является добавление строки в пути, а затем проверить, если (х, у) на этой линии:

ctx.beginPath(); 
ctx.moveTo(x1, y1); // start of line 
ctx.lineTo(x2, y2); // end of line 

// this will test the point against the line (lineWidth matters) 
if (ctx.isPointInStroke(x, y)) { 
    // draw line segment in f.ex. different color here 
    ctx.strokeStyle = "red"; 
    ctx.stroke(); // we already have a line segment on the path 
} 

Нет необходимости фактически обводить линию, просто перестроить путь. Примите при необходимости.

Вот полный пример:

var ctx = canvas.getContext("2d"), 
 
    lines = [], // store line segments for demo 
 
    count = 10, // max 10 lines for demo 
 
    i = 0; 
 

 
for(; i < count; i++) { 
 
    var x = Math.random() * canvas.width; // random point for end points 
 
    var y = Math.random() * canvas.height; 
 
    
 
    if (i) ctx.lineTo(x, y); // if not first line, add lineTo 
 
    else ctx.moveTo(x, y); // start point 
 
    
 
    lines.push({    // store point to create a poly-line 
 
    x: x, 
 
    y: y 
 
    }); 
 
} 
 

 
ctx.lineWidth = 5; 
 
ctx.lineJoin = "round"; 
 
ctx.strokeStyle = "blue"; 
 
ctx.stroke();    // ..and draw line 
 

 
// here we use the principle 
 
canvas.onclick = function(e) { 
 

 
    var r = canvas.getBoundingClientRect(), // adjust to proper mouse position 
 
     x = e.clientX - r.left, 
 
     y = e.clientY - r.top, 
 
     i = 0 
 
    
 
    // for each line segment, build segment to path and check 
 
    for(; i < count - 1; i++) { 
 
    ctx.beginPath();      // new segment 
 
    ctx.moveTo(lines[i].x, lines[i].y);  // start is current point 
 
    ctx.lineTo(lines[i+1].x, lines[i+1].y); // end point is next 
 
    if (ctx.isPointInStroke(x, y)) {  // x,y is on line? 
 
     ctx.strokeStyle = "red";    // stroke red for demo 
 
     ctx.stroke(); 
 
     break; 
 
    } 
 
    } 
 
}
<canvas id=canvas width=500 height=500></canvas>

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

Для этого используется внутренний скомпилированный код (например, DirectX в Windows). Таким образом, вам не нужно иметь дело с математикой и т. Д. И получите быстрый результат.

+0

@markE lines * * очень узкие по своей природе ... :-) Просто добавьте вторую строку с небольшим смещением (без поглаживания их, конечно). При желании найдите угол, переведите/поверните, добавьте прямоугольник и вместо этого используйте isPointInPath(). – K3N

+0

Чтобы увеличить чувствительность, вы можете просто изменить 'ctx.lineWidth' на большее число. –

3

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

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

// canvas related variables 
 
var canvas=document.getElementById("canvas"); 
 
var ctx=canvas.getContext("2d"); 
 
var cw=canvas.width; 
 
var ch=canvas.height; 
 
var $canvas=$("#canvas"); 
 
var canvasOffset=$canvas.offset(); 
 
var offsetX=canvasOffset.left; 
 
var offsetY=canvasOffset.top; 
 
ctx.lineWidth=2; 
 

 
// linear interpolation -- needed in setClosestLine() 
 
var lerp=function(a,b,x){ return(a+x*(b-a)); }; 
 

 
// vars to track which line is closest to the mouse 
 
var closestLineIndex=-1; 
 
var closestX,closestY; 
 

 
// make some random lines and save them in lines[] 
 
var n=5; 
 
var lines=[]; 
 
var randomX=function(){return(Math.random()*cw*.67);} 
 
var randomY=function(){return(Math.random()*ch*.67);} 
 
var lastX=randomX(); 
 
var lastY=randomY(); 
 
for(var i=0;i<n;i++){ 
 
    var x=Math.random()*cw*.67; 
 
    var y=Math.random()*ch*.67; 
 
    var dx=x-lastX; 
 
    var dy=y-lastY; 
 
    var line={ 
 
    x0:lastX, 
 
    y0:lastY, 
 
    x1:x, 
 
    y1:y, 
 
    weight:Math.round(Math.random()*20), 
 
    // precalc often used values 
 
    dx:dx, 
 
    dy:dy, 
 
    dx2dy2:dx*dx+dy*dy, 
 
    }; 
 
    lines.push(line); 
 
    lastX=x; 
 
    lastY=y; 
 
} 
 

 

 
redraw(); 
 

 
$("#canvas").mousedown(function(e){handleMouseDown(e);}); 
 
$("#canvas").mousemove(function(e){handleMouseMove(e);}); 
 

 

 
////////////////////////////// 
 

 

 
function setClosestLine(mx,my) { 
 

 
    closestLineIndex=-1; 
 
    var minDistanceSquared=100000000; 
 

 
    // examine each line & 
 
    // determine which line is closest to the mouse (mx,my) 
 
    for(var i=0;i<lines.length;i++){ 
 
    var line=lines[i]; 
 

 
    var dx=line.x1-line.x0; 
 
    var dy=line.y1-line.y0; 
 
    var t=((mx-line.x0)*line.dx+(my-line.y0)*line.dy)/line.dx2dy2; 
 
    var x=lerp(line.x0, line.x1, t); 
 
    var y=lerp(line.y0, line.y1, t); 
 
    var dx1=mx-x; 
 
    var dy1=my-y; 
 
    var distSquared=dx1*dx1+dy1*dy1; 
 
    if(distSquared<minDistanceSquared){ 
 
     minDistanceSquared=distSquared; 
 
     closestLineIndex=i; 
 
     closestX=x; 
 
     closestY=y; 
 
    } 
 
    } 
 

 
}; 
 

 

 
function redraw(){ 
 

 
    // clear the canvas 
 
    ctx.clearRect(0,0,cw,ch); 
 

 
    // draw all lines 
 
    ctx.strokeStyle='black'; 
 
    for(var i=0;i<lines.length;i++){ 
 
    var line=lines[i]; 
 
    ctx.beginPath(); 
 
    ctx.moveTo(line.x0,line.y0); 
 
    ctx.lineTo(line.x1,line.y1); 
 
    ctx.stroke(); 
 
    } 
 

 
    // draw the line closest to the mouse in red 
 
    if(closestLineIndex<0){return;} 
 
    var line=lines[closestLineIndex]; 
 
    ctx.strokeStyle='red'; 
 
    ctx.beginPath(); 
 
    ctx.moveTo(line.x0,line.y0); 
 
    ctx.lineTo(line.x1,line.y1); 
 
    ctx.stroke(); 
 
    ctx.fillText("Index:"+closestLineIndex+", weight:"+line.weight,10,15); 
 
} 
 

 
function handleMouseMove(e){ 
 
    e.preventDefault(); 
 
    e.stopPropagation(); 
 

 
    mouseX=parseInt(e.clientX-offsetX); 
 
    mouseY=parseInt(e.clientY-offsetY); 
 

 
    setClosestLine(mouseX,mouseY); 
 

 
    redraw(); 
 

 
}
body{ background-color: ivory; } 
 
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> 
 
<h4>Closest line is drawn in red<br>Closest line's weight is reported top-left</h4> 
 
<canvas id="canvas" width=300 height=300></canvas>