Adding a list of names to JVectorMap

Hi everybody.

I have spent all the Sunday trying to implement a system to add a list with all the names of countries in the World Map provided by JVectorMaps as you can see it here.

I am using the 0.2.3. version available in this url.

Well, the idea is that hovering on any of the linked names on the list, the region should highlight at the same time, and viceversa, you know.

So far, I have been unable to implement it, and fond just a post in a forum offering some advice on it (here)

Obviously, my knowledge on this language is basic.

I would appreciate some further explanation on the post in stackoverflow.com, or whatever other solution to achieve the same result.

Best regards and thanks.

In order to know where you may have gone wrong, you’ll have to say where you are currently. What OS are you using, what have you managed to implement, what isn’t working exactly? are you getting error messages? or is something not installing? or you are getting maps but no hover?? Because once someone knows where you are they can better guide you to where you need to look next.

If you don’t need the vectory-ness, this can be done with lots of handwork with pure CSS as well. It’s less handwork if you already have the images you need (example). Though the vector version seems to have many advantages.

I am using Windows XP.

Everything works properly. It is simply that I cannot put in practice the solution in stackoverflow.

Just imagine the World Map from JVector Maps with the effect in your example.

By the way, the example in css is quite good but not enough in hovering the regions (obviously).

My code is as following, and I am unable to add the code from stackoverflow in the correct way. Sometimes there is no change in the map, and others it disappears because an error in the code.

I would appreciate some indication.

/**
 * jVectorMap version 0.2.3
 *
 * Copyright 2011-2012, Kirill Lebedev
 * Licensed under the MIT license.
 *
 */
(function( $ ){
  var apiParams = {
        colors: 1,
        values: 1,
        backgroundColor: 1,
        scaleColors: 1,
        normalizeFunction: 1
      },
      apiEvents = {
        onLabelShow: 'labelShow',
        onRegionOver: 'regionOver',
        onRegionOut: 'regionOut',
        onRegionClick: 'regionClick',
        onMarkerLabelShow: 'markerLabelShow',
        onMarkerOver: 'markerOver',
        onMarkerOut: 'markerOut',
        onMarkerClick: 'markerClick'
      };

  $.fn.vectorMap = function(options) {
    var defaultParams = {
          map: 'world_en',
          backgroundColor: '#505050',
          color: '#ffffff',
          hoverColor: 'black',
          scaleColors: ['#b6d6ff', '#005ace'],
          normalizeFunction: 'linear'
        },
        map,
        methodName,
        event;

    if (options === 'addMap') {
      WorldMap.maps[arguments[1]] = arguments[2];
    } else if (options === 'set' && apiParams[arguments[1]]) {
      methodName = arguments[1].charAt(0).toUpperCase()+arguments[1].substr(1);
      this.data('mapObject')['set'+methodName].apply(this.data('mapObject'), Array.prototype.slice.call(arguments, 2));
    } else {
      $.extend(defaultParams, options);
      defaultParams.container = this;
      this.css({
        position: 'relative',
        overflow: 'hidden'
      });
      map = new WorldMap(defaultParams);
      this.data('mapObject', map);
      for (event in apiEvents) {
        if (defaultParams[event]) {
          this.bind(apiEvents[event]+'.jvectormap', defaultParams[event]);
        }
      }
    }
  };

  var VectorCanvas = function(width, height) {
    this.mode = window.SVGAngle ? 'svg' : 'vml';
    if (this.mode == 'svg') {
      this.createSvgNode = function(nodeName) {
        return document.createElementNS(this.svgns, nodeName);
      }
    } else {
      try {
        if (!document.namespaces.rvml) {
          document.namespaces.add("rvml","urn:schemas-microsoft-com:vml");
        }
        this.createVmlNode = function (tagName) {
          return document.createElement('<rvml:' + tagName + ' class="rvml">');
        };
      } catch (e) {
        this.createVmlNode = function (tagName) {
          return document.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
        };
      }
      document.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
    }
    if (this.mode == 'svg') {
      this.canvas = this.createSvgNode('svg');
    } else {
      this.canvas = this.createVmlNode('group');
      this.canvas.style.position = 'absolute';
    }
    this.setSize(width, height);
  }

  VectorCanvas.prototype = {
    svgns: "http://www.w3.org/2000/svg",
    mode: 'svg',
    width: 0,
    height: 0,
    canvas: null,

    setSize: function(width, height) {
      if (this.mode == 'svg') {
        this.canvas.setAttribute('width', width);
        this.canvas.setAttribute('height', height);
      } else {
        this.canvas.style.width = width + "px";
        this.canvas.style.height = height + "px";
        this.canvas.coordsize = width+' '+height;
        this.canvas.coordorigin = "0 0";
        if (this.rootGroup) {
          var paths = this.rootGroup.getElementsByTagName('shape');
          for(var i=0, l=paths.length; i<l; i++) {
            paths[i].coordsize = width+' '+height;
            paths[i].style.width = width+'px';
            paths[i].style.height = height+'px';
          }
          this.rootGroup.coordsize = width+' '+height;
          this.rootGroup.style.width = width+'px';
          this.rootGroup.style.height = height+'px';
        }
      }
      this.width = width;
      this.height = height;
    },

    createPath: function(config) {
      var node;
      if (this.mode == 'svg') {
        node = this.createSvgNode('path');
        node.setAttribute('d', config.path);
        node.setAttribute('fill-rule', 'evenodd');
        node.setFill = function(color) {
          this.setAttribute("fill", color);
        };
        node.getFill = function(color) {
          return this.getAttribute("fill");
        };
        node.setOpacity = function(opacity) {
          this.setAttribute('fill-opacity', opacity);
        };
      } else {
        node = this.createVmlNode('shape');
        node.coordorigin = "0 0";
        node.coordsize = this.width + ' ' + this.height;
        node.style.width = this.width+'px';
        node.style.height = this.height+'px';
        node.fillcolor = WorldMap.defaultFillColor;
        node.stroked = false;
        node.path = VectorCanvas.pathSvgToVml(config.path);
        var scale = this.createVmlNode('skew');
        scale.on = true;
        scale.matrix = '0.01,0,0,0.01,0,0';
        scale.offset = '0,0';
        node.appendChild(scale);
        var fill = this.createVmlNode('fill');
        node.appendChild(fill);
        node.setFill = function(color) {
          this.getElementsByTagName('fill')[0].color = color;
        };
        node.getFill = function(color) {
          return this.getElementsByTagName('fill')[0].color;
        };
        node.setOpacity = function(opacity) {
          this.getElementsByTagName('fill')[0].opacity = parseInt(opacity*100)+'%';
        };
      }
      return node;
    },

    createCircle: function(config) {
      var node;
      if (this.mode == 'svg') {
        node = this.createSvgNode('circle');
        node.setAttribute('cx', config.x);
        node.setAttribute('cy', config.y);
        node.setAttribute('r', config.r);
        node.setAttribute('fill', config.fill);
        node.setAttribute('stroke', config.stroke);
        node.setPosition = function(point){
          node.setAttribute('cx', point.x);
          node.setAttribute('cy', point.y);
        }
      } else {
        node = this.createVmlNode('oval');
        node.style.width = config.r*2+'px';
        node.style.height = config.r*2+'px';
        node.style.left = config.x-config.r+'px';
        node.style.top = config.y-config.r+'px';
        node.fillcolor = config.fill;
        node.stroke = true;
        node.strokecolor = config.stroke;
        node.setPosition = function(point){
          node.style.left = point.x-config.r+'px';
          node.style.top = point.y-config.r+'px';
        }
      }
      return node;
    },

    createGroup: function(isRoot) {
      var node;
      if (this.mode == 'svg') {
        node = this.createSvgNode('g');
      } else {
        node = this.createVmlNode('group');
        node.style.width = this.width+'px';
        node.style.height = this.height+'px';
        node.style.left = '0px';
        node.style.top = '0px';
        node.coordorigin = "0 0";
        node.coordsize = this.width + ' ' + this.height;
      }
      if (isRoot) {
        this.rootGroup = node;
      }
      return node;
    },

    applyTransformParams: function(scale, transX, transY) {
      if (this.mode == 'svg') {
        this.rootGroup.setAttribute('transform', 'scale('+scale+') translate('+transX+', '+transY+')');
      } else {
        this.rootGroup.coordorigin = (this.width-transX-this.width/100)+','+(this.height-transY-this.height/100);
        this.rootGroup.coordsize = this.width/scale+','+this.height/scale;
      }
    }
  }

  VectorCanvas.pathSvgToVml = function(path) {
    var result = '',
      cx = 0, cy = 0, ctrlx, ctrly;

    path = path.replace(/(-?\\d+)e(-?\\d+)/g, '0');
    return path.replace(/([MmLlHhVvCcSs])\\s*((?:-?\\d*(?:\\.\\d+)?\\s*,?\\s*)+)/g, function(segment, letter, coords, index){
      coords = coords.replace(/(\\d)-/g, '$1,-').replace(/\\s+/g, ',').split(',');
      if (!coords[0]) coords.shift();
      for (var i=0, l=coords.length; i<l; i++) {
        coords[i] = Math.round(100*coords[i]);
      }
      switch (letter) {
        case 'm':
          cx += coords[0];
          cy += coords[1];
          return 't'+coords.join(',');
        break;
        case 'M':
          cx = coords[0];
          cy = coords[1];
          return 'm'+coords.join(',');
        break;
        case 'l':
          cx += coords[0];
          cy += coords[1];
          return 'r'+coords.join(',');
        break;
        case 'L':
          cx = coords[0];
          cy = coords[1];
          return 'l'+coords.join(',');
        break;
        case 'h':
          cx += coords[0];
          return 'r'+coords[0]+',0';
        break;
        case 'H':
          cx = coords[0];
          return 'l'+cx+','+cy;
        break;
        case 'v':
          cy += coords[0];
          return 'r0,'+coords[0];
        break;
        case 'V':
          cy = coords[0];
          return 'l'+cx+','+cy;
        break;
        case 'c':
          ctrlx = cx + coords[coords.length-4];
          ctrly = cy + coords[coords.length-3];
          cx += coords[coords.length-2];
          cy += coords[coords.length-1];
          return 'v'+coords.join(',');
        break;
        case 'C':
          ctrlx = coords[coords.length-4];
          ctrly = coords[coords.length-3];
          cx = coords[coords.length-2];
          cy = coords[coords.length-1];
          return 'c'+coords.join(',');
        break;
        case 's':
          coords.unshift(cy-ctrly);
          coords.unshift(cx-ctrlx);
          ctrlx = cx + coords[coords.length-4];
          ctrly = cy + coords[coords.length-3];
          cx += coords[coords.length-2];
          cy += coords[coords.length-1];
          return 'v'+coords.join(',');
        break;
        case 'S':
          coords.unshift(cy+cy-ctrly);
          coords.unshift(cx+cx-ctrlx);
          ctrlx = coords[coords.length-4];
          ctrly = coords[coords.length-3];
          cx = coords[coords.length-2];
          cy = coords[coords.length-1];
          return 'c'+coords.join(',');
        break;
      }
      return '';
    }).replace(/z/g, 'e');
  }

  var WorldMap = function(params) {
    params = params || {};
    var map = this;
    var mapData = WorldMap.maps[params.map];

    this.params = params;

    this.container = params.container;

    this.defaultWidth = mapData.width;
    this.defaultHeight = mapData.height;

    this.color = params.color;
    this.hoverColor = params.hoverColor;
    this.setBackgroundColor(params.backgroundColor);

    this.width = params.container.width();
    this.height = params.container.height();

    this.resize();

    $(window).resize(function(){
      map.width = params.container.width();
      map.height = params.container.height();
      map.resize();
      map.canvas.setSize(map.width, map.height);
      map.applyTransform();
    });

    this.canvas = new VectorCanvas(this.width, this.height);
    params.container.append(this.canvas.canvas);

    this.makeDraggable();

    this.rootGroup = this.canvas.createGroup(true);

    this.index = WorldMap.mapIndex;
    this.label = $('<div/>').addClass('jvectormap-label').appendTo($('body'));
    $('<div/>').addClass('jvectormap-zoomin').text('+').appendTo(params.container);
    $('<div/>').addClass('jvectormap-zoomout').html('&#x2212;').appendTo(params.container);

    for(var key in mapData.paths) {
      var path = this.canvas.createPath({path: mapData.paths[key].path});
      path.setFill(this.color);
      if (this.canvas.mode == 'svg') {
        path.setAttribute('class', 'jvectormap-region');
      } else {
        $(path).addClass('jvectormap-region');
      }
      path.id = 'jvectormap'+map.index+'_'+key;
      map.countries[key] = path;
      $(this.rootGroup).append(path);
    }

    $(params.container).delegate('.jvectormap-region', 'mouseover mouseout', function(e){
      var path = e.target,
        code = e.target.id.substr(e.target.id.indexOf('_')+1),
        labelShowEvent = $.Event('labelShow.jvectormap'),
        regionOverEvent = $.Event('regionOver.jvectormap');

      if (e.type == 'mouseover') {
        $(params.container).trigger(regionOverEvent, 

);
if (!regionOverEvent.isDefaultPrevented()) {
if (params.hoverOpacity) {
path.setOpacity(params.hoverOpacity);
}
if (params.hoverColor) {
path.currentFillColor = path.getFill()+‘’;
path.setFill(params.hoverColor);
}
}

    map.label.text(mapData.paths
.name);
        $(params.container).trigger(labelShowEvent, [map.label, code]);
        if (!labelShowEvent.isDefaultPrevented()) {
          map.label.show();
          map.labelWidth = map.label.width();
          map.labelHeight = map.label.height();
        }
      } else {
        path.setOpacity(1);
        if (path.currentFillColor) {
          path.setFill(path.currentFillColor);
        }
        map.label.hide();
        $(params.container).trigger('regionOut.jvectormap', 

);
}
});

$(params.container).delegate('.jvectormap-region', 'click', function(e){
  var path = e.target;
  var code = e.target.id.split('_').pop();
  $(params.container).trigger('regionClick.jvectormap', 
);
    });

    params.container.mousemove(function(e){
      if (map.label.is(':visible')) {
        map.label.css({
          left: e.pageX-15-map.labelWidth,
          top: e.pageY-15-map.labelHeight
        })
      }
    });

    this.setColors(params.colors);

    this.canvas.canvas.appendChild(this.rootGroup);

    if (params.markers) {
      this.createMarkers(params.markers);
      $(params.container).delegate('.jvectormap-marker', 'mouseover mouseout', function(e){
        var marker = e.target,
            index = marker.getAttribute('data-index'),
            labelShowEvent = $.Event('markerLabelShow.jvectormap'),
            markerOverEvent = $.Event('markerOver.jvectormap');

        if (e.type == 'mouseover') {
          $(params.container).trigger(markerOverEvent, [index]);
          $(params.container).trigger(labelShowEvent, [map.label, index]);
          if (!labelShowEvent.isDefaultPrevented()) {
            map.label.text(map.markers[index].config.name || '');
            map.label.show();
            map.labelWidth = map.label.width();
            map.labelHeight = map.label.height();
          }
        } else {
          map.label.hide();
          $(params.container).trigger('markerOut.jvectormap', [index]);
        }
      });
      $(params.container).delegate('.jvectormap-marker', 'click', function(e){
        var marker = e.target;
        var index = marker.getAttribute('data-index');
        $(params.container).trigger('markerClick.jvectormap', [index]);
      });
    }

    this.applyTransform();

    this.colorScale = new ColorScale(params.scaleColors, params.normalizeFunction, params.valueMin, params.valueMax);
    if (params.values) {
      this.values = params.values;
      this.setValues(params.values);
    }

    this.bindZoomButtons();

    WorldMap.mapIndex++;
  }

  WorldMap.prototype = {
    transX: 0,
    transY: 0,
    scale: 1,
    baseTransX: 0,
    baseTransY: 0,
    baseScale: 1,

    width: 0,
    height: 0,
    countries: {},
    countriesColors: {},
    countriesData: {},
    zoomStep: 1.4,
    zoomMaxStep: 4,
    zoomCurStep: 1,

    setColors: function(key, color) {
      if (typeof key == 'string') {
        this.countries[key].setFill(color);
      } else {
        var colors = key;
        for (var code in colors) {
          if (this.countries

) {
this.countries

.setFill(colors

);
}
}
}
},

setValues: function(values) {
  var max = 0,
    min = Number.MAX_VALUE,
    val;

  for (var cc in values) {
    val = parseFloat(values[cc]);
    if (val &gt; max) max = values[cc];
    if (val && val &lt; min) min = val;
  }
  this.colorScale.setMin(min);
  this.colorScale.setMax(max);

  var colors = {};
  for (cc in values) {
    val = parseFloat(values[cc]);
    if (val) {
      colors[cc] = this.colorScale.getColor(val);
    } else {
      colors[cc] = this.color;
    }
  }
  this.setColors(colors);
  this.values = values;
},

setBackgroundColor: function(backgroundColor) {
  this.container.css('background-color', backgroundColor);
},

setScaleColors: function(colors) {
  this.colorScale.setColors(colors);
  if (this.values) {
    this.setValues(this.values);
  }
},

setNormalizeFunction: function(f) {
  this.colorScale.setNormalizeFunction(f);
  if (this.values) {
    this.setValues(this.values);
  }
},

resize: function() {
  var curBaseScale = this.baseScale;
  if (this.width / this.height &gt; this.defaultWidth / this.defaultHeight) {
    this.baseScale = this.height / this.defaultHeight;
    this.baseTransX = Math.abs(this.width - this.defaultWidth * this.baseScale) / (2 * this.baseScale);
  } else {
    this.baseScale = this.width / this.defaultWidth;
    this.baseTransY = Math.abs(this.height - this.defaultHeight * this.baseScale) / (2 * this.baseScale);
  }
  this.scale *= this.baseScale / curBaseScale;
  this.transX *= this.baseScale / curBaseScale;
  this.transY *= this.baseScale / curBaseScale;
},

reset: function() {
  this.countryTitle.reset();
  for(var key in this.countries) {
    this.countries[key].setFill(WorldMap.defaultColor);
  }
  this.scale = this.baseScale;
  this.transX = this.baseTransX;
  this.transY = this.baseTransY;
  this.applyTransform();
},

applyTransform: function() {
  var maxTransX, maxTransY, minTransX, maxTransY;
  if (this.defaultWidth * this.scale &lt;= this.width) {
    maxTransX = (this.width - this.defaultWidth * this.scale) / (2 * this.scale);
    minTransX = (this.width - this.defaultWidth * this.scale) / (2 * this.scale);
  } else {
    maxTransX = 0;
    minTransX = (this.width - this.defaultWidth * this.scale) / this.scale;
  }

  if (this.defaultHeight * this.scale &lt;= this.height) {
    maxTransY = (this.height - this.defaultHeight * this.scale) / (2 * this.scale);
    minTransY = (this.height - this.defaultHeight * this.scale) / (2 * this.scale);
  } else {
    maxTransY = 0;
    minTransY = (this.height - this.defaultHeight * this.scale) / this.scale;
  }

  if (this.transY &gt; maxTransY) {
    this.transY = maxTransY;
  } else if (this.transY &lt; minTransY) {
    this.transY = minTransY;
  }
  if (this.transX &gt; maxTransX) {
    this.transX = maxTransX;
  } else if (this.transX &lt; minTransX) {
    this.transX = minTransX;
  }

  this.canvas.applyTransformParams(this.scale, this.transX, this.transY);

  if (this.markers) {
    this.repositionMarkers();
  }
},

makeDraggable: function(){
  var mouseDown = false;
  var oldPageX, oldPageY;
  var self = this;
  this.container.mousemove(function(e){
    if (mouseDown) {
      var curTransX = self.transX;
      var curTransY = self.transY;

      self.transX -= (oldPageX - e.pageX) / self.scale;
      self.transY -= (oldPageY - e.pageY) / self.scale;

      self.applyTransform();

      oldPageX = e.pageX;
      oldPageY = e.pageY;
    }
    return false;
  }).mousedown(function(e){
    mouseDown = true;
    oldPageX = e.pageX;
    oldPageY = e.pageY;
    return false;
  }).mouseup(function(){
    mouseDown = false;
    return false;
  });
},

bindZoomButtons: function() {
  var map = this;
  var sliderDelta = ($('#zoom').innerHeight() - 6*2 - 15*2 - 3*2 - 7 - 6) / (this.zoomMaxStep - this.zoomCurStep);
  this.container.find('.jvectormap-zoomin').click(function(){
    if (map.zoomCurStep &lt; map.zoomMaxStep) {
      var curTransX = map.transX;
      var curTransY = map.transY;
      var curScale = map.scale;
      map.transX -= (map.width / map.scale - map.width / (map.scale * map.zoomStep)) / 2;
      map.transY -= (map.height / map.scale - map.height / (map.scale * map.zoomStep)) / 2;
      map.setScale(map.scale * map.zoomStep);
      map.zoomCurStep++;
      $('#zoomSlider').css('top', parseInt($('#zoomSlider').css('top')) - sliderDelta);
    }
  });
  this.container.find('.jvectormap-zoomout').click(function(){
    if (map.zoomCurStep &gt; 1) {
      var curTransX = map.transX;
      var curTransY = map.transY;
      var curScale = map.scale;
      map.transX += (map.width / (map.scale / map.zoomStep) - map.width / map.scale) / 2;
      map.transY += (map.height / (map.scale / map.zoomStep) - map.height / map.scale) / 2;
      map.setScale(map.scale / map.zoomStep);
      map.zoomCurStep--;
      $('#zoomSlider').css('top', parseInt($('#zoomSlider').css('top')) + sliderDelta);
    }
  });
},

setScale: function(scale) {
  this.scale = scale;
  this.applyTransform();
},

getCountryPath: function(cc) {
  return $('#'+cc)[0];
},

createMarkers: function(markers) {
  var group = this.canvas.createGroup(),
      i,
      marker,
      point,
      markerConfig,
      defaultConfig = {latLng: [0, 0], r: 5, fill: 'white', stroke: '#505050'};

  this.markers = [];

  for (i = 0; i &lt; markers.length; i++) {
    markerConfig = markers[i] instanceof Array ? {latLng: markers[i]} : markers[i];
    markerConfig = $.extend({}, defaultConfig, this.params.markerDefaults, markerConfig);
    point = this.latLngToPoint.apply(this, markerConfig.latLng);
    $.extend(markerConfig, point);
    marker = this.canvas.createCircle(markerConfig);
    if (this.canvas.mode == 'svg') {
      marker.setAttribute('class', 'jvectormap-marker');
      marker.setAttribute('data-index', i);
    } else {
      $(marker).addClass('jvectormap-marker').attr('data-index', i);
    }
    this.markers.push({element: marker, config: markerConfig});
    $(group).append(marker);
  }

  this.canvas.canvas.appendChild(group);
},

repositionMarkers: function() {
  var i,
      point;

  for (i = 0; i &lt; this.markers.length; i++) {
    point = this.latLngToPoint.apply(this, this.markers[i].config.latLng);
    this.markers[i].element.setPosition(point);
  }
},

latLngToPoint: function(lat, lng) {
  var x,
      y,
      centralMeridian = WorldMap.maps[this.params.map].projection.centralMeridian,
      width = this.width - this.baseTransX * 2 * this.baseScale,
      height = this.height - this.baseTransY * 2 * this.baseScale,
      inset,
      bbox,
      scaleFactor = this.scale / this.baseScale;

  if (lng &lt; (-180 + centralMeridian)) {
    lng += 360;
  }

  x = (lng - centralMeridian) / 360 * WorldMap.circumference,
  y = (180 / Math.PI * (5 / 4) * Math.log(Math.tan(Math.PI / 4 + (4 / 5) * -lat * Math.PI / 360))) / 360 * WorldMap.circumference;

  inset = this.getInsetForPoint(x, y);
  if (inset) {
    bbox = inset.bbox;

    x = (x - bbox[0].x) / (bbox[1].x - bbox[0].x) * inset.width * this.scale;
    y = (y - bbox[0].y) / (bbox[1].y - bbox[0].y) * inset.height * this.scale;

    return {
      x: x + this.transX*this.scale + inset.left*this.scale,
      y: y + this.transY*this.scale + inset.top*this.scale
    };
  } else {
    return {x: 0, y: 0};
  }
},

getInsetForPoint: function(x, y){
  var insets = WorldMap.maps[this.params.map].insets,
      i,
      bbox;

  for (i = 0; i &lt; insets.length; i++) {
    bbox = insets[i].bbox;
    if (x &gt; bbox[0].x && x &lt; bbox[1].x && y &gt; bbox[0].y && y &lt; bbox[1].y) {
      return insets[i];
    }
  }
  return false;
}

},

WorldMap.xlink = “http://www.w3.org/1999/xlink”;
WorldMap.mapIndex = 1;
WorldMap.maps = {};
WorldMap.circumference = 40075017;

var ColorScale = function(colors, normalizeFunction, minValue, maxValue) {
if (colors) this.setColors(colors);
if (normalizeFunction) this.setNormalizeFunction(normalizeFunction);
if (minValue) this.setMin(minValue);
if (minValue) this.setMax(maxValue);
}

ColorScale.prototype = {
colors: ,

setMin: function(min) {
  this.clearMinValue = min;
  if (typeof this.normalize === 'function') {
    this.minValue = this.normalize(min);
  } else {
    this.minValue = min;
  }
},

setMax: function(max) {
  this.clearMaxValue = max;
  if (typeof this.normalize === 'function') {
    this.maxValue = this.normalize(max);
  } else {
    this.maxValue = max;
  }
},

setColors: function(colors) {
  for (var i=0; i&lt;colors.length; i++) {
    colors[i] = ColorScale.rgbToArray(colors[i]);
  }
  this.colors = colors;
},

setNormalizeFunction: function(f) {
  if (f === 'polynomial') {
    this.normalize = function(value) {
      return Math.pow(value, 0.2);
    }
  } else if (f === 'linear') {
    delete this.normalize;
  } else {
    this.normalize = f;
  }
  this.setMin(this.clearMinValue);
  this.setMax(this.clearMaxValue);
},

getColor: function(value) {
  if (typeof this.normalize === 'function') {
    value = this.normalize(value);
  }
  var lengthes = [];
  var fullLength = 0;
  var l;
  for (var i=0; i&lt;this.colors.length-1; i++) {
    l = this.vectorLength(this.vectorSubtract(this.colors[i+1], this.colors[i]));
    lengthes.push(l);
    fullLength += l;
  }
  var c = (this.maxValue - this.minValue) / fullLength;
  for (i=0; i&lt;lengthes.length; i++) {
    lengthes[i] *= c;
  }
  i = 0;
  value -= this.minValue;
  while (value - lengthes[i] &gt;= 0) {
    value -= lengthes[i];
    i++;
  }
  var color;
  if (i == this.colors.length - 1) {
    color = this.vectorToNum(this.colors[i]).toString(16);
  } else {
    color = (
      this.vectorToNum(
        this.vectorAdd(this.colors[i],
          this.vectorMult(
            this.vectorSubtract(this.colors[i+1], this.colors[i]),
            (value) / (lengthes[i])
          )
        )
      )
    ).toString(16);
  }

  while (color.length &lt; 6) {
    color = '0' + color;
  }
  return '#'+color;
},

vectorToNum: function(vector) {
  var num = 0;
  for (var i=0; i&lt;vector.length; i++) {
    num += Math.round(vector[i])*Math.pow(256, vector.length-i-1);
  }
  return num;
},

vectorSubtract: function(vector1, vector2) {
  var vector = [];
  for (var i=0; i&lt;vector1.length; i++) {
    vector[i] = vector1[i] - vector2[i];
  }
  return vector;
},

vectorAdd: function(vector1, vector2) {
  var vector = [];
  for (var i=0; i&lt;vector1.length; i++) {
    vector[i] = vector1[i] + vector2[i];
  }
  return vector;
},

vectorMult: function(vector, num) {
  var result = [];
  for (var i=0; i&lt;vector.length; i++) {
    result[i] = vector[i] * num;
  }
  return result;
},

vectorLength: function(vector) {
  var result = 0;
  for (var i=0; i&lt;vector.length; i++) {
    result += vector[i]*vector[i];
  }
  return Math.sqrt(result);
}

}

ColorScale.arrayToRgb = function(ar) {
var rgb = ‘#’;
var d;
for (var i=0; i<ar.length; i++) {
d = ar[i].toString(16);
rgb += d.length == 1 ? ‘0’+d : d;
}
return rgb;
}

ColorScale.rgbToArray = function(rgb) {
rgb = rgb.substr(1);
return [parseInt(rgb.substr(0, 2), 16), parseInt(rgb.substr(2, 2), 16), parseInt(rgb.substr(4, 2), 16)];
}
})( jQuery );

Hi again.

This is exactly the case.

Is it possible to set it in JVectorMaps?

Thanks.

The basic idea is to have some kind of relation between the link attributes in your html and the region attributes in your jvectormap object.

After that, you can implement a simple algo to look for the region and trigger the setHovered(true) and setHovered(false) on that particular region. I’ve done something like this for markers, using <a> elements.

Also, you may want to check out mapael.

No, the buttons on the mapael are not links, but vector images. I mean the button “MA” is part of the Massachusetts region.

This is exactly what I am looking for.

You know some example or demo?

If you want a demo, please build a jsfiddle or jsbin and I’ll modify that code.

As I said, my knowledge on this language is basic.

I am looking for some tutorial or practical example applicable to the case.

What myty and poes are getting at is that you have to help us to help you.

Try and set up the map plugin is a JS fiddle and add to add the required functionality on your own.
As you stated yourself, your JS knowledge is basic, so presumably you’ll get stuck at some point.
When this happens, post back here and I’m sure someone will be able to help.

Doing it this way just means that we don’t have to do everything from scratch for you.

The application comes with four different .js files. I have tried jsfiddle or jsbin with no result.

I have modified the original code to get the regions linked to different urls:


...

  $.fn.vectorMap = function(options) {
    var defaultParams = {
          map: 'world_en',
          color: '#6383d3',
          hoverColor: '#323637',
          onRegionClick: function(event, code) {
        if (code === 'UK') {
            window.location = 'xxx'
        }
        else if (code === 'CA') {
            window.location = 'xxx'
        }
        else if (code === 'US') {
            window.location = 'xxx'
        }
    },
          normalizeFunction: 'linear'
        },
        
        map,
        methodName,
        event;

...

But I am unable to apply the solution pointed by myty (the setHovered(true) and setHovered(false))

What about a hover to call the selected region.

<a class="canada" href="canada">Canada</a>

And then:


        <script>
         $(document).ready(function(){
            $('a.canada').hover(function(){
               $(this)...............................................................
         });
      </script>


$(params.container).delegate('.jvectormap-region', 'click', function(e){
var path = e.target;
var code = e.target.id.split('_').pop();
$(params.container).trigger('regionClick.jvectorma p', 

);
});

What about using a on hover function to trigger the setHovered(true) for a given area according to the code above.

  <a class="canada" href="canada">Canada</a>

        <script>
         $(document).ready(function(){
            $('a.canada').hover(function(){
               $(this).................................

         });
      </script>

You are unable to apply setHovered because it’s not part of the exposed API of jvectormap. It’s there, but it’s not documented, you have to look at the map object for yourself.

For markers, I did something like this:

mapObj.markers[i].element.setHovered(true)

where i was the result of a function I wrote:

i = findMarker(markers, $(elem).text())

. elem is a <a> tag in a <li> in a <ul id=“counties”> of counties, and I used an event delegation:

$('#counties').on('mouseover mouseout', 'a:first-child', function(event){

.

I’ll see if I can build a jsfiddle, but it may take a while, I have things to do. If you have a live link of your own, it would be easier to just start from there.

Hi,

This is probably no help whatsoever but I uploaded a test here that allows regions to be highlighted by a separate label and vice versa. I only added two countries but the format would be the same for all countries but the code needs to be simplified as you don’t want to call it for every country like that but that is beyond my meagre skills.

That is exactly what I am looking for.

I have downloaded the url but does not work in local.

Please, might you paste your implementation?

Hi,

All I basically did was download the map zip and put the following page in the tests folder.


<!DOCTYPE html>
<html>
<head>
<title>jVectorMap demo</title>
<link rel="stylesheet" media="all" href="../jquery-jvectormap.css"/>
<script src="assets/jquery-1.7.2.min.js"></script>
<script src="../jquery-jvectormap.js"></script>
<script src="assets/jquery-jvectormap-world-en.js"></script>
<script>
$(function () {
			    $('#map').vectorMap({
			        map: 'world_en'
			    });


			    $('#map').bind('regionOver.jvectormap', function (event, code) {
			        $('#' + code).addClass('over');

			    })
			    $('#map').bind('regionOut.jvectormap', function (event, code) {
			        $('#' + code).removeClass('over');
			    });

			    $('#US').hover(
			        function () {
			           
			            $('#map').vectorMap('set', 'colors', {
			                US: '#f00f00'
			            })
			        },
			        function () {
			            $('#map').vectorMap('set', 'colors', {
			                US: '#ffffff'
			            })
			        }
			    );

			    $('#AU').hover(
			        function () {
			            $('#map').vectorMap('set', 'colors', {
			                AU: '#f00f00'
			            })
			        },
			        function () {
			            $('#map').vectorMap('set', 'colors', {
			                AU: '#ffffff'
			            })
			        }
			    );



			})
 </script>
<style type="text/css">
#countries {
	margin:0;
	padding:0;
	list-style:none;
	clear:both;
}
#countries li {
	float:left;
	padding:10px;
	border:1px solid #000;
	background:blue;
	color:#fff;
	margin:10px;
	cursor:pointer;
}
#countries li.over { background:red }
</style>
</head>
<body>
<div id="map" style="width: 600px; height: 400px"></div>
<ul id="countries">
		<li id="US">America</li>
		<li id="AU">Australia</li>
</ul>
</body>
</html>

I used the map references as Ids on the list:


<ul id="countries">
		<li id="US">America</li>
		<li id="AU">Australia</li>
</ul>

Then used the reference gained from the code variable to highlight the list item by adding and removing a class:


 $('#map').bind('regionOver.jvectormap', function (event, code) {
			        $('#' + code).addClass('over');

    })
$('#map').bind('regionOut.jvectormap', function (event, code) {
			        $('#' + code).removeClass('over');
    });

As long as you list all the countries in the html using the correct ids they will get highlighted with the above code when required.

The awkward part is doing the reverse and I used this:


 $('#US').hover(
			        function () {
			           
			            $('#map').vectorMap('set', 'colors', {
			                US: '#f00f00'
			            })
			        },
			        function () {
			            $('#map').vectorMap('set', 'colors', {
			                US: '#ffffff'
			            })
			        }
			    );
 

$('#AU').hover(
			        function () {
			            $('#map').vectorMap('set', 'colors', {
			                AU: '#f00f00'
			            })
			        },
			        function () {
			            $('#map').vectorMap('set', 'colors', {
			                AU: '#ffffff'
			            })
			        }
			    );

However you would need to repeat that for all the ids so it needs one of our js experts to make it work automatically. If for example the “AU” part of “AU: ‘#f00f00’” could be gained from the id of the list item that was hovered then you would only need the one routine.

Hopefully one of the others here can simplify into a single routine.:slight_smile:

You are a master Paul O’B.

The problem is solved, for the first time, because I have read every post trying to do this same effect in all the forums and sites on JVectorMap and vector maps in general and there is no one offering a valid solution.

Thanks very much pal.

I can see how some of what I said goes over your head, since you’re just starting, and that’s why I asked for a live playground. This is a reply to what I believe to be a complete unfounded remark about no one offering a valid solution. stackoverflow is giving you the right answer (if only for selected part), and I provided more than enough info for you to build a working example, complete with hovered part.

Now, Paul’s maybe works, but it’s a dirty one, with many caveats, the biggest being the weak JS code in it, the second biggest being the complete disregard for the unified CSS style used in jvectormap.

The map has hover and selected styles for markers and regions, available as properties for the map object. Paul, on the other hand, is creating its own style, and, what’s worse, he’s controlling style from JS (what I mean is that while changing class attribute values is OK, hardcoding CSS values with JS isn’t OK at all).
I mean, Paul, really?! :slight_smile:

My offer still stands, if you are able to build a live js fiddle.

lol - yes I agree with all that you say. :slight_smile:

I actually took part of the code from the documentation.

e.g.

Methods

set option, value
This method could be to used to change any option except the callbacks after map initialization.


    $('#map').vectorMap('set', 'colors', {us: '#0000ff'});

Obviously I latched on to what I understood and I’m sure there’s a much better way to do this. It was really just a proof of concept to see if I could get something working with my limited knowledge of Jquery (as I mentioned before) and to spark a discussion like this :slight_smile:

I did start with a caveat that it was probably no use whatsoever but at least I tried :wink: