how to draw lines with svg or using html div - html

I have created an app in which instead of filling form manually on paper user can generate a request for creating email of the organisation domain through app. The user can fill the form and the form will be sent to HR department and than after approval of HR department the form will be sent to IT department and after the approval of IT manager the email will be created by IT staff. I want to give the rights for the user to see and check the status of his/her request wether it is in HR approval process or in IT approval process. All he has to do is search by ID which I will provide him on submitting the form. I attached the pic what I really want you can see. Explanation: when user search and track his request I want to show the status through flag . I mean if if is in HR process than the flag will be shown on HR . Same for IT. I have checks for all approval in my database . Like I have properties HR approval , IT approval . In my table . What I need here I don't know any Api or JS library which can provide this type of visuals. How can i achieve this. I am using .net mvc Sql and entity framework as my core technologies.
I used svg line to create that line on x-axis but it is not fulfilling my requirements , whats wrong with the code . or is there any other good way to create it ?
<svg height="210" width="500" xmlns="http://www.w3.org/2000/svg" version="1.1">
<line x1="40" x2="120" y1="100" y2="100" stroke="black" stroke-width="20" stroke-linecap="round"/>
</svg>
I would appreciate if someone guide with code snippet.
I tried in this way too but it is not working either
<div style="width:auto ; margin-left:5%" class="col-md-2">
IT
</div>
<div style="width:auto ; margin-left:5%" class="col-md-2">
HR
<div>
<img src="~/Content/148878.png" />
</div>
</div>
<div style="width:auto ; margin-left:5%" class="col-md-2">
VP
</div>
<div style="width:auto ; margin-left:5%" class="col-md-2">
FH
</div>
<div style="width:auto; margin-left:5% " class="col-md-2">
SR
</div>
<div style="width:auto ; margin-left:5%" class="col-md-2">
FH
</div>
</div>

Have you considered using a canvas instead? HTML Canvases can be easily controlled from JS and they can easily load images. You can load images and text as well, so you could easily load the image of the line, the text for the title (although that could be an image as well), and load the image of the flag wherever it needs to be. It would take very little code and very little canvas experience as well. A few google searches could tell you everything you need to know. You can find a lot of tutorials for this in the canvas tutorial at https://www.w3schools.com/graphics/default.asp
If you have any questions about using canvas that aren't answered by the tutorial, they will most likely have answers here on stack overflow.
I have attached snippet. The canvas seems a little blurry in the snippet, but you should not have this issue on an actual webpage. I also left some comments that could be very helpful in the snippet. I still urge you to visit the canvas tutorial I linked to if you decide to use a canvas. It is extremely helpful, and everything written in the snippet could be much better learned in just a few minutes in the tutorial.
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
// Draw your title. You may use text or load an image.
ctx.font = "15px Arial";
let text = "Email Request Process Live Tracking";
ctx.fillStyle = "#0000ff";
ctx.fillText(text,canvas.width/2 - ctx.measureText(text).width/2,20);
/* Draw the progress bar. You would probably want to use an image here
but I do not have the image, so I am drawing a gray rectangle
as a placeholder. */
ctx.fillStyle = "#a2a2a2";
let startX = 40;
let startY = canvas.height - 50;
let width = canvas.width - 80;
let height = 10;
ctx.fillRect(startX, startY, width, height);
/* Place the flag somewhere along the progress bar. I am keeping track
of the coordinates for specific positions on the bar in a JSON object
so that you only have to change the variable "progress" to change the
position. Try it out. For this you will probably want to use an image.*/
var progress = "it";
let locations = {
function: {x: startX, y: startY},
hr: {x: startX + width/5, y: startY},
it: {x: startX + 2 * (width/5), y: startY},
processed: {x: startX + 3 * (width/5), y: startY},
actionPerformed: {x: startX + 4 * (width/5), y: startY},
handedoverClosed: {x: startX + width, y: startY}
};
let img = new Image;
/* I got this image off of google images. In reality, you'll probably
want to upload your own flag image and use that instead.*/
img.src = "https://static.goshopping.dk/products/300/kay-bojesen-flag-til-garder-39021-6382-1.jpg";
let x = locations[progress].x
let y = locations[progress].y
ctx.drawImage(img, locations[progress].x, locations[progress].y - 40, 20, 40)
}
#myCanvas {
border:1px solid #d3d3d3;
width:100%;
height:100%;
}
#invis {
display:none
}
<canvas id="myCanvas"></canvas>
<!–– Normally you would not have to load this image in, but I code snippet fails to load the image in the canvas without it for whatever reason. Because it is uneccessary and should not be displayed, I've set its display to none to stop it from being rendered.-->
<img src="https://static.goshopping.dk/products/300/kay-bojesen-flag-til-garder-39021-6382-1.jpg" id="invis">

Related

Jigsaw Puzzle pices using Bezier Curve

I was trying to make some jigsaw pieces like this -
What I have tried till now with lineTo -
outside: function (ctx, s, cx, cy) {
ctx.lineTo(cx, cy)
ctx.lineTo(cx+s*.3, cy)
ctx.lineTo(cx+s*.5, cy+s*-.2)
ctx.lineTo(cx+s*.7, cy)
ctx.lineTo(cx+s, cy)
},
inside: function (ctx, s, cx, cy) {
ctx.lineTo(cx, cy)
ctx.lineTo(cx+s*.3, cy)
ctx.lineTo(cx+s*.5, cy+s*+.2)
ctx.lineTo(cx+s*.7, cy)
ctx.lineTo(cx+s, cy)
},
Fiddle Link
Efficient Jigsaw design is simple and it works like this:
The linked code already shows how to efficiently assemble one of your jigsaw pieces by reusing a single side design.
The piece on the right side of you illustration is a traditional (or "Japanese Style") piece. This means its sides are uniform in length and fully interlocking. Japanese style pieces are the easiest to design because a single piece of design code and be reused throughout the puzzle.
Ironically, While Japanese Style puzzles are the easiest to code, they are more difficult for the user to solve since many pieces will physically fit together without correctly solving the puzzle.
How to design a Japanese Style jigsaw puzzle
Design one side (not more!) of a jigsaw piece by combining multiple cubic Bezier curves.
Use transforms to apply that one jigsaw design to the top, right, bottom or left sides as needed. (or code functions that automatically manipulate the original Bezier control points to apply that one jigsaw design to the 4 sides). Mirror the original side design to give your pieces a variety of "inny" and "outy" sides.
Assemble a puzzle from pieces by mirroring the design of each neighboring side:
Give the top-left piece (0,0) a random right side (either inny or outy).
Let's assume piece (0,0) was assigned an outy right side. Then the next piece to the right (1,0) must get an inny left side.
Now give piece (1,0) a random right side (either inny or outy), and piece (2,0) must get the mirrored type of side. And so on...
So in general, fill the puzzle by assigning random right sides to all the pieces and mirroring the assigned side on the left side of the next piece.
Do the same vertically. fill the puzzle by assigning random bottom sides to all the pieces and mirroring the assigned side on the top side of the next piece.
Designing the 2 example pieces you've illustrated
I assume the linked code is not your code because it already shows how to design that piece on the right of your illustration(!).
// Given the center point of the piece (cx,cy) and the side length (s)
// The single side "outy" design is below
// Use this single design (with transforms/mirroring) to make all pieces
ctx.lineTo(cx + s * .34, cy);
ctx.bezierCurveTo(cx + s * .5, cy, cx + s * .4, cy + s * -.15, cx + s * .4, cy + s * -.15);
ctx.bezierCurveTo(cx + s * .3, cy + s * -.3, cx + s * .5, cy + s * -.3, cx + s * .5, cy + s * -.3);
ctx.bezierCurveTo(cx + s * .7, cy + s * -.3, cx + s * .6, cy + s * -.15, cx + s * .6, cy + s * -.15);
ctx.bezierCurveTo(cx + s * .5, cy, cx + s * .65, cy, cx + s * .65, cy);
ctx.lineTo(cx + s, cy);
Then you can reuse this one single set of Bezier curves along with transformations to create your entire puzzle. Transformations==moving, rotating and mirroring the one single design to make up any side of any puzzle piece.
The piece on the left of your illustration is probably from a Freeform Style jigsaw puzzle. It is more complex because it uses 3 different side designs. I assume there are additional side designs which you haven't shown because the 3-sided design you show would not allow all pieces to interlock to complete the puzzle.
You have several options when creating a Freeform Style jigsaw puzzle.
Non-interlocking Freeform Style
In this style, you basically take an image and draw lines that cut it into non-uniform pieces that can be arranged to form the image. Think of this like a pizza that's been sliced randomly. You can fit the pieces together to reform the pizza even if the pieces do not interlock. Mmmmm, pizza! :-)
Interlocking Freeform Style
In this style, you design 2+ sides and create the puzzle much the same way as the traditional style puzzle. Usually you create one design that you will use for all left-right sides and a second design that you will use for all top-bottom sides. The complexity is that the 2 types of sides must fit together where they meet. This means that side-type-1 must share a mirrored pattern where it intersects side-type-2.
So to design the piece on the left side of your illustration, you must decide if you want it to be Interlocking-Freeform or Non-interlocking-Freeform.
Non-interlocking Freeform is the easier. Just pull apart the 3 types of sides and use them with their mirrored partners to chop up your image.
For Interlocking-Freeform, more design work is necessary on your part. You must create additional side designs that will interlock with the 3 designs you've already created.
That's a quick tour of jigsaw puzzles...Good luck with your project!
[ Additional details ]
For the piece on the right side of your illustration, the common "outside" looks like a "shoulders & head" silhouette.
The Bezier-set to create the shoulders & head break down like this:
A Bezier for the "left shoulder"
A Bezier for the "left neck"
A Bezier for the "left head"
A Bezier for the "right head"
A Bezier for the "right neck"
A Bezier for the "right shoulder"
A shoulder & head Bezier set might look like this:
Here's one specific example of the control points to create an outside side with a "shoulders & head" shape:
var ShouldersAndHeadCubicBezierControlPoints=[
{cx1:0, cy1:0, cx2:35,cy2:15, ex:37, ey:5}, // left shoulder
{cx1:37, cy1:5, cx2:40,cy2:0, ex:38, ey:-5}, // left neck
{cx1:38, cy1:-5, cx2:20,cy2:-20,ex:50, ey:-20}, // left head
{cx1:50, cy1:-20,cx2:80,cy2:-20,ex:62, ey:-5}, // right head
{cx1:62, cy1:-5, cx2:60,cy2:0, ex:63, ey:5}, // right neck
{cx1:63, cy1:5, cx2:65,cy2:15, ex:100,ey:0}, // right shoulder
];
Once you have the "outside" set of curves, you can use canvas's context transformations to flip the "outside" into its mirrored "inside". Alternatively you can manually reverse the "outside" array of curve control points.
Illustrations: top-tab and top-slot (top-slot is top-tab mirrored)
Example displaying top-tab and top-slot:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
ctx.lineWidth=3;
var colors=['red','green','blue','gold','purple','cyan'];
var bSet=makeBeziers();
draw(bSet,50,100);
var bSetMirrored=mirror(bSet,1,-1,0,0);
draw(bSetMirrored,50,200);
function draw(bSet,transX,transY){
ctx.translate(transX,transY);
ctx.scale(2,2);
for(var i=0;i<bSet.length;i++){
var b=bSet[i];
ctx.beginPath();
ctx.bezierCurveTo(b.cx1,b.cy1,b.cx2,b.cy2,b.ex,b.ey);
ctx.strokeStyle=colors[i];
ctx.stroke();
}
ctx.setTransform(1,0,0,1,0,0);
}
function makeBeziers(){
return([
{cx1:0, cy1:0, cx2:35,cy2:15, ex:37, ey:5}, // left shoulder
{cx1:37, cy1:5, cx2:40,cy2:0, ex:38, ey:-5}, // left neck
{cx1:38, cy1:-5, cx2:20,cy2:-20,ex:50, ey:-20}, // left head
{cx1:50, cy1:-20,cx2:80,cy2:-20,ex:62, ey:-5}, // right head
{cx1:62, cy1:-5, cx2:60,cy2:0, ex:63, ey:5}, // right neck
{cx1:63, cy1:5, cx2:65,cy2:15, ex:100,ey:0}, // right shoulder
]);
}
function mirror(b,signX,signY,x,y){
var a=[];
for(var i=0;i<b.length;i++){
var bb=b[i];
a.push({
cx1: bb.cx1*signX+x,
cy1: bb.cy1*signY+y,
cx2: bb.cx2*signX+x,
cy2: bb.cy2*signY+y,
ex: bb.ex*signX+x,
ey: bb.ey*signY+y
});
}
return(a);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>
I would like to propose an alternative approach -
SVG source
Why not consider using a SVG image source that you make in Illustrator or some similar software. The tools will allow you to trace the outline of a piece (it can in fact do it almost entirely automatic - see result below). The SVG may use Beziers too, or just a path that fits the original image almost perfectly. Just hit trace, adjust threshold, save out and clean up the result a little.
This way you can simply import the SVG, draw it to an off-screen canvas at the size you want to rasterize it. The result can then be used for either composition or "cutting out" graphics directly.
This is much faster and simpler than calculating and using splines.
Example
This result is from Illustrator converted to SVG, with some manual clean-up such as removing comments and background, adding width and height and adjusting viewbox:
(Note: in this demo I left the shadow in the original image - you would have to clean up the image itself, then process it to SVG etc.).
I can now load it as a basis for composition so I could do:
var ctx = document.querySelector("canvas").getContext("2d"),
svg = document.querySelector("svg").outerHTML,
img = new Image();
// fill some graphics to canvas
ctx.fillStyle = "#777";
ctx.fillRect(0, 0, 600, 600);
// load SVG so we can use the puzzle with canvas
img.onload = demo;
img.src = "data:image/svg+xml;base64," + btoa(svg);
function demo() {
// create a matte so it becomes rasterized - choose the size dynamically if you need to
var matte = document.createElement("canvas"),
mctx = matte.getContext("2d");
matte.width = matte.height = 100;
mctx.drawImage(this, 0, 0, 100, 100); // draw in (rasterize) the SVG
// we can now use the puzzle as basis for an image region, or to mask out parts:
ctx.globalCompositeOperation = "destination-out";
ctx.drawImage(matte, 10, 10);
ctx.drawImage(matte, 100, 100);
ctx.drawImage(matte, 210, 10);
}
canvas {border:1px solid #000;background:url(http://i.stack.imgur.com/bEiyx.jpg)}
<canvas width=600 height=600></canvas>
<br><br>SVG (inlined for demo - use from URL instead):<br>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
<svg version="1.1" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" viewBox="0 0 90 90" width="300" height="300" xml:space="preserve">
<path d="M16.1,34.2c-2.8,2.3-4.4,4.3-6.5,5.1c-1.9,0.7-5.2,1.2-6.3,0.1C1.9,38,1,34.6,1.7,32.7c0.9-2.6,3-5.2,5.3-6.7
c6.5-4.4,6.5-4.3,3.9-11.8c-0.5-1.4,0.6-4.7,1.6-5c2.6-0.7,5.8-1,8.2,0c1.2,0.4,2.4,4.4,1.7,5.8c-2.3,4.9-0.3,7.7,3.5,10
c3.4,2,6.7,1.5,9.3-1.8c2.4-3.1,1.9-5.9-1.1-8.3c-3.2-2.6-2.7-5.1,0.1-7.4c3.6-3.1,12.4-3.2,16-0.2c2.7,2.2,3.9,4.6,0.6,7.4
c-2.7,2.3-4.1,4.9-1.6,8.2c2.4,3.2,5.6,4.2,9.2,2.3c3.5-1.8,5-4.7,4-8.7c-1.5-5.7,1-9.2,6.2-8.9c4.4,0.2,6.8,4.4,4.3,8
c-2.5,3.7-1.6,6.1,1.8,8.3c1.7,1.1,3.3,2.3,4.9,3.5c3.9,3,5,9.1,2.2,12c-2.2,2.3-6.4,1.4-10.2-2.2c-0.7-0.7-1.3-1.4-2-2.1
c-5.7,5.4-6.2,12.7-1.6,17.8c1.9,2.1,4.2,3.1,6.4,0.8c2.1-2.1,3.8-4.5,6.9-1.4c2.7,2.8,3.5,8,0.8,10.4c-2,1.7-4.8,2.9-7.4,3.4
c-4.9,0.9-6.2,3.5-3.8,8c0.9,1.7,0.5,4.1,0.8,6.1c-2.2-0.3-5.2,0.2-6.5-1.1c-2.4-2.4-3.8-5.7-5.4-8.7c-2.2-4.2-4.2-4.6-9.5-2.1
c-4,1.9-3.1,4.4-1.3,7.3c1.9,3.1,4.5,6.5-0.3,9.4c-4,2.5-13.5,1.7-14.8-1.6c-0.8-2.1,0-5.2,1.2-7.3c2-3.5,2.8-6-1.7-7.9
c-5.4-2.4-7.1-1.7-9.5,3.2c-1.6,3.2-3.6,6.3-6.1,8.8c-0.9,0.9-3.7-0.1-5.7-0.3c0.2-1.8-0.2-3.9,0.6-5.3c3.4-5.3,2.4-7.6-4-8.3
c-7-0.8-10.5-6.7-7.1-12.5c1.4-2.4,3.2-4,6-1.9c2.2,1.7,4.7,4.9,7.2,2.1c2.4-2.6,4.1-6.5,4.3-10C19.7,40.9,17.5,37.8,16.1,34.2z"/>
</svg>
And of course, if you don't want to use it as matte you can draw a piece of the image on top of it every time you need to update a piece on the board (use source-atop for example to replace the image on the same "matte").

Canvas content disappering on resize [duplicate]

This question already has answers here:
Resize HTML5 canvas element
(3 answers)
Closed 8 years ago.
Probably I'm missing something fundamental.
I'm filling a canvas with objects. On user input I need to resize the canvas (thus scaling the content).
JS (simplified):
var c = document.getElementById('c');
var cc = c.getContext('2d');
cc.beginPath();
cc.rect(20, 20, 20, 12);
cc.fill();
function resizeCanvas(size){
var c = document.getElementById('c');
var cc = c.getContext('2d');
// This will make the content disappear
c.width = c.style.width = c.height = c.style.height = size;
}
HTML
<canvas id="c" width="200" height="200"></canvas>
<br/>
<button onclick='resizeCanvas(100);return false;'>Resize</button>
CSS
canvas {border: 1px solid black}
The canvas is resized but the content is blanked. Any idea?
jsfddle here
By changing either width or height -and obviously by changing both-, you completely redefine the canvas, so in fact it is quite logical that the canvas content is cleared : how should it change ?
Should it scale ? , re-use existing pixels values, but how ? centered, ... ??
That was even a 'trick' at some time : to clear a canvas, just do canvas.width = 0 then canvas.width = oldWidth , and that will clear things up. Since clearRect or fillRect are now faster that this trick, it has no reason to be used any more.
So when your canvas get resized, it will get cleared. It's up to you to decide of the policy you want when such resize occur : will you scale old canvas and copy it on the new one, or copy at same scale centered, or will that be an up/left most copy ??
you decide.
If you have a 'scene graph', meaning : if you are able to redraw every objects of your canvas, there's no real issue.
If you don't, you have to do some efforts to get the old content on the new canvas.
Something like (untested) :
function resizeCanvas(size){
var c = document.getElementById('c');
var canvasCopy = document.createElement('canvas');
canvasCopy.width = c.width; canvasCopy.height = c.height;
canvasCopy.getContext('2d').drawImage(c, 0,0 ); // copy the 'old' canvas
// This will make the content disappear
c.width = c.style.width = c.height = c.style.height = size;
var cc = c.getContext('2d');
cc.drawImage(canvasCopy, 0, 0) ; // or you might scale, or center, or...
}

Generating a random image with specific content at each page reload/refresh

So I have a banner on a site, but I want to make it so that each time the page loads, a different image appears. More precisely, I want (say 50) squares (say having a black border, white fill) of random size (say from 5 pixels to 20 pixels in size) in random positions of a 750x63 px frame, with a white background.
What would be the best way to do this? I know a little JavaScript and HTML (and am very willing to learn more), but I really have no idea where to start. This is for my personal webpage, which I wish to spruce up a bit. Right now the fanciest code I have is some JavaScript for a simple Lightbox interface.
Wow, that was easier and more fun than I expected. Here's the code, that goes in the <body> section of my HTML code, optimized for a 750x80px frame. The random integer generator I got from this other question.
<canvas id="canvas" width="750" height="80"></canvas>
<script type="text/javascript">
//Random integer generator
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
//Loop to make 80 squares
for (var i=0;i<80;i++) {
//The x-position of the square, with 5px padding in frame
var sx = getRandomInt(5,705);
//The y-position of the square, with 5px padding in frame
var sy = getRandomInt(5,35);
//The height of the square, smallest 8x8px, largest 40x40px
var sh = getRandomInt(8,40);
//First, create a black square
ctx.fillStyle = "rgb(0,0,0)";
ctx.fillRect (sx, sy, sh, sh);
//Second, create a white square that's 4px shorter and thinner,
//leaving a boundary of 2px
ctx.fillStyle = "rgb(255,255,255)";
ctx.fillRect (sx+2, sy+2, sh-4, sh-4);
}
}
draw();
</script>
The approach I used is from a Mozilla Developers page. The result is something like this:
Hooray!

Canvas getImageData() bizarre issue

I have faced quite bizarre issue lately, please take a look at the code snippet below
<canvas id="cancan" width="320", height="480">One color image</canvas>
<script type="text/javascript">
function imageLoaded(ev) {
element = document.getElementById("cancan");
c = element.getContext("2d");
im = ev.target; // the image, assumed to be 200x200
// read the width and height of the canvas
width = element.width;
height = element.height;
// stamp the image on the left of the canvas:
c.drawImage(im, 0, 0);
// get all canvas pixel data
imageData = c.getImageData(0, 0, width, height);
console.log(imageData.data[0] + " " + imageData.data[1] + " " + imageData.data[2]);
// output is "243 52 47"
// matlab and c# output is: "237 36 27"
}
im = new Image();
im.onload = imageLoaded;
im.src = "imgtest1.jpg"; // image is 320x480
</script>
imgtest1.jpg used in this example is constant - each pixel is (237,36,27). Pixel color returned by getImageData() differs - it is brighter then what is returned from - for example - matlab - any ideas what could be the reason ?
Lightness or Brightness or Intensity can be computed as (R+G+B)/3 (see HSI color code). After your sample code result, it is obvious that your output-image is a little bit bright than the original one because your R-G-B values are higher than the original ones (from Matlab or C++).
The question must be "Why your code computes higher values?". I don't know, but you could re-scale the values in order to have the same brightness.

How to select lines that are drawn on a HTML5 Canvas?

I am using using HTML5 Canvas to plot lines. A single line is formed by calling drawLine() on multiple intermediate points. For example:
(0,0) -> (10, 10) -> (10, 5) -> (20, 12)
would show up as one line on the plot.
All the (x,y) co-ordinates of a line are stored in an array.
I want to provide the users with the ability to select a line when they click on it. It becomes difficult to do this in HTML5 Canvas as the line is not represented by an object. The only option that I am left with is to first find that (x,y) coordinate of any line that is closest to the (x,y) of a mousedown event. Once I detect which line the user has selected, then I need to redraw the line with a bold color or put a translucent color around it. But, I am assuming that this would be too time-intensive, as it involves looping over all (x,y) coordinates of all lines.
I am looking for ways that can help me achieve the above in a more time-efficient manner. Should I consider using SVG in HTML5?
Any suggestions would be appreciated.
The simplest way to do this in HTML5 canvas is to take a snapshot of the image data for the canvas, and during mousemove look at the alpha color at the pixel under the mouse.
I've put up a working example of this on my site here:
http://phrogz.net/tmp/canvas_detect_mouseover.html
Here's the core code I wrote. Pass it a context and a function, and it will call your function with the RGBA components underneath the pixel.
function pixelOnMouseOver(ctx,callback){
var canvas = ctx.canvas;
var w = canvas.width, h=canvas.height;
var data = ctx.getImageData(0,0,w,h).data;
canvas.addEventListener('mousemove',function(e){
var idx = (e.offsetY*w + e.offsetX)*4;
var parts = Array.prototype.slice.call(data,idx,idx+4);
callback.apply(ctx,parts);
},false);
}
And here's how it's used on that test page:
var wasOver;
pixelOnMouseOver(ctx,function(r,g,b,a){
var isOver = a > 10; // arbitrary threshold
if (isOver != wasOver){
can.style.backgroundColor = isOver ? '#ff6' : '';
wasOver = isOver;
}
out.innerHTML = "r:"+r+", g:"+g+", b:"+b+", a:"+a;
});
I think you'd find this much easier in SVG. There each line would be a <polyline> and you could add a onclick handler to do what you want. For example...
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<polyline points="20,20 40,25 60,40 80,120 120,140 200,180"
style="fill:none;stroke:black;stroke-width:5"
onclick="this.style.stroke='red'" />
</svg>
The only way to do this on the canvas is to detect pixel color and follow path or save paths as objects and detect a click on that path.