简体   繁体   中英

select and change color of a line in html5 canvas?

I wrote this code to draw random graphs. I have been trying in vain to find how I can select a line in the graph so that I can apply the prim's algorithm as one selects lines and see if they have found the minimum tree.

 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();
};  

I found this in stackoverflow and it doesn't help much. How to select lines that are drawn on a HTML5 Canvas? . I was wondering if there's a prewritten code so that I need not write it from scratch.

I was thinking if I could find the location of the mouse as it moves and each time check to see if the location of mouse is on the line as in here Finding if a point is on a line . Please help and suggest if there's any prewritten code because I'm restricted by time. Thank you in advance.

You have to loop through your line array(s) and for each line segment do:

Core principle is to add a line to the path and then test if (x,y) is on that line:

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
}

There is no need to actually stroke the line, just rebuild the path. Adopt as needed.

Here is a full example:

 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> 

To increase sensitivity you can adjust lineWidth to a larger value (there is no need to redraw).

You can use math to determine which line is closest to the mouse.

Here's example code and a demo:

 // 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*(ba)); }; // 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> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM