SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 35
  1. #1
    SitePoint Enthusiast
    Join Date
    Sep 2013
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    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.

  2. #2
    om nom nom nom Stomme poes's Avatar
    Join Date
    Aug 2007
    Location
    Netherlands
    Posts
    10,234
    Mentioned
    47 Post(s)
    Tagged
    1 Thread(s)
    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.

  3. #3
    SitePoint Enthusiast
    Join Date
    Sep 2013
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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.

    Code JavaScript:
    /**
     * 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, [code]);
            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[code].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', [code]);
          }
        });
     
        $(params.container).delegate('.jvectormap-region', 'click', function(e){
          var path = e.target;
          var code = e.target.id.split('_').pop();
          $(params.container).trigger('regionClick.jvectormap', [code]);
        });
     
        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[code]) {
                this.countries[code].setFill(colors[code]);
              }
            }
          }
        },
     
        setValues: function(values) {
          var max = 0,
            min = Number.MAX_VALUE,
            val;
     
          for (var cc in values) {
            val = parseFloat(values[cc]);
            if (val > max) max = values[cc];
            if (val && val < 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 > 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 <= 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 <= 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 > maxTransY) {
            this.transY = maxTransY;
          } else if (this.transY < minTransY) {
            this.transY = minTransY;
          }
          if (this.transX > maxTransX) {
            this.transX = maxTransX;
          } else if (this.transX < 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 < 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 > 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 < 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 < 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 < (-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 < insets.length; i++) {
            bbox = insets[i].bbox;
            if (x > bbox[0].x && x < bbox[1].x && y > bbox[0].y && y < 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<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<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<lengthes.length; i++) {
            lengthes[i] *= c;
          }
          i = 0;
          value -= this.minValue;
          while (value - lengthes[i] >= 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 < 6) {
            color = '0' + color;
          }
          return '#'+color;
        },
     
        vectorToNum: function(vector) {
          var num = 0;
          for (var i=0; i<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<vector1.length; i++) {
            vector[i] = vector1[i] - vector2[i];
          }
          return vector;
        },
     
        vectorAdd: function(vector1, vector2) {
          var vector = [];
          for (var i=0; i<vector1.length; i++) {
            vector[i] = vector1[i] + vector2[i];
          }
          return vector;
        },
     
        vectorMult: function(vector, num) {
          var result = [];
          for (var i=0; i<vector.length; i++) {
            result[i] = vector[i] * num;
          }
          return result;
        },
     
        vectorLength: function(vector) {
          var result = 0;
          for (var i=0; i<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 );
    Last edited by Pullo; Sep 23, 2013 at 02:54. Reason: Added code tags

  4. #4
    SitePoint Enthusiast
    Join Date
    Sep 2013
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi again.

    This is exactly the case.

    Is it possible to set it in JVectorMaps?

    Thanks.

  5. #5
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    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.

  6. #6
    SitePoint Enthusiast
    Join Date
    Sep 2013
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    No, the buttons on the mapael are not links, but vector images. I mean the button "MA" is part of the Massachusetts region.

  7. #7
    SitePoint Enthusiast
    Join Date
    Sep 2013
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by myty View Post
    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.
    This is exactly what I am looking for.

    You know some example or demo?

  8. #8
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    If you want a demo, please build a jsfiddle or jsbin and I'll modify that code.

  9. #9
    SitePoint Enthusiast
    Join Date
    Sep 2013
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by myty View Post
    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.

  10. #10
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,358
    Mentioned
    179 Post(s)
    Tagged
    9 Thread(s)
    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.

  11. #11
    SitePoint Enthusiast
    Join Date
    Sep 2013
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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:

    Code:
    ...
    
      $.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))

  12. #12
    SitePoint Enthusiast
    Join Date
    Sep 2013
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What about a hover to call the selected region.



    Code:
    <a class="canada" href="canada">Canada</a>
    And then:

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


    [CODE]
    $(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',
    Code:
    );
    });

  13. #13
    SitePoint Enthusiast
    Join Date
    Sep 2013
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What about using a on hover function to trigger the setHovered(true) for a given area according to the code above.


    Code:
      <a class="canada" href="canada">Canada</a>
    Code:
            <script>
             $(document).ready(function(){
                $('a.canada').hover(function(){
                   $(this).................................
    
             });
          </script>

  14. #14
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    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:
    Code:
    mapObj.markers[i].element.setHovered(true)
    where i was the result of a function I wrote:
    Code:
    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:
    Code:
    $('#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.

  15. #15
    The CSS Clinic is open silver trophybronze trophy
    Paul O'B's Avatar
    Join Date
    Jan 2003
    Location
    Hampshire UK
    Posts
    39,877
    Mentioned
    160 Post(s)
    Tagged
    4 Thread(s)
    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.

  16. #16
    SitePoint Enthusiast
    Join Date
    Sep 2013
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Paul O'B View Post
    This is probably no help whatsoever but[URL="http://www.pmob.co.uk/map/tests/my-test.htm"].
    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?

  17. #17
    The CSS Clinic is open silver trophybronze trophy
    Paul O'B's Avatar
    Join Date
    Jan 2003
    Location
    Hampshire UK
    Posts
    39,877
    Mentioned
    160 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by andresb View Post
    I have downloaded the url but does not work in local.
    Hi,

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

    Code:
    <!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:

    Code:
    <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:

    Code:
     $('#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:

    Code:
     $('#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.
    Attached Files Attached Files

  18. #18
    SitePoint Enthusiast
    Join Date
    Sep 2013
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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.

  19. #19
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    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?!

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

  20. #20
    The CSS Clinic is open silver trophybronze trophy
    Paul O'B's Avatar
    Join Date
    Jan 2003
    Location
    Hampshire UK
    Posts
    39,877
    Mentioned
    160 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by myty View Post
    I mean, Paul, really?!
    lol - yes I agree with all that you say.

    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.
    Code:
        $('#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

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

  21. #21
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    +10 for effort! If the OP is not able to produce a playground until then, I may have to, tomorrow.

    A better version, v1.x, is available: http://jvectormap.com/documentation/.../jvm-worldmap/

    The API is improved greatly:
    regionStyle Object Set the styles for the map's regions. Each region or marker has four states: initial (default state), hover (when the mouse cursor is over the region or marker), selected (when region or marker is selected), selectedHover (when the mouse cursor is over the region or marker and it's selected simultaneously). Styles could be set for each of this states. Default value for that parameter is:

    {
    initial: {
    fill: 'white',
    "fill-opacity": 1,
    stroke: 'none',
    "stroke-width": 0,
    "stroke-opacity": 1
    },
    hover: {
    "fill-opacity": 0.8
    },
    selected: {
    fill: 'yellow'
    },
    selectedHover: {
    }
    }
    Being an object, it's only a matter of setting its properties, like the stackoverflow post explains. But, even like that, we're not talking about a one-off setting, we're still accounting for a general style.

  22. #22
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    As promised, I've put together a jsfiddle: http://jsfiddle.net/3xZ28/117/

    I've also posted an answer on SO: http://stackoverflow.com/a/18975740/1324929

    The html is kept clean, no need for id values in the list of countries.
    The link text has to match the country's international name.
    The findRegion function uses this text to find the key for the region property/object and return it.
    Then, the key is used to set the region hover on and off: mapObj.regions[cntrycode].element.setHovered(true/false).

    Any more explaining needed, just ask.

  23. #23
    The CSS Clinic is open silver trophybronze trophy
    Paul O'B's Avatar
    Join Date
    Jan 2003
    Location
    Hampshire UK
    Posts
    39,877
    Mentioned
    160 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by myty View Post
    As promised, I've put together a jsfiddle: http://jsfiddle.net/3xZ28/117/
    Very nice

    The html is kept clean, no need for id values in the list of countries.
    The link text has to match the country's international name.
    That's very clever and not something I would have been able to work out at my current level.

    Any more explaining needed, just ask.
    Why the use of first-child here:

    Code:
    $('#countries').on('mouseover mouseout', 'a:first-child'
    Or is that just in case more sibling anchors were added later?

    The only thing missing that I notice the OP asked for is for the country name to get highlighted when the map is hovered. I assume you would need to match the country name with the text in the html list (the reverse procedure of what you have already done) but that is a little beyond me.

    Even though this isn't my thread thanks for taking the time to produce this and hope that it was spurred on by my rubbish attempt

  24. #24
    Non-Member
    Join Date
    Feb 2012
    Posts
    892
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    Thanks Paul.

    About the :first-child. Yes, in my markers project I had grouped regions, something like countries and then counties. Hovering over the first <a> would highlight the entire country, hovering over the next would highlight only the county. But for this example, :first-child is not relevant and could be omitted.

    Controlling the reverse it's pretty easy, using the jvectormap's exposed API this time, onRegionOver and onRegionOut, even easier since there is no need to look for country code, country name is already available for the hovered region. As far as I'm concerned, since jvectormap displays region labels on hover, it's not required, but if the OP really wants it and can't get it, I will do this also.

    And yours is an honest attempt, so please stop diminishing your effort!

  25. #25
    The CSS Clinic is open silver trophybronze trophy
    Paul O'B's Avatar
    Join Date
    Jan 2003
    Location
    Hampshire UK
    Posts
    39,877
    Mentioned
    160 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by myty View Post
    Thanks Paul.

    About the :first-child. Yes, in my markers project I had grouped regions, something like countries and then counties. Hovering over the first <a> would highlight the entire country, hovering over the next would highlight only the county. But for this example, :first-child is not relevant and could be omitted.
    Ok thanks for the clarification.

    Controlling the reverse it's pretty easy, using the jvectormap's exposed API this time, onRegionOver and onRegionOut, even easier since there is no need to look for country code, country name is already available for the hovered region. As far as I'm concerned, since jvectormap displays region labels on hover, it's not required, but if the OP really wants it and can't get it, I will do this also.
    Yes I did think duplicating it was a little unnecessary as the labels are already there on the map.

    I hope the OP returns and sees the great work you've put into this.

    And yours is an honest attempt, so please stop diminishing your effort!
    Thanks, I don't feel so bad now. I'm at that stage with js/jquery where a little knowledge is a dangerous thing (I must get my nose out of CSS a bit more often like this and learn something new.)


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •