0

I am using JQVMAP to generate some maps of the US. The plugin has an onRegionClick callback. I am trying to zoom in to the clicked state within this function. I kind of have an idea of how to do it by converting the SVG path returned to me onClick to viewBox coordinates, however, I am having trouble with the conversion. Here is what I have so far.

<script type="text/javascript">
jQuery(document).ready(function() {
    jQuery('#vmap').vectorMap(
    {
        map: 'usa_en',
        backgroundColor: '#a5bfdd',
        borderColor: '#818181',
        borderOpacity: .50,
        borderWidth: 1,
        color: '#f4f3f0',
        enableZoom: false,
        hoverColor: '#c9dfaf',
        hoverOpacity: null,
        normalizeFunction: 'linear',
        scaleColors: ['#b6d6ff', '#005ace'],
        selectedColor: '#c9dfaf',
        selectedRegion: null,
        showTooltip: true,
        onRegionClick: function(element, code, region)
        {
            //$('#vmap > svg')[0].setAttribute('viewBox', vmlPath);
            console.log(region.path);
            console.log(region.name);
        }
    });
});
</script>

Link to live demo. How can I convert the SVG path to viewBox coordinates? Am i going about this the right way? Or is there a better way to do this? My ultimate goal is to zoom into the state onRegionClick.

hanleyhansen
  • 6,304
  • 8
  • 37
  • 73
  • Do you need old IE support? VML has no viewBox, so if you try this approach it won't work on older IE. I haven't used JQVMAP but it seems to me that there must be some way to zoom and translate to the correct position. – methodofaction Nov 21 '12 at 16:52
  • @Duopixel I can zoom anywhere I want by simply specifying the coordinates for the viewbox. My issue is translating to the correct position. If you look at the console you'll see the output of the path. I need to turn that into something meaningful (viewBox coordinates) so that I can zoom to that position. – hanleyhansen Nov 21 '12 at 16:56
  • 2
    try `console.log(element.getBBox())` and see if those coordinates are what you're looking for. They will most likely be the coords before the scaling transform so you might need to apply some math there. – methodofaction Nov 21 '12 at 20:11
  • @Duopixel Tried `console.log(region.path.getBBox());`, `console.log(region.getBBox());`, and `console.log(element.getBBox());` and all return `has no method 'getBBox'` – hanleyhansen Nov 26 '12 at 14:25
  • 1
    Looks like JQVMAP's documentation is wrong, it should be `onRegionClick: function(event, code, region)` and then `event.target.getBBox()` – methodofaction Nov 26 '12 at 14:39
  • @Duopixel DUDE!!! Please put that in an answer so i can give you credit!!!!!!!!!! – hanleyhansen Nov 26 '12 at 15:13
  • @Duopixel that worked but the math is wrong so the zoom is off. Any ideas? I want to also zoom back out somehow. I might be better off just finding another plugin that does more of what i'm looking for. – hanleyhansen Nov 26 '12 at 18:55
  • 1
    The dimensions returned by `getBBox()` are before the map is scaled, so you need to apply the same matrix transformation on these coords as the transformation that is applied on the map or display the map at its original size. – methodofaction Nov 26 '12 at 19:43
  • @Duopixel that makes sense. Not sure where to start with that though. I found some matrix scaling on line 229 of `jquery.vmap.js` but i'm not sure if I should apply the same scaling in my instance onRegionClick or what? – hanleyhansen Nov 27 '12 at 14:36
  • @Duopixel how can i apply the same transformation to those coordinates? – hanleyhansen Nov 28 '12 at 16:27
  • 1
    Try element.getBoundingClientRect(), but I'm not sure it will work in all browsers. If that fails, take a look at this answer: http://stackoverflow.com/questions/13430241/scaling-a-rotated-object-to-fit-specific-rect, sorry I can't help any more. – methodofaction Nov 28 '12 at 17:42
  • @Duopixel just like you thought. Works but only in chrome. – hanleyhansen Nov 28 '12 at 18:57

2 Answers2

1

What you are trying to accomplish is extremely difficult. SVG paths (especially the size of the ones you are dealing with) are very hard to parse. The most meaningful thing you could probably parse from the path is the first value (values are comma separted). This value will either start with a "m" or a "M". Lowercase m is a relative starting point and uppercase M is an absolute starting point.

That being said once you know where the path starts you can start to set your viewBox. However, you still don't the width and height of the path (the Texas path is larger than the Rhode Island path). So, you can set the starting point of the viewBox but have no idea how big to make it, and parsing out that info would be a nightmare!

The best way would be to find out yourself what the viewBox would be for each state and include that in your jquery.vmap.usa.js object info for each state. So each object would have a path, a name, and a viewBox. Then you could grab it in your onRegionClick event by calling region.viewBox.

Outside of that, this is the best I could come up with:

var showAll = false;
    jQuery(document).ready(function () {
        jQuery('#vmap').vectorMap(
    {
        map: 'usa_en',
        backgroundColor: '#a5bfdd',
        borderColor: '#818181',
        borderOpacity: .50,
        borderWidth: 1,
        color: '#f4f3f0',
        enableZoom: false,
        hoverColor: '#c9dfaf',
        hoverOpacity: null,
        normalizeFunction: 'linear',
        scaleColors: ['#b6d6ff', '#005ace'],
        selectedColor: '#c9dfaf',
        selectedRegion: null,
        showTooltip: true,
        onRegionClick: function (element, code, region) {
            $('path').each(function () {
                if (showAll) {
                    $(this).show();
                } else {
                    $(this).hide();
                }
            });
            if (showAll) { showAll = false; } else { showAll = true; }

            var id = '#jqvmap1_' + code;
            $(id).show();
        }
    });
    });
zgood
  • 12,181
  • 2
  • 25
  • 26
1

You can just use jVectorMap, from which jqvmap was derived. Its API has focusOn method to zoom to the specified area on the map. The area could be specified by coordinates or region code.

bjornd
  • 22,397
  • 4
  • 57
  • 73
  • This seems like it will work. Thanks for your help. I tried implementing it by my syntax might be wrong. Mind taking a look at it [here](http://pastebin.com/5v6Z1JME)? – hanleyhansen Nov 27 '12 at 14:27
  • This is the [latest code](http://pastebin.com/V4Wn1WKz) and here is the [live link](http://www.hanseninfotech.com/interactive_map/) – hanleyhansen Nov 27 '12 at 15:04