PageSourceSearch

https://www.inpa.gov.it/wp-content/plugins/dro-dashboard/modules/dro-mappa/assets/js/jvectormap/map.js

js inpa.gov.it collected 2026-09-24 10:27:24 UTC 41,058 bytes, 1,196 lines download raw bytes

1/**
2 * Creates map, draws paths, binds events.
3 * @constructor
4 * @param {Object} params Parameters to initialize map with.
5 * @param {String} params.map Name of the map in the format <code>territory_proj_lang</code> where <code>territory</code> is a unique code or name of the territory which the map represents (ISO 3166 standard is used where possible), <code>proj</code> is a name of projection used to generate representation of the map on the plane (projections are named according to the conventions of proj4 utility) and <code>lang</code> is a code of the language, used for the names of regions.
6 * @param {String} params.backgroundColor Background color of the map in CSS format.
7 * @param {Boolean} params.zoomOnScroll When set to true map could be zoomed using mouse scroll. Default value is <code>true</code>.
8 * @param {Number} params.zoomOnScrollSpeed Mouse scroll speed. Number from 1 to 10. Default value is <code>3</code>.
9 * @param {Boolean} params.panOnDrag When set to true, the map pans when being dragged. Default value is <code>true</code>.
10 * @param {Number} params.zoomMax Indicates the maximum zoom ratio which could be reached zooming the map. Default value is <code>8</code>.
11 * @param {Number} params.zoomMin Indicates the minimum zoom ratio which could be reached zooming the map. Default value is <code>1</code>.
12 * @param {Number} params.zoomStep Indicates the multiplier used to zoom map with +/- buttons. Default value is <code>1.6</code>.
13 * @param {Boolean} params.zoomAnimate Indicates whether or not to animate changing of map zoom with zoom buttons.
14 * @param {Boolean} params.regionsSelectable When set to true regions of the map could be selected. Default value is <code>false</code>.
15 * @param {Boolean} params.regionsSelectableOne Allow only one region to be selected at the moment. Default value is <code>false</code>.
16 * @param {Boolean} params.markersSelectable When set to true markers on the map could be selected. Default value is <code>false</code>.
17 * @param {Boolean} params.markersSelectableOne Allow only one marker to be selected at the moment. Default value is <code>false</code>.
18 * @param {Object} params.regionStyle Set the styles for the map's regions. Each region or marker has four states: <code>initial</code> (default state), <code>hover</code>
18 (when the mouse cursor is over the region or marker), <code>selected</code> (when region or marker is selected), <code>selectedHover</code> (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:
19<pre>{
20  initial: {
21    fill: 'white',
22    "fill-opacity": 1,
23    stroke: 'none',
24    "stroke-width": 0,
25    "stroke-opacity": 1
26  },
27  hover: {
28    "fill-opacity": 0.8,
29    cursor: 'pointer'
30  },
31  selected: {
32    fill: 'yellow'
33  },
34  selectedHover: {
35  }
36}</pre>
37* @param {Object} params.regionLabelStyle Set the styles for the regions' labels. Each region or marker has four states: <code>initial</code> (default state), <code>hover</code> (when the mouse cursor is over the region or marker), <code>selected</code> (when region or marker is selected), <code>selectedHover</code> (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:
38<pre>{
39  initial: {
40    'font-family': 'Verdana',
41    'font-size': '12',
42    'font-weight': 'bold',
43    cursor: 'default',
44    fill: 'black'
45  },
46  hover: {
47    cursor: 'pointer'
48  }
49}</pre>
50 * @param {Object} params.markerStyle Set the styles for the map's markers. Any parameter suitable for <code>regionStyle</code> could be used as well as numeric parameter <code>r</code> to set the marker's radius. Default value for that parameter is:
51<pre>{
52  initial: {
53    fill: 'grey',
54    stroke: '#505050',
55    "fill-opacity": 1,
56    "stroke-width": 1,
57    "stroke-opacity": 1,
58    r: 5
59  },
60  hover: {
61    stroke: 'black',
62    "stroke-width": 2,
63    cursor: 'pointer'
64  },
65  selected: {
66    fill: 'blue'
67  },
68  selectedHover: {
69  }
70}</pre>
71You can also use <code>image</code> style attribute for markers. By default marker images are centered with the target point on map. To supply a custom offset please use the following format:
72<pre>{
73  url: 'image/url',
74  offset: [-10, 5]
75}</pre>
76 * @param {Object} params.markerLabelStyle Set the styles for the markers' labels. Default value for that parameter is:
77<pre>{
78  initial: {
79    'font-family': 'Verdana',
80    'font-size': '12',
81    'font-weight': 'bold',
82    cursor: 'default',
83    fill: 'black'
84  },
85  hover: {
86    cursor: 'pointer'
87  }
88}</pre>
89 * @param {Object|Array} params.markers Set of markers to add to the map during initialization. In case of array is provided, codes of markers will be set as string representations of array indexes. Each marker is represented by <code>latLng</code> (array of two numeric values), <code>name</code> (string which will be show on marker's tip) and any marker styles.
90 * @param {Object} params.series Object with two keys: <code>markers</code> and <code>regions</code>. Each of which is an array of series configs to be applied to the respective map elements. See <a href="jvm.DataSeries.html">DataSeries</a> description for a list of parameters available.
91 * @param {Object|String} params.focusOn This parameter sets the initial position and scale of the map viewport. See <code>setFocus</code> docuemntation for possible parameters.
92 * @param {Object} params.labels Defines parameters for rendering static labels. Object could contain two keys: <code>regions</code> and <code>markers</code>. Each key value defines configuration object with the following possible options:
93<ul>
94  <li><code>render {Function}</code> - defines method for converting region code or marker index to actual label value.</li>
95  <li><code>offsets {Object|Function}</code> - provides method or object which could be used to define label offset by region code or marker index.</li>
96</ul>
97<b>Plase note: static labels feature is not supported in Internet Explorer 8 and below.</b>
98 * @param {Array|Object|String} params.selectedRegions Set initially selected regions.
99 * @param {Array|Object|String} params.selectedMarkers Set initially selected markers.
100 * @param {Function} params.onRegionTipShow <code>(Event e, Object tip, String code)</code> Will be called right before the region tip is going to be shown.
101 * @param {Function} params.onRegionOver <code>(Event e, String code)</code> Will be called on region mouse over event.
102 * @param {Function} params.onRegionOut <code>(Event e, String code)</code> Will be called on region mouse out event.
103 * @param {Function} params.onRegionClick <code>(Event e, String code)</code> Will be called on region click event.
104 * @param {Function} params.onRegionSelected <code>(Event e, String code, Boolean isSelected, Array selectedRegions)</code> Will be called when region is (de)selected. <code>isSelected</code> parameter of the callback indicates whether region is selected or not. <code>selectedRegions</code>
104 contains codes of all currently selected regions.
105 * @param {Function} params.onMarkerTipShow <code>(Event e, Object tip, String code)</code> Will be called right before the marker tip is going to be shown.
106 * @param {Function} params.onMarkerOver <code>(Event e, String code)</code> Will be called on marker mouse over event.
107 * @param {Function} params.onMarkerOut <code>(Event e, String code)</code> Will be called on marker mouse out event.
108 * @param {Function} params.onMarkerClick <code>(Event e, String code)</code> Will be called on marker click event.
109 * @param {Function} params.onMarkerSelected <code>(Event e, String code, Boolean isSelected, Array selectedMarkers)</code> Will be called when marker is (de)selected. <code>isSelected</code> parameter of the callback indicates whether marker is selected or not. <code>selectedMarkers</code> contains codes of all currently selected markers.
110 * @param {Function} params.onViewportChange <code>(Event e, Number scale)</code> Triggered when the map's viewport is changed (map was panned or zoomed).
111 */
112jvm.Map = function(params) {
113  var map = this,
114      e;
115
116  this.params = jvm.$.extend(true, {}, jvm.Map.defaultParams, params);
117
118  if (!jvm.Map.maps[this.params.map]) {
119    throw new Error('Attempt to use map which was not loaded: '+this.params.map);
120  }
121
122  this.mapData = jvm.Map.maps[this.params.map];
123  this.markers = {};
124  this.regions = {};
125  this.regionsColors = {};
126  this.regionsData = {};
127
128  this.container = jvm.$('<div>').addClass('jvectormap-container');
129  if (this.params.container) {
130    this.params.container.append( this.container );
131  }
132  this.container.data('mapObject', this);
133
134  this.defaultWidth = this.mapData.width;
135  this.defaultHeight = this.mapData.height;
136
137  this.setBackgroundColor(this.params.backgroundColor);
138
139  this.onResize = function(){
140    map.updateSize();
141  }
142  jvm.$(window).resize(this.onResize);
143
144  for (e in jvm.Map.apiEvents) {
145    if (this.params[e]) {
146      this.container.bind(jvm.Map.apiEvents[e]+'.jvectormap', this.params[e]);
147    }
148  }
149
150  this.canvas = new jvm.VectorCanvas(this.container[0], this.width, this.height);
151
152  if (this.params.bindTouchEvents) {
153    if (('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch)) {
154      this.bindContainerTouchEvents();
155    } else if (window.MSGesture) {
156      this.bindContainerPointerEvents();
157    }
158  }
159  this.bindContainerEvents();
160  this.bindElementEvents();
161  this.createTip();
162  if (this.params.zoomButtons) {
163    this.bindZoomButtons();
164  }
165
166  this.createRegions();
167  this.createMarkers(this.params.markers || {});
168
169  this.updateSize();
170
171  if (this.params.focusOn) {
172    if (typeof this.params.focusOn === 'string') {
173      this.params.focusOn = {region: this.params.focusOn};
174    } else if (jvm.$.isArray(this.params.focusOn)) {
175      this.params.focusOn = {regions: this.params.focusOn};
176    }
177    this.setFocus(this.params.focusOn);
178  }
179
180  if (this.params.selectedRegions) {
181    this.setSelectedRegions(this.params.selectedRegions);
182  }
183  if (this.params.selectedMarkers) {
184    this.setSelectedMarkers(this.params.selectedMarkers);
185  }
186
187  this.legendCntHorizontal = jvm.$('<div/>').addClass('jvectormap-legend-cnt jvectormap-legend-cnt-h');
188  this.legendCntVertical = jvm.$('<div/>').addClass('jvectormap-legend-cnt jvectormap-legend-cnt-v');
189  this.container.append(this.legendCntHorizontal);
190  this.container.append(this.legendCntVertical);
191
192  if (this.params.series) {
193    this.createSeries();
194  }
195};
196
197jvm.Map.prototype = {
198  transX: 0,
199  transY: 0,
200  scale: 1,
201  baseTransX: 0,
202  baseTransY: 0,
203  baseScale: 1,
204
205  width: 0,
206  height: 0,
207
208  /**
209   * Set background color of the map.
210   * @param {String}
210 backgroundColor Background color in CSS format.
211   */
212  setBackgroundColor: function(backgroundColor) {
213    this.container.css('background-color', backgroundColor);
214  },
215
216  resize: function() {
217    var curBaseScale = this.baseScale;
218    if (this.width / this.height > this.defaultWidth / this.defaultHeight) {
219      this.baseScale = this.height / this.defaultHeight;
220      this.baseTransX = Math.abs(this.width - this.defaultWidth * this.baseScale) / (2 * this.baseScale);
221    } else {
222      this.baseScale = this.width / this.defaultWidth;
223      this.baseTransY = Math.abs(this.height - this.defaultHeight * this.baseScale) / (2 * this.baseScale);
224    }
225    this.scale *= this.baseScale / curBaseScale;
226    this.transX *= this.baseScale / curBaseScale;
227    this.transY *= this.baseScale / curBaseScale;
228  },
229
230  /**
231   * Synchronize the size of the map with the size of the container. Suitable in situations where the size of the container is changed programmatically or container is shown after it became visible.
232   */
233  updateSize: function(){
234    this.width = this.container.width();
235    this.height = this.container.height();
236    this.resize();
237    this.canvas.setSize(this.width, this.height);
238    this.applyTransform();
239  },
240
241  /**
242   * Reset all the series and show the map with the initial zoom.
243   */
244  reset: function() {
245    var key,
246        i;
247
248    for (key in this.series) {
249      for (i = 0; i < this.series[key].length; i++) {
250        this.series[key][i].clear();
251      }
252    }
253    this.scale = this.baseScale;
254    this.transX = this.baseTransX;
255    this.transY = this.baseTransY;
256    this.applyTransform();
257  },
258
259  applyTransform: function() {
260    var maxTransX,
261        maxTransY,
262        minTransX,
263        minTransY;
264
265    if (this.defaultWidth * this.scale <= this.width) {
266      maxTransX = (this.width - this.defaultWidth * this.scale) / (2 * this.scale);
267      minTransX = (this.width - this.defaultWidth * this.scale) / (2 * this.scale);
268    } else {
269      maxTransX = 0;
270      minTransX = (this.width - this.defaultWidth * this.scale) / this.scale;
271    }
272
273    if (this.defaultHeight * this.scale <= this.height) {
274      maxTransY = (this.height - this.defaultHeight * this.scale) / (2 * this.scale);
275      minTransY = (this.height - this.defaultHeight * this.scale) / (2 * this.scale);
276    } else {
277      maxTransY = 0;
278      minTransY = (this.height - this.defaultHeight * this.scale) / this.scale;
279    }
280
281    if (this.transY > maxTransY) {
282      this.transY = maxTransY;
283    } else if (this.transY < minTransY) {
284      this.transY = minTransY;
285    }
286    if (this.transX > maxTransX) {
287      this.transX = maxTransX;
288    } else if (this.transX < minTransX) {
289      this.transX = minTransX;
290    }
291
292    this.canvas.applyTransformParams(this.scale, this.transX, this.transY);
293
294    if (this.markers) {
295      this.repositionMarkers();
296    }
297
298    this.repositionLabels();
299
300    this.container.trigger('viewportChange', [this.scale/this.baseScale, this.transX, this.transY]);
301  },
302
303  bindContainerEvents: function(){
304    var mouseDown = false,
305        oldPageX,
306        oldPageY,
307        map = this;
308
309    if (this.params.panOnDrag) {
310      this.container.mousemove(function(e){
311        if (mouseDown) {
312          map.transX -= (oldPageX - e.pageX) / map.scale;
313          map.transY -= (oldPageY - e.pageY) / map.scale;
314
315          map.applyTransform();
316
317          oldPageX = e.pageX;
318          oldPageY = e.pageY;
319        }
320        return false;
321      }).mousedown(function(e){
322        mouseDown = true;
323        oldPageX = e.pageX;
324        oldPageY = e.pageY;
325        return false;
326      });
327
328      this.onContainerMouseUp = function(){
329        mouseDown = false;
330      };
331      jvm.$('body').mouseup(this.onContainerMouseUp);
332    }
333
334    // if (this.params.zoomOnScroll) {
335    //   this.container.mousewheel(function(event, delta, deltaX, deltaY) {
336    //     var offset = jvm.$(map.container).offset(),
337    //         centerX = event.pageX - offset.left,
338    //         centerY = event.pageY - offset.top,
339    //         zoomStep = Math.pow(1 + map.params.zoomOnScrollSpeed / 1000, event.deltaFactor * event.deltaY);
340    //
341    //     map.tip.hide();
342    //
343    //     map.setScale(map.scale * zoomStep, centerX, centerY);
344    //     event.preventDefault();
345    //   });
346    // }
347  },
348
349  bindContainerTouchEvents: function(){
350    var touchStartScale,
351        touchStartDistance,
352        map = this,
353        touchX,
354        touchY,
355        centerTouchX,
356        centerTouchY,
357        lastTouchesLength,
358        handleTouchEvent = function(e){
359          var touches = e.originalEvent.touches,
360              offset,
361              scale,
362              transXOld,
363              transYOld;
364
365          if (e.type == 'touchstart') {
366            lastTouchesLength = 0;
367          }
368
369          if (touches.length == 1) {
370            if (lastTouchesLength == 1) {
371              transXOld = map.transX;
372              transYOld = map.transY;
373              map.transX -= (touchX - touches[0].pageX) / map.scale;
374              map.transY -= (touchY - touches[0].pageY) / map.scale;
375              map.applyTransform();
376              map.tip.hide();
377              if (transXOld != map.transX || transYOld != map.transY) {
378                e.preventDefault();
379              }
380            }
381            touchX = touches[0].pageX;
382            touchY = touches[0].pageY;
383          } else if (touches.length == 2) {
384            if (lastTouchesLength == 2) {
385              scale = Math.sqrt(
386                Math.pow(touches[0].pageX - touches[1].pageX, 2) +
387                Math.pow(touches[0].pageY - touches[1].pageY, 2)
388              ) / touchStartDistance;
389              map.setScale(
390                touchStartScale * scale,
391                centerTouchX,
392                centerTouchY
393              )
394              map.tip.hide();
395              e.preventDefault();
396            } else {
397              offset = jvm.$(map.container).offset();
398              if (touches[0].pageX > touches[1].pageX) {
399                centerTouchX = touches[1].pageX + (touches[0].pageX - touches[1].pageX) / 2;
400              } else {
401                centerTouchX = touches[0].pageX + (touches[1].pageX - touches[0].pageX) / 2;
402              }
403              if (touches[0].pageY > touches[1].pageY) {
404                centerTouchY = touches[1].pageY + (touches[0].pageY - touches[1].pageY) / 2;
405              } else {
406                centerTouchY = touches[0].pageY + (touches[1].pageY - touches[0].pageY) / 2;
407              }
408              centerTouchX -= offset.left;
409              centerTouchY -= offset.top;
410              touchStartScale = map.scale;
411              touchStartDistance = Math.sqrt(
412                Math.pow(touches[0].pageX - touches[1].pageX, 2) +
413                Math.pow(touches[0].pageY - touches[1].pageY, 2)
414              );
415            }
416          }
417
418          lastTouchesLength = touches.length;
419        };
420
421    jvm.$(this.container).bind('touchstart', handleTouchEvent);
422    jvm.$(this.container).bind('touchmove', handleTouchEvent);
423  },
424
425  bindContainerPointerEvents: function(){
426    var map = this,
427        gesture = new MSGesture(),
428        element = this.container[0],
429        handlePointerDownEvent = function(e){
430          gesture.addPointer(e.pointerId);
431        },
432        handleGestureEvent = function(e){
433          var offset,
434              scale,
435              transXOld,
436              transYOld;
437
438          if (e.translationX != 0 || e.translationY != 0) {
439            transXOld = map.transX;
440            transYOld = map.transY;
441            map.transX += e.translationX / map.scale;
442            map.transY += e.translationY / map.scale;
443            map.applyTransform();
444            map.tip.hide();
445            if (transXOld != map.transX || transYOld != map.transY) {
446              e.preventDefault();
447            }
448          }
449          if (e.scale != 1) {
450            map.setScale(
451              map.scale * e.scale,
452              e.offsetX,
453              e.offsetY
454            )
455            map.tip.hide();
456            e.preventDefault();
457          }
458        };
459
460    gesture.target = element;
461    element.addEventListener("MSGestureChange", handleGestureEvent, false);
462    element.addEventListener("pointerdown", handlePointerDownEvent, false);
463  },
464
465  bindElementEvents: function(){
466    var map = this,
467        pageX,
468        pageY,
469        mouseMoved;
470
471    this.container.mousemove(function(e){
472      if (Math.abs(pageX - e.pageX) + Math.abs(pageY - e.pageY) > 2) {
473        mouseMoved = true;
474      }
475    });
476
477    /* Can not use common class selectors here because of the bug in jQuery
478       SVG handling, use with caution. */
479    this.container.delegate("[class~='jvectormap-element']", 'mouseover mouseout', function(e){
480      var baseVal = jvm.$(this).attr('class').baseVal || jvm.$(this).attr('class'),
481          type = baseVal.indexOf('jvectormap-region') === -1 ? 'marker' : 'region',
482          code = type == 'region' ? jvm.$(this).attr('data-code') : jvm.$(this).attr('data-index'),
483          element = type == 'region' ? map.regions[code].element : map.markers[code].element,
484          tipText = type == 'region' ? map.mapData.paths[code].name : (map.markers[code].config.name || ''),
485          tipShowEvent = jvm.$.Event(type+'TipShow.jvectormap'),
486          overEvent = jvm.$.Event(type+'Over.jvectormap');
487
488      if (e.type == 'mouseover') {
489        map.container.trigger(overEvent, [code]);
490        if (!overEvent.isDefaultPrevented()) {
491          element.setHovered(true);
492        }
493
494        map.tip.text(tipText);
495        map.container.trigger(tipShowEvent, [map.tip, code]);
496        if (!tipShowEvent.isDefaultPrevented()) {
497          map.tip.show();
498          map.tipWidth = map.tip.width();
499          map.tipHeight = map.tip.height();
500        }
501      } else {
502        element.setHovered(false);
503        map.tip.hide();
504        map.container.trigger(type+'Out.jvectormap', [code]);
505      }
506    });
507
508    /* Can not use common class selectors here because of the bug in jQuery
509       SVG handling, use with caution. */
510    this.container.delegate("[class~='jvectormap-element']", 'mousedown', function(e){
511      pageX = e.pageX;
512      pageY = e.pageY;
513      mouseMoved = false;
514    });
515
516    /* Can not use common class selectors here because of the bug in jQuery
517       SVG handling, use with caution. */
518    this.container.delegate("[class~='jvectormap-element']", 'mouseup', function(){
519      var baseVal = jvm.$(this).attr('class').baseVal ? jvm.$(this).attr('class').baseVal : jvm.$(this).attr('class'),
520          type = baseVal.indexOf('jvectormap-region') === -1 ? 'marker' : 'region',
521          code = type == 'region' ? jvm.$(this).attr('data-code') : jvm.$(this).attr('data-index'),
522          clickEvent = jvm.$.Event(type+'Click.jvectormap'),
523          element = type == 'region' ? map.regions[code].element : map.markers[code].element;
524
525      if (!mouseMoved) {
526        map.container.trigger(clickEvent, [code]);
527        if ((type === 'region' && map.params.regionsSelectable) || (type === 'marker' && map.params.markersSelectable)) {
528          if (!clickEvent.isDefaultPrevented()) {
529            if (map.params[type+'sSelectableOne']) {
530              map.clearSelected(type+'s');
531            }
532            element.setSelected(!element.isSelected);
533          }
534        }
535      }
536    });
537  },
538
539  bindZoomButtons: function() {
540    var map = this;
541
542    jvm.$('<div/>').addClass('jvectormap-zoomin').text('+').appendTo(this.container);
543    jvm.$('<div/>').addClass('jvectormap-zoomout').html('&#x2212;').appendTo(this.container);
544
545    this.container.find('.jvectormap-zoomin').click(function(){
546      map.setScale(map.scale * map.params.zoomStep, map.width / 2, map.height / 2, false, map.params.zoomAnimate);
547    });
548    this.container.find('.jvectormap-zoomout').click(function(){
549      map.setScale(map.scale / map.params.zoomStep, map.width / 2, map.height / 2, false, map.params.zoomAnimate);
550    });
551  },
552
553  createTip: function(){
554    var map = this;
555
556    this.tip = jvm.$('<div/>').addClass('jvectormap-tip').appendTo(jvm.$('body'));
557
558    this.container.mousemove(function(e){
559      var left = e.pageX-15-map.tipWidth,
560          top = e.pageY-15-map.tipHeight;
561
562      if (left < 5) {
563        left = e.pageX + 15;
564      }
565      if (top < 5) {
566        top = e.pageY + 15;
567      }
568
569      map.tip.css({
570        left: left,
571        top: top
572      });
573    });
574  },
575
576  setScale: function(scale, anchorX, anchorY, isCentered, animate) {
577    var viewportChangeEvent = jvm.$.Event('zoom.jvectormap'),
578        interval,
579        that = this,
580        i = 0,
581        count = Math.abs(Math.round((scale - this.scale) * 60 / Math.max(scale, this.scale))),
582        scaleStart,
583        scaleDiff,
584        transXStart,
585        transXDiff,
586        transYStart,
587        transYDiff,
588        transX,
589        transY,
590        deferred = new jvm.$.Deferred();
591
592    if (scale > this.params.zoomMax * this.baseScale) {
593      scale = this.params.zoomMax * this.baseScale;
594    } else if (scale < this.params.zoomMin * this.baseScale) {
595      scale = this.params.zoomMin * this.baseScale;
596    }
597
598    if (typeof anchorX != 'undefined' && typeof anchorY != 'undefined') {
599      zoomStep = scale / this.scale;
600      if (isCentered) {
601        transX = anchorX + this.defaultWidth * (this.width / (this.defaultWidth * scale)) / 2;
602        transY = anchorY + this.defaultHeight * (this.height / (this.defaultHeight * scale)) / 2;
603      } else {
604        transX = this.transX - (zoomStep - 1) / scale * anchorX;
605        transY = this.transY - (zoomStep - 1) / scale * anchorY;
606      }
607    }
608
609    if (animate && count > 0)  {
610      scaleStart = this.scale;
611      scaleDiff = (scale - scaleStart) / count;
612      transXStart = this.transX * this.scale;
613      transYStart = this.transY * this.scale;
614      transXDiff = (transX * scale - transXStart) / count;
615      transYDiff = (transY * scale - transYStart) / count;
616      interval = setInterval(function(){
617        i += 1;
618        that.scale = scaleStart + scaleDiff * i;
619        that.transX = (transXStart + transXDiff * i) / that.scale;
620        that.transY = (transYStart + transYDiff * i) / that.scale;
621        that.applyTransform();
622        if (i == count) {
623          clearInterval(interval);
624          that.container.trigger(viewportChangeEvent, [scale/that.baseScale]);
625          deferred.resolve();
626        }
627      }, 10);
628    } else {
629      this.transX = transX;
630      this.transY = transY;
631      this.scale = scale;
632      this.applyTransform();
633      this.container.trigger(viewportChangeEvent, [scale/this.baseScale]);
634      deferred.resolve();
635    }
636
637    return deferred;
638  },
639
640  /**
641   * Set the map's viewport to the specific point and set zoom of the map to the specific level. Point and zoom level could be defined in two ways: using the code of some region to focus on or a central point and zoom level as numbers.
642   * @param This method takes a configuration object as the single argument. The options passed to it are the following:
643   * @param {Array} params.regions Array of region codes to zoom to.
644   * @param {String} params.region Region code to zoom to.
645   * @param {Number} params.scale Map scale to set.
646   * @param {Number} params.lat Latitude to set viewport to.
647   * @param {Number} params.lng Longitude to set viewport to.
648   * @param {Number} params.x Number from 0 to 1 specifying the horizontal coordinate of the central point of the viewport.
649   * @param {Number} params.y Number from 0 to 1 specifying the vertical coordinate of the central point of the viewport.
650   * @param {Boolean} params.animate Indicates whether or not to animate the scale change and transition.
651   */
652  setFocus: function(config){
653    var bbox,
654        itemBbox,
655        newBbox,
656        codes,
657        i,
658        point;
659
660    config = config || {};
661
662    if (config.region) {
663      codes = [config.region];
664    } else if (config.regions) {
665      codes = config.regions;
666    }
667
668    if (codes) {
669      for (i = 0; i < codes.length; i++) {
670        if (this.regions[codes[i]]) {
671          itemBbox = this.regions[codes[i]].element.shape.getBBox();
672          if (itemBbox) {
673            if (typeof bbox == 'undefined') {
674              bbox = itemBbox;
675            } else {
676              newBbox = {
677                x: Math.min(bbox.x, itemBbox.x),
678                y: Math.min(bbox.y, itemBbox.y),
679                width: Math.max(bbox.x + bbox.width, itemBbox.x + itemBbox.width) - Math.min(bbox.x, itemBbox.x),
680                height: Math.max(bbox.y + bbox.height, itemBbox.y + itemBbox.height) - Math.min(bbox.y, itemBbox.y)
681              }
682              bbox = newBbox;
683            }
684          }
685        }
686      }
687      return this.setScale(
688        Math.min(this.width / bbox.width, this.height / bbox.height),
689        - (bbox.x + bbox.width / 2),
690        - (bbox.y + bbox.height / 2),
691        true,
692        config.animate
693      );
694    } else {
695      if (config.lat !== undefined && config.lng !== undefined) {
696        point = this.latLngToPoint(config.lat, config.lng);
697        config.x = this.transX - point.x / this.scale;
698        config.y = this.transY - point.y / this.scale;
699      } else if (config.x && config.y) {
700        config.x *= -this.defaultWidth;
701        config.y *= -this.defaultHeight;
702      }
703      return this.setScale(config.scale * this.baseScale, config.x, config.y, true, config.animate);
704    }
705  },
706
707  getSelected: function(type){
708    var key,
709        selected = [];
710
711    for (key in this[type]) {
712      if (this[type][key].element.isSelected) {
713        selected.push(key);
714      }
715    }
716    return selected;
717  },
718
719  /**
720   * Return the codes of currently selected regions.
721   * @returns {Array}
722   */
723  getSelectedRegions: function(){
724    return this.getSelected('regions');
725  },
726
727  /**
728   * Return the codes of currently selected markers.
729   * @returns {Array}
730   */
731  getSelectedMarkers: function(){
732    return this.getSelected('markers');
733  },
734
735  setSelected: function(type, keys){
736    var i;
737
738    if (typeof keys != 'object') {
739      keys = [keys];
740    }
741
742    if (jvm.$.isArray(keys)) {
743      for (i = 0; i < keys.length; i++) {
744        this[type][keys[i]].element.setSelected(true);
745      }
746    } else {
747      for (i in keys) {
748        this[type][i].element.setSelected(!!keys[i]);
749      }
750    }
751  },
752
753  /**
754   * Set or remove selected state for the regions.
755   * @param {String|Array|Object} keys If <code>String</code> or <code>Array</code> the region(s) with the corresponding code(s) will be selected. If <code>Object</code> was provided its keys are  codes of regions, state of which should be changed. Selected state will be set if value is true, removed otherwise.
756   */
757  setSelectedRegions: function(keys){
758    this.setSelected('regions', keys);
759  },
760
761  /**
762   * Set or remove selected state for the markers.
763   * @param {String|Array|Object} keys If <code>String</code> or <code>Array</code> the marker(s) with the corresponding code(s) will be selected. If <code>Object</code> was provided its keys are  codes of markers, state of which should be changed. Selected state will be set if value is true, removed otherwise.
764   */
765  setSelectedMarkers: function(keys){
766    this.setSelected('markers', keys);
767  },
768
769  clearSelected: function(type){
770    var select = {},
771        selected = this.getSelected(type),
772        i;
773
774    for (i = 0; i < selected.length; i++) {
775      select[selected[i]] = false;
776    };
777
778    this.setSelected(type, select);
779  },
780
781  /**
782   * Remove the selected state from all the currently selected regions.
783   */
784  clearSelectedRegions: function(){
785    this.clearSelected('regions');
786  },
787
788  /**
789   * Remove the selected state from all the currently selected markers.
790   */
791  clearSelectedMarkers: function(){
792    this.clearSelected('markers');
793  },
794
795  /**
796   * Return the instance of Map. Useful when instantiated as a jQuery plug-in.
797   * @returns {Map}
798   */
799  getMapObject: function(){
800    return this;
801  },
802
803  /**
804   * Return the name of the region by region code.
805   * @returns {String}
806   */
807  getRegionName: function(code){
808    return this.mapData.paths[code].name;
809  },
810
811  createRegions: function(){
812    var key,
813        region,
814        map = this;
815
816    this.regionLabelsGroup = this.regionLabelsGroup || this.canvas.addGroup();
817
818    for (key in this.mapData.paths) {
819      region = new jvm.Region({
820        map: this,
821        path: this.mapData.paths[key].path,
822        code: key,
823        style: jvm.$.extend(true, {}, this.params.regionStyle),
824        labelStyle: jvm.$.extend(true, {}, this.params.regionLabelStyle),
825        canvas: this.canvas,
826        labelsGroup: this.regionLabelsGroup,
827        label: this.canvas.mode != 'vml' ? (this.params.labels && this.params.labels.regions) : null
828      });
829
830      jvm.$(region.shape).bind('selected', function(e, isSelected){
831        map.container.trigger('regionSelected.jvectormap', [jvm.$(this.node).attr('data-code'), isSelected, map.getSelectedRegions()]);
832      });
833      this.regions[key] = {
834        element: region,
835        config: this.mapData.paths[key]
836      };
837    }
838  },
839
840  createMarkers: function(markers) {
841    var i,
842        marker,
843        point,
844        markerConfig,
845        markersArray,
846        map = this;
847
848    this.markersGroup = this.markersGroup || this.canvas.addGroup();
849    this.markerLabelsGroup = this.markerLabelsGroup || this.canvas.addGroup();
850
851    if (jvm.$.isArray(markers)) {
852      markersArray = markers.slice();
853      markers = {};
854      for (i = 0; i < markersArray.length; i++) {
855        markers[i] = markersArray[i];
856      }
857    }
858
859    for (i in markers) {
860      markerConfig = markers[i] instanceof Array ? {latLng: markers[i]} : markers[i];
861      point = this.getMarkerPosition( markerConfig );
862      if (point !== false) {
863        //console.log(markers[i])
864        this.params.markerStyle.initial.r = markers[i].realRadius;
865        marker = new jvm.Marker({
866          map: this,
867          style: jvm.$.extend(true, {}, this.params.markerStyle, {initial: markerConfig.style || {}}),
868          labelStyle: jvm.$.extend(true, {}, this.params.markerLabelStyle),
869          index: i,
870          cx: point.x,
871          cy: point.y,
872          regionCode: markers[i].regionCode,
873          group: this.markersGroup,
874          canvas: this.canvas,
875          labelsGroup: this.markerLabelsGroup,
876          label: this.canvas.mode != 'vml' ? (this.params.labels && this.params.labels.markers) : null
877        });
878
879
880
881        jvm.$(marker.shape).bind('selected', function(e, isSelected){
882          map.container.trigger('markerSelected.jvectormap', [jvm.$(this.node).attr('data-index'), isSelected, map.getSelectedMarkers()]);
883        });
884        if (this.markers[i]) {
885          this.removeMarkers([i]);
886        }
887        this.markers[i] = {element: marker, config: markerConfig};
888      }
889
890    }
891  },
892
893  repositionMarkers: function() {
894    var i,
895        point;
896
897    for (i in this.markers) {
898      point = this.getMarkerPosition( this.markers[i].config );
899      if (point !== false) {
900        this.markers[i].element.setStyle({cx: point.x, cy: point.y});
901      }
902    }
903  },
904
905  repositionLabels: function() {
906    var key;
907
908    for (key in this.regions) {
909      this.regions[key].element.updateLabelPosition();
910    }
911
912    for (key in this.markers) {
913      this.markers[key].element.updateLabelPosition();
914    }
915  },
916
917  getMarkerPosition: function(markerConfig) {
918    if (jvm.Map.maps[this.params.map].projection) {
919      return this.latLngToPoint.apply(this, markerConfig.latLng || [0, 0]);
920    } else {
921      return {
922        x: markerConfig.coords[0]*this.scale + this.transX*this.scale,
923        y: markerConfig.coords[1]*this.scale + this.transY*this.scale,
924      };
925    }
926  },
927
928  /**
929   * Add one marker to the map.
930   * @param {String}
930 key Marker unique code.
931   * @param {Object} marker Marker configuration parameters.
932   * @param {Array} seriesData Values to add to the data series.
933   */
934  addMarker: function(key, marker, seriesData){
935    var markers = {},
936        data = [],
937        values,
938        i,
939        seriesData = seriesData || [];
940
941    markers[key] = marker;
942
943    for (i = 0; i < seriesData.length; i++) {
944      values = {};
945      if (typeof seriesData[i] !== 'undefined') {
946        values[key] = seriesData[i];
947      }
948      data.push(values);
949    }
950    this.addMarkers(markers, data);
951  },
952
953  /**
954   * Add set of marker to the map.
955   * @param {Object|Array} markers Markers to add to the map. In case of array is provided, codes of markers will be set as string representations of array indexes.
956   * @param {Array} seriesData Values to add to the data series.
957   */
958  addMarkers: function(markers, seriesData){
959    var i;
960
961    seriesData = seriesData || [];
962
963    this.createMarkers(markers);
964    for (i = 0; i < seriesData.length; i++) {
965      this.series.markers[i].setValues(seriesD
965ata[i] || {});
966    };
967  },
968
969  /**
970   * Remove some markers from the map.
971   * @param {Array} markers Array of marker codes to be removed.
972   */
973  removeMarkers: function(markers){
974    var i;
975
976    for (i = 0; i < markers.length; i++) {
977      this.markers[ markers[i] ].element.remove();
978      delete this.markers[ markers[i] ];
979    };
980  },
981
982  /**
983   * Remove all markers from the map.
984   */
985  removeAllMarkers: function(){
986    var i,
987        markers = [];
988
989    for (i in this.markers) {
990      markers.push(i);
991    }
992    this.removeMarkers(markers)
993  },
994
995  /**
996   * Converts coordinates expressed as latitude and longitude to the coordinates in pixels on the map.
997   * @param {Number} lat Latitide of point in degrees.
998   * @param {Number} lng Longitude of point in degrees.
999   */
1000  latLngToPoint: function(lat, lng) {
1001    var point,
1002        proj = jvm.Map.maps[this.params.map].projection,
1003        centralMeridian = proj.centralMeridian,
1004        inset,
1005        bbox;
1006
1007    if (lng < (-180 + centralMeridian)) {
1008      lng += 360;
1009    }
1010
1011    point = jvm.Proj[proj.type](lat, lng, centralMeridian);
1012
1013    inset = this.getInsetForPoint(point.x, point.y);
1014    if (inset) {
1015      bbox = inset.bbox;
1016
1017      point.x = (point.x - bbox[0].x) / (bbox[1].x - bbox[0].x) * inset.width * this.scale;
1018      point.y = (point.y - bbox[0].y) / (bbox[1].y - bbox[0].y) * inset.height * this.scale;
1019
1020      return {
1021        x: point.x + this.transX*this.scale + inset.left*this.scale,
1022        y: point.y + this.transY*this.scale + inset.top*this.scale
1023      };
1024     } else {
1025       return false;
1026     }
1027  },
1028
1029  /**
1030   * Converts cartesian coordinates into coordinates expressed as latitude and longitude.
1031   * @param {Number} x X-axis of point on map in pixels.
1032   * @param {Number} y Y-axis of point on map in pixels.
1033   */
1034  pointToLatLng: function(x, y) {
1035    var proj = jvm.Map.maps[this.params.map].projection,
1036        centralMeridian = proj.centralMeridian,
1037        insets = jvm.Map.maps[this.params.map].insets,
1038        i,
1039        inset,
1040        bbox,
1041        nx,
1042        ny;
1043
1044    for (i = 0; i < insets.length; i++) {
1045      inset = insets[i];
1046      bbox = inset.bbox;
1047
1048      nx = x - (this.transX*this.scale + inset.left*this.scale);
1049      ny = y - (this.transY*this.scale + inset.top*this.scale);
1050
1051      nx = (nx / (inset.width * this.scale)) * (bbox[1].x - bbox[0].x) + bbox[0].x;
1052      ny = (ny / (inset.height * this.scale)) * (bbox[1].y - bbox[0].y) + bbox[0].y;
1053
1054      if (nx > bbox[0].x && nx < bbox[1].x && ny > bbox[0].y && ny < bbox[1].y) {
1055        return jvm.Proj[proj.type + '_inv'](nx, -ny, centralMeridian);
1056      }
1057    }
1058
1059    return false;
1060  },
1061
1062  getInsetForPoint: function(x, y){
1063    var insets = jvm.Map.maps[this.params.map].insets,
1064        i,
1065        bbox;
1066
1067    for (i = 0; i < insets.length; i++) {
1068      bbox = insets[i].bbox;
1069      if (x > bbox[0].x && x < bbox[1].x && y > bbox[0].y && y < bbox[1].y) {
1070        return insets[i];
1071      }
1072    }
1073  },
1074
1075  createSeries: function(){
1076    var i,
1077        key;
1078
1079    this.series = {
1080      markers: [],
1081      regions: []
1082    };
1083
1084    for (key in this.params.series) {
1085      for (i = 0; i < this.params.series[key].length; i++) {
1086        this.series[key][i] = new jvm.DataSeries(
1087          this.params.series[key][i],
1088          this[key],
1089          this
1090        );
1091      }
1092    }
1093  },
1094
1095  /**
1096   * Gracefully remove the map and and all its accessories, unbind event handlers.
1097   */
1098  remove: function(){
1099    this.tip.remove();
1100    this.container.remove();
1101    jvm.$(window).unbind('resize', this.onResize);
1102    jvm.$('body').unbind('mouseup', this.onContainerMouseUp);
1103  }
1104};
1105
1106jvm.Map.maps = {};
1107jvm.Map.defaultParams = {
1108  map: 'world_mill_en',
1109  backgroundColor: '#505050',
1110  zoomButtons: true,
1111  zoomOnScroll: true,
1112  zoomOnScrollSpeed: 3,
1113  panOnDrag: true,
1114  zoomMax: 8,
1115  zoomMin: 1,
1116  zoomStep: 1.6,
1117  zoomAnimate: true,
1118  regionsSelectable: false,
1119  markersSelectable: false,
1120  bindTouchEvents: true,
1121  regionStyle: {
1122    initial: {
1123      fill: 'white',
1124      "fill-opacity": 1,
1125      stroke: 'none',
1126      "stroke-width": 0,
1127      "stroke-opacity": 1
1128    },
1129    hover: {
1130      "fill-opacity": 0.8,
1131      cursor: 'pointer'
1132    },
1133    selected: {
1134      fill: 'yellow'
1135    },
1136    selectedHover: {
1137    }
1138  },
1139  regionLabelStyle: {
1140    initial: {
1141      'font-family': 'Verdana',
1142      'font-size': '12',
1143      'font-weight': 'bold',
1144      cursor: 'default',
1145      fill: 'black'
1146    },
1147    hover: {
1148      cursor: 'pointer'
1149    }
1150  },
1151  markerStyle: {
1152    initial: {
1153      fill: 'grey',
1154      stroke: '#505050',
1155      "fill-opacity": 1,
1156      "stroke-width": 1,
1157      "stroke-opacity": 1,
1158      r: 5
1159    },
1160    hover: {
1161      stroke: 'black',
1162      "stroke-width": 2,
1163      cursor: 'pointer'
1164    },
1165    selected: {
1166      fill: 'blue'
1167    },
1168    selectedHover: {
1169    }
1170  },
1171  markerLabelStyle: {
1172    initial: {
1173      'font-family': 'Verdana',
1174      'font-size': '12',
1175      'font-weight': 'bold',
1176      cursor: 'default',
1177      fill: 'black'
1178    },
1179    hover: {
1180      cursor: 'pointer'
1181    }
1182  }
1183};
1184jvm.Map.apiEvents = {
1185  onRegionTipShow: 'regionTipShow',
1186  onRegionOver: 'regionOver',
1187  onRegionOut: 'regionOut',
1188  onRegionClick: 'regionClick',
1189  onRegionSelected: 'regionSelected',
1190  onMarkerTipShow: 'markerTipShow',
1191  onMarkerOver: 'markerOver',
1192  onMarkerOut: 'markerOut',
1193  onMarkerClick: 'markerClick',
1194  onMarkerSelected: 'markerSelected',
1195  onViewportChange: 'viewportChange'
1196};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.