3

I have the following to draw a polygon on a canvas when the mouseover event fires:

      $(document).ready(function() {

        $('#flam').mouseover(function() {

        context.fillStyle = '#f00';
        context.beginPath();
        context.moveTo(98,265);
        context.lineTo(197,240);
        context.lineTo(197,235);
        context.lineTo(227,220);
        context.lineTo(242,220);
        context.lineTo(245,209);
        context.lineTo(252,208);
        context.lineTo(252,200);
        context.lineTo(274,179);
        context.lineTo(277,179);
        context.lineTo(290,166);
        context.lineTo(191,72);
        context.lineTo(164,97);
        context.lineTo(166,112);
        context.lineTo(94,129);
        context.lineTo(105,170);
        context.lineTo(72,177);
        context.closePath();
        context.fill();

            $('#flam').mouseout(function() {
               //What do I need to do here to clear this on mouseout

            ;})
        ;})

Or is there another more efficient way to do this

Jamie
  • 33
  • 1
  • 5
  • 1
    what do you mean by 'clear' : have the polygon drawn in black, or have the previous content restored ? – GameAlchemist Sep 28 '13 at 21:58
  • when the use mouseovers the area it draws that polygon, when the mouse leaves it i want the polygon to no longer be there so yes have it restored to how it was before. also should I be using mouseenter/leave instead? – Jamie Sep 28 '13 at 22:01
  • First tell us if a) you have a way to re-paint the whole canvas or b) you build the canvas step by step and have no way to re-paint it all. ?? – GameAlchemist Sep 28 '13 at 22:05
  • Build step by step for multiple areas. I am just starting out with this. – Jamie Sep 28 '13 at 22:06
  • I added a click event now as well because I need it to save the region that is clicked but when the mouse leaves it clears it how do i remove the mouseout function when it has been clicked? use jquery to remove the identifier? – Jamie Sep 29 '13 at 00:31
  • Is it one or several areas that can be selected ? just a draft : You need to handle an object, selectedArea(s), that will store the id(s) of the selected area(s) (selectedArea[id]=true), then, in the mouse out, after clearing the canvas, re-draw the selected area(s). – GameAlchemist Sep 29 '13 at 03:11
  • Only one at a time may be slected – Jamie Sep 29 '13 at 03:21
  • Well, i think i answered enough for now, SO is about local issue solving, not building whole solution ;-) Please mark my answer as acccepted, And if you want you can hire me to build or help you to reach your goal. In any case good luck for your project. – GameAlchemist Sep 29 '13 at 10:20

1 Answers1

6

Ok so my answer changed completely :-).

What you need to do :
- set a canvas on top of the image.
--> use for both canvas and image : position:absolute; top:0px; left:0px;
- in order to have IE working (thx to @Kerry Liu's comments), it seems you cannot ignore mouse events on the canvas in IE, so set another empty image on the canvas+image, and hook the area on this latest image.
- add a class to all your area to be able to select them. I choose 'mapPart'.
- Hook an event that will draw the polygon on canvas on mouse
over for all mapParts.
- Hook an event that will clear the canvas on mouse out for all mapParts.

http://jsfiddle.net/gamealchemist/cmKsD/

(using jQuery 1.9.1)

(Credits to this answer from @enhzflep from whom i stoled the polygon drawing :-)
here : How to apply Hovering on html area tag?
One might want to handle other area types as he does. )

html (extract) :

<div id='myImage' class="map">
    <img src="http://www.linkparis.com/images/francemap.jpg" border="0"  
         style='position:absolute; top:0px; left:0px;' />
    <canvas id='myCanvas' height='494' width='494' style='position:absolute; top:0px; left:0px;'>Canvas is not supported by your browser.</canvas>
    <img border="0" usemap="#imgmap" style='position:absolute; top:0px; left:0px; width:100%; height:100%; ' usemap="#imgmap" />
</div>
<map id="imgmap" name="imgmap">
    <area shape="poly" id="flam" class="mapPart" coords="98,265,197,240,197,235,227,220,242,220,245,209,252,208,252,200,274,179,277,179,
        290,166,191,72,164,97,166,112,94,129,105,170,72,177" />
    <area shape="poly" id="ancaster" class="mapPart" coords=" 198,240,97,265,103,274,232,334,254,263,251,261,251,243,243,245,240,235,
        229,240,229,240,222,240,216,244,213,237" />
....

Code :

var cv = document.getElementById('myCanvas');
var context = cv.getContext('2d');

context.clearRect(0, 0, cv.width, cv.height);

$('.mapPart').mouseover(function () {
    var coordStr = this.getAttribute('coords');
    // draw
    drawPolygon(context, coordStr);
});

$('.mapPart').mouseout(function () {
    // clear
    context.clearRect(0, 0, cv.width, cv.height);
});

function drawPolygon(hdc, coOrdStr) {
    var mCoords = coOrdStr.split(',');
    var i, n;
    n = mCoords.length;

    hdc.beginPath();
    hdc.moveTo(mCoords[0], mCoords[1]);
    for (i = 2; i < n; i += 2) {
        hdc.lineTo(mCoords[i], mCoords[i + 1]);
    }
    hdc.lineTo(mCoords[0], mCoords[1]);
    hdc.stroke();
}
Community
  • 1
  • 1
GameAlchemist
  • 18,995
  • 7
  • 36
  • 59
  • I would like to upvote but dont have the rep yet :D But I already have a canvas and the #flam id is from a area within a map already does this make a difference in how I would go about this? Such as is there a way I can grab the coordinates of the tag and draw the polygon that way as well? – Jamie Sep 28 '13 at 22:36
  • I never used area, but afaik it is meant for images, not canvases, right ? – GameAlchemist Sep 28 '13 at 22:45
  • sorry I guess I should have mentioned that it is when a user hovers over an image of a map eg city lines of a state. that city needs to be highlighted by a polygon drawn on a canvas, and mouse out it clears. but i am guessing if it has the id of what is being used it should work the same possibly – Jamie Sep 28 '13 at 22:50
  • so when does the canvas come in action ? is it located on top of the image ? This might raise some issue for detection, i don't know. While googling for area i found this answer that might quite be of help to you : http://stackoverflow.com/questions/12661124/how-to-apply-hovering-on-html-area-tag – GameAlchemist Sep 28 '13 at 22:55
  • Now we should be pretty close to the answer. – GameAlchemist Sep 29 '13 at 00:00
  • Yes very close I just need to understand better whats going on and be able to write it myself but that wont be too much work :D thank you very much for your help – Jamie Sep 29 '13 at 00:12
  • @GameAlchemist You may want to find an alternative for [pointer-events](http://caniuse.com/#feat=pointer-events). They aren't supported in IE. – Kerry Liu Sep 29 '13 at 00:41
  • @ Kerry Liu : i didn't know that. Do you have a clue ? Re-sending the events might be a solution, but simpler would be better. – GameAlchemist Sep 29 '13 at 00:53
  • @GameAlchemist I can think of two options: test for elements at a given point: https://gist.github.com/gwwar/2166393. Or add an invisible element on top that will receive your mouse events, and add an in-memory model of the bounding boxes you're interested in. Test for collisions. If you want to get fancy you can use something like a [Quadtree](http://en.wikipedia.org/wiki/Quadtree) But if the op doesn't care about IE support your solution will work fine. – Kerry Liu Sep 29 '13 at 01:17
  • quadtree are nice, but would just be an overkill to handle 5-50 items in a quiet application. I just had this idea : how about setting an empty image on top of the image+canvas, and have the areas bound to this empty image. So we don't need to use pointer-events. I tested it on Chrome and it works, unfortunately i cannot test it on IE which i don't have on my mac. Fiddle is here if you fancy have a try : http://jsfiddle.net/gamealchemist/cmKsD/3/ – GameAlchemist Sep 29 '13 at 01:24
  • @GameAlchemist Yup it's overkill, but that's what happens when you write this stuff from scratch. Jamie, you may want to look into canvas frameworks like [KineticJs](http://kineticjs.com/) which handles canvas events for you. – Kerry Liu Sep 29 '13 at 01:29
  • I mean by overkill that having a O(n) algorithm that just iterates the areas is just fine for a small n, especially in javascript which has a quite high overhead for arrays/recursion. Yes, KineticJS is fine, createJS is also a candidate. Would you mind testing my latest attempt on IE ? – GameAlchemist Sep 29 '13 at 01:32
  • yup im going to look into as much as possible thanks for the help guys – Jamie Sep 29 '13 at 01:33
  • @GameAlchemist works in my Win7/IE10 image if you downgrade jQuery to 1.9.1 – Kerry Liu Sep 29 '13 at 01:33
  • Thx. I don't know well enough jQuery to know about 1.9 vs 2.0 but the solution seems find now for our friend Jamie :-) – GameAlchemist Sep 29 '13 at 01:35
  • Ok so i edited the post to put this last solution -even if my interest for I.E. is... moderate...- :-) – GameAlchemist Sep 29 '13 at 01:44
  • @GameAlchemist jQuery 2.0 drops support for older browsers. It's probably just a bug or IE10 doesn't count. Anyway +1. Sorry for the nits. :) – Kerry Liu Sep 29 '13 at 01:49
  • Don't be sorry : even if it's between 5 and 20 times slower, some unaware people or company keep on using this rotten browser so... – GameAlchemist Sep 29 '13 at 01:58