10
var VectorCanvas = function (width, height, params) {
11
this.mode = window.SVGAngle ? 'svg' : 'vml';
14
if (this.mode === 'svg') {
15
this.createSvgNode = function (nodeName) {
16
return document.createElementNS(this.svgns, nodeName);
20
if (!document.namespaces.rvml) {
21
document.namespaces.add('rvml', 'urn:schemas-microsoft-com:vml');
23
this.createVmlNode = function (tagName) {
24
return document.createElement('<rvml:' + tagName + ' class="rvml">');
27
this.createVmlNode = function (tagName) {
28
return document.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
32
document.createStyleSheet().addRule('.rvml', 'behavior:url(#default#VML)');
35
if (this.mode === 'svg') {
36
this.canvas = this.createSvgNode('svg');
38
this.canvas = this.createVmlNode('group');
39
this.canvas.style.position = 'absolute';
42
this.setSize(width, height);
45
VectorCanvas.prototype = {
46
svgns: 'http://www.w3.org/2000/svg',
53
var ColorScale = function (colors, normalizeFunction, minValue, maxValue) {
55
this.setColors(colors);
57
if (normalizeFunction) {
58
this.setNormalizeFunction(normalizeFunction);
61
this.setMin(minValue);
64
this.setMax(maxValue);
68
ColorScale.prototype = {
72
var JQVMap = function (params) {
73
params = params || {};
75
var mapData = JQVMap.maps[params.map];
79
throw new Error('Invalid "' + params.map + '" map parameter. Please make sure you have loaded this map file in your HTML.');
82
this.selectedRegions = [];
83
this.multiSelectRegion = params.multiSelectRegion;
85
this.container = params.container;
87
this.defaultWidth = mapData.width;
88
this.defaultHeight = mapData.height;
90
this.color = params.color;
91
this.selectedColor = params.selectedColor;
92
this.hoverColor = params.hoverColor;
93
this.hoverColors = params.hoverColors;
94
this.hoverOpacity = params.hoverOpacity;
95
this.setBackgroundColor(params.backgroundColor);
97
this.width = params.container.width();
98
this.height = params.container.height();
102
jQuery(window).resize(function () {
103
var newWidth = params.container.width();
104
var newHeight = params.container.height();
106
if(newWidth && newHeight){
107
map.width = newWidth;
108
map.height = newHeight;
110
map.canvas.setSize(map.width, map.height);
111
map.applyTransform();
113
var resizeEvent = jQuery.Event('resize.jqvmap');
114
jQuery(params.container).trigger(resizeEvent, [newWidth, newHeight]);
117
jQuery('.jqvmap-pin').remove();
118
map.pinHandlers = false;
119
map.placePins(mapPins.pins, mapPins.mode);
124
this.canvas = new VectorCanvas(this.width, this.height, params);
125
params.container.append(this.canvas.canvas);
127
this.makeDraggable();
129
this.rootGroup = this.canvas.createGroup(true);
131
this.index = JQVMap.mapIndex;
132
this.label = jQuery('<div/>').addClass('jqvmap-label').appendTo(jQuery('body')).hide();
134
if (params.enableZoom) {
135
jQuery('<div/>').addClass('jqvmap-zoomin').text('+').appendTo(params.container);
136
jQuery('<div/>').addClass('jqvmap-zoomout').html('−').appendTo(params.container);
141
for (var key in mapData.paths) {
142
var path = this.canvas.createPath({
143
path: mapData.paths[key].path
146
path.setFill(this.color);
147
path.id = map.getCountryId(key);
148
map.countries[key] = path;
150
if (this.canvas.mode === 'svg') {
151
path.setAttribute('class', 'jqvmap-region');
153
jQuery(path).addClass('jqvmap-region');
156
jQuery(this.rootGroup).append(path);
159
jQuery(params.container).delegate(this.canvas.mode === 'svg' ? 'path' : 'shape', 'mouseover mouseout', function (e) {
160
var containerPath = e.target,
161
code = e.target.id.split('_').pop(),
162
labelShowEvent = jQuery.Event('labelShow.jqvmap'),
163
regionMouseOverEvent = jQuery.Event('regionMouseOver.jqvmap');
165
code = code.toLowerCase();
167
if (e.type === 'mouseover') {
168
jQuery(params.container).trigger(regionMouseOverEvent, [code, mapData.paths[code].name]);
169
if (!regionMouseOverEvent.isDefaultPrevented()) {
170
map.highlight(code, containerPath);
172
if (params.showTooltip) {
173
map.label.text(mapData.paths[code].name);
174
jQuery(params.container).trigger(labelShowEvent, [map.label, code]);
176
if (!labelShowEvent.isDefaultPrevented()) {
178
map.labelWidth = map.label.width();
179
map.labelHeight = map.label.height();
183
map.unhighlight(code, containerPath);
186
jQuery(params.container).trigger('regionMouseOut.jqvmap', [code, mapData.paths[code].name]);
190
jQuery(params.container).delegate(this.canvas.mode === 'svg' ? 'path' : 'shape', 'click', function (regionClickEvent) {
192
var targetPath = regionClickEvent.target;
193
var code = regionClickEvent.target.id.split('_').pop();
194
var mapClickEvent = jQuery.Event('regionClick.jqvmap');
196
code = code.toLowerCase();
198
jQuery(params.container).trigger(mapClickEvent, [code, mapData.paths[code].name]);
200
if ( !params.multiSelectRegion && !mapClickEvent.isDefaultPrevented()) {
201
for (var keyPath in mapData.paths) {
202
map.countries[keyPath].currentFillColor = map.countries[keyPath].getOriginalFill();
203
map.countries[keyPath].setFill(map.countries[keyPath].getOriginalFill());
207
if ( !mapClickEvent.isDefaultPrevented()) {
208
if (map.isSelected(code)) {
209
map.deselect(code, targetPath);
211
map.select(code, targetPath);
216
if (params.showTooltip) {
217
params.container.mousemove(function (e) {
218
if (map.label.is(':visible')) {
219
var left = e.pageX - 15 - map.labelWidth;
220
var top = e.pageY - 15 - map.labelHeight;
237
this.setColors(params.colors);
239
this.canvas.canvas.appendChild(this.rootGroup);
241
this.applyTransform();
243
this.colorScale = new ColorScale(params.scaleColors, params.normalizeFunction, params.valueMin, params.valueMax);
246
this.values = params.values;
247
this.setValues(params.values);
250
if (params.selectedRegions) {
251
if (params.selectedRegions instanceof Array) {
252
for(var k in params.selectedRegions) {
253
this.select(params.selectedRegions[k].toLowerCase());
256
this.select(params.selectedRegions.toLowerCase());
260
this.bindZoomButtons();
268
this.pinHandlers = false;
269
this.placePins(params.pins, params.pinMode);
272
if(params.showLabels){
273
this.pinHandlers = false;
276
for (key in map.countries){
277
if (typeof map.countries[key] !== 'function') {
278
if( !params.pins || !params.pins[key] ){
279
pins[key] = key.toUpperCase();
289
this.placePins(pins, 'content');
312
JQVMap.xlink = 'http://www.w3.org/1999/xlink';
323
normalizeFunction: 1,
334
onLabelShow: 'labelShow',
336
onRegionOver: 'regionMouseOver',
337
onRegionOut: 'regionMouseOut',
338
onRegionClick: 'regionClick',
339
onRegionSelect: 'regionSelect',
340
onRegionDeselect: 'regionDeselect',
344
jQuery.fn.vectorMap = function (options) {
346
var defaultParams = {
348
backgroundColor: '#a5bfdd',
350
hoverColor: '#c9dfaf',
352
selectedColor: '#c9dfaf',
353
scaleColors: ['#b6d6ff', '#005ace'],
354
normalizeFunction: 'linear',
357
borderColor: '#818181',
360
selectedRegions: null,
361
multiSelectRegion: false
362
}, map = this.data('mapObject');
364
if (options === 'addMap') {
365
JQVMap.maps[arguments[1]] = arguments[2];
366
} else if (options === 'set' && apiParams[arguments[1]]) {
367
map['set' + arguments[1].charAt(0).toUpperCase() + arguments[1].substr(1)].apply(map, Array.prototype.slice.call(arguments, 2));
368
} else if (typeof options === 'string' &&
369
typeof map[options] === 'function') {
370
return map[options].apply(map, Array.prototype.slice.call(arguments, 1));
372
jQuery.extend(defaultParams, options);
373
defaultParams.container = this;
374
this.css({ position: 'relative', overflow: 'hidden' });
376
map = new JQVMap(defaultParams);
378
this.data('mapObject', map);
380
this.unbind('.jqvmap');
382
for (var e in apiEvents) {
383
if (defaultParams[e]) {
384
this.bind(apiEvents[e] + '.jqvmap', defaultParams[e]);
388
var loadEvent = jQuery.Event('load.jqvmap');
389
jQuery(defaultParams.container).trigger(loadEvent, map);
397
ColorScale.arrayToRgb = function (ar) {
400
for (var i = 0; i < ar.length; i++) {
401
d = ar[i].toString(16);
402
rgb += d.length === 1 ? '0' + d : d;
407
ColorScale.prototype.getColor = function (value) {
408
if (typeof this.normalize === 'function') {
409
value = this.normalize(value);
416
for (var i = 0; i < this.colors.length - 1; i++) {
417
l = this.vectorLength(this.vectorSubtract(this.colors[i + 1], this.colors[i]));
422
var c = (this.maxValue - this.minValue) / fullLength;
424
for (i = 0; i < lengthes.length; i++) {
429
value -= this.minValue;
431
while (value - lengthes[i] >= 0) {
432
value -= lengthes[i];
437
if (i === this.colors.length - 1) {
438
color = this.vectorToNum(this.colors[i]).toString(16);
440
color = (this.vectorToNum(this.vectorAdd(this.colors[i], this.vectorMult(this.vectorSubtract(this.colors[i + 1], this.colors[i]), (value) / (lengthes[i]))))).toString(16);
443
while (color.length < 6) {
449
ColorScale.rgbToArray = function (rgb) {
451
return [parseInt(rgb.substr(0, 2), 16), parseInt(rgb.substr(2, 2), 16), parseInt(rgb.substr(4, 2), 16)];
454
ColorScale.prototype.setColors = function (colors) {
455
for (var i = 0; i < colors.length; i++) {
456
colors[i] = ColorScale.rgbToArray(colors[i]);
458
this.colors = colors;
461
ColorScale.prototype.setMax = function (max) {
462
this.clearMaxValue = max;
463
if (typeof this.normalize === 'function') {
464
this.maxValue = this.normalize(max);
470
ColorScale.prototype.setMin = function (min) {
471
this.clearMinValue = min;
473
if (typeof this.normalize === 'function') {
474
this.minValue = this.normalize(min);
480
ColorScale.prototype.setNormalizeFunction = function (f) {
481
if (f === 'polynomial') {
482
this.normalize = function (value) {
483
return Math.pow(value, 0.2);
485
} else if (f === 'linear') {
486
delete this.normalize;
490
this.setMin(this.clearMinValue);
491
this.setMax(this.clearMaxValue);
494
ColorScale.prototype.vectorAdd = function (vector1, vector2) {
496
for (var i = 0; i < vector1.length; i++) {
497
vector[i] = vector1[i] + vector2[i];
502
ColorScale.prototype.vectorLength = function (vector) {
504
for (var i = 0; i < vector.length; i++) {
505
result += vector[i] * vector[i];
507
return Math.sqrt(result);
510
ColorScale.prototype.vectorMult = function (vector, num) {
512
for (var i = 0; i < vector.length; i++) {
513
result[i] = vector[i] * num;
518
ColorScale.prototype.vectorSubtract = function (vector1, vector2) {
520
for (var i = 0; i < vector1.length; i++) {
521
vector[i] = vector1[i] - vector2[i];
526
ColorScale.prototype.vectorToNum = function (vector) {
528
for (var i = 0; i < vector.length; i++) {
529
num += Math.round(vector[i]) * Math.pow(256, vector.length - i - 1);
534
JQVMap.prototype.applyTransform = function () {
535
var maxTransX, maxTransY, minTransX, minTransY;
536
if (this.defaultWidth * this.scale <= this.width) {
537
maxTransX = (this.width - this.defaultWidth * this.scale) / (2 * this.scale);
538
minTransX = (this.width - this.defaultWidth * this.scale) / (2 * this.scale);
541
minTransX = (this.width - this.defaultWidth * this.scale) / this.scale;
544
if (this.defaultHeight * this.scale <= this.height) {
545
maxTransY = (this.height - this.defaultHeight * this.scale) / (2 * this.scale);
546
minTransY = (this.height - this.defaultHeight * this.scale) / (2 * this.scale);
549
minTransY = (this.height - this.defaultHeight * this.scale) / this.scale;
552
if (this.transY > maxTransY) {
553
this.transY = maxTransY;
554
} else if (this.transY < minTransY) {
555
this.transY = minTransY;
557
if (this.transX > maxTransX) {
558
this.transX = maxTransX;
559
} else if (this.transX < minTransX) {
560
this.transX = minTransX;
563
this.canvas.applyTransformParams(this.scale, this.transX, this.transY);
566
JQVMap.prototype.bindZoomButtons = function () {
568
this.container.find('.jqvmap-zoomin').click(function(){
571
this.container.find('.jqvmap-zoomout').click(function(){
576
JQVMap.prototype.deselect = function (cc, path) {
577
cc = cc.toLowerCase();
578
path = path || jQuery('#' + this.getCountryId(cc))[0];
580
if (this.isSelected(cc)) {
581
this.selectedRegions.splice(this.selectIndex(cc), 1);
583
jQuery(this.container).trigger('regionDeselect.jqvmap', [cc]);
584
path.currentFillColor = path.getOriginalFill();
585
path.setFill(path.getOriginalFill());
587
for (var key in this.countries) {
588
this.selectedRegions.splice(this.selectedRegions.indexOf(key), 1);
589
this.countries[key].currentFillColor = this.color;
590
this.countries[key].setFill(this.color);
595
JQVMap.prototype.getCountryId = function (cc) {
596
return 'jqvmap' + this.index + '_' + cc;
599
JQVMap.prototype.getPin = function(cc){
600
var pinObj = jQuery('#' + this.getPinId(cc));
601
return pinObj.html();
604
JQVMap.prototype.getPinId = function (cc) {
605
return this.getCountryId(cc) + '_pin';
608
JQVMap.prototype.getPins = function(){
609
var pins = this.container.find('.jqvmap-pin');
611
jQuery.each(pins, function(index, pinObj){
612
pinObj = jQuery(pinObj);
613
var cc = pinObj.attr('for').toLowerCase();
614
var pinContent = pinObj.html();
615
ret[cc] = pinContent;
617
return JSON.stringify(ret);
620
JQVMap.prototype.highlight = function (cc, path) {
621
path = path || jQuery('#' + this.getCountryId(cc))[0];
622
if (this.hoverOpacity) {
623
path.setOpacity(this.hoverOpacity);
624
} else if (this.hoverColors && (cc in this.hoverColors)) {
625
path.currentFillColor = path.getFill() + '';
626
path.setFill(this.hoverColors[cc]);
627
} else if (this.hoverColor) {
628
path.currentFillColor = path.getFill() + '';
629
path.setFill(this.hoverColor);
633
JQVMap.prototype.isSelected = function(cc) {
634
return this.selectIndex(cc) >= 0;
637
JQVMap.prototype.makeDraggable = function () {
638
var mouseDown = false;
639
var oldPageX, oldPageY;
642
self.isMoving = false;
643
self.isMovingTimeout = false;
648
var touchStartDistance;
653
this.container.mousemove(function (e) {
656
self.transX -= (oldPageX - e.pageX) / self.scale;
657
self.transY -= (oldPageY - e.pageY) / self.scale;
659
self.applyTransform();
664
self.isMoving = true;
665
if (self.isMovingTimeout) {
666
clearTimeout(self.isMovingTimeout);
669
self.container.trigger('drag');
674
}).mousedown(function (e) {
682
}).mouseup(function () {
686
clearTimeout(self.isMovingTimeout);
687
self.isMovingTimeout = setTimeout(function () {
688
self.isMoving = false;
693
}).mouseout(function () {
695
if(mouseDown && self.isMoving){
697
clearTimeout(self.isMovingTimeout);
698
self.isMovingTimeout = setTimeout(function () {
700
self.isMoving = false;
707
jQuery(this.container).bind('touchmove', function (e) {
711
var touches = e.originalEvent.touches;
715
if (touches.length === 1) {
716
if (lastTouchCount === 1) {
718
if(touchX === touches[0].pageX && touchY === touches[0].pageY){
722
transformXOld = self.transX;
723
transformYOld = self.transY;
725
self.transX -= (touchX - touches[0].pageX) / self.scale;
726
self.transY -= (touchY - touches[0].pageY) / self.scale;
728
self.applyTransform();
730
if (transformXOld !== self.transX || transformYOld !== self.transY) {
734
self.isMoving = true;
735
if (self.isMovingTimeout) {
736
clearTimeout(self.isMovingTimeout);
740
touchX = touches[0].pageX;
741
touchY = touches[0].pageY;
743
} else if (touches.length === 2) {
745
if (lastTouchCount === 2) {
747
Math.pow(touches[0].pageX - touches[1].pageX, 2) +
748
Math.pow(touches[0].pageY - touches[1].pageY, 2)
749
) / touchStartDistance;
752
touchStartScale * scale,
761
offset = jQuery(self.container).offset();
762
if (touches[0].pageX > touches[1].pageX) {
763
touchCenterX = touches[1].pageX + (touches[0].pageX - touches[1].pageX) / 2;
765
touchCenterX = touches[0].pageX + (touches[1].pageX - touches[0].pageX) / 2;
768
if (touches[0].pageY > touches[1].pageY) {
769
touchCenterY = touches[1].pageY + (touches[0].pageY - touches[1].pageY) / 2;
771
touchCenterY = touches[0].pageY + (touches[1].pageY - touches[0].pageY) / 2;
774
touchCenterX -= offset.left;
775
touchCenterY -= offset.top;
776
touchStartScale = self.scale;
778
touchStartDistance = Math.sqrt(
779
Math.pow(touches[0].pageX - touches[1].pageX, 2) +
780
Math.pow(touches[0].pageY - touches[1].pageY, 2)
785
lastTouchCount = touches.length;
788
jQuery(this.container).bind('touchstart', function () {
792
jQuery(this.container).bind('touchend', function () {
797
JQVMap.prototype.placePins = function(pins, pinMode){
800
if(!pinMode || (pinMode !== 'content' && pinMode !== 'id')) {
804
if(pinMode === 'content') {
805
jQuery.each(pins, function(index, pin){
806
if(jQuery('#' + map.getCountryId(index)).length === 0){
810
var pinIndex = map.getPinId(index);
811
var $pin = jQuery('#' + pinIndex);
815
map.container.append('<div id="' + pinIndex + '" for="' + index + '" class="jqvmap-pin" style="position:absolute">' + pin + '</div>');
818
jQuery.each(pins, function(index, pin){
819
if(jQuery('#' + map.getCountryId(index)).length === 0){
822
var pinIndex = map.getPinId(index);
823
var $pin = jQuery('#' + pinIndex);
827
map.container.append('<div id="' + pinIndex + '" for="' + index + '" class="jqvmap-pin" style="position:absolute"></div>');
828
$pin.append(jQuery('#' + pin));
833
if(!this.pinHandlers){
834
this.pinHandlers = true;
835
var positionFix = function(){
838
this.container.bind('zoomIn', positionFix)
839
.bind('zoomOut', positionFix)
840
.bind('drag', positionFix);
844
JQVMap.prototype.positionPins = function(){
846
var pins = this.container.find('.jqvmap-pin');
847
jQuery.each(pins, function(index, pinObj){
848
pinObj = jQuery(pinObj);
849
var countryId = map.getCountryId(pinObj.attr('for').toLowerCase());
850
var countryObj = jQuery('#' + countryId);
851
var bbox = countryObj[0].getBBox();
853
var scale = map.scale;
854
var rootCoords = map.canvas.rootGroup.getBoundingClientRect();
855
var mapCoords = map.container[0].getBoundingClientRect();
857
left: rootCoords.left - mapCoords.left,
858
top: rootCoords.top - mapCoords.top
861
var middleX = (bbox.x * scale) + ((bbox.width * scale) / 2);
862
var middleY = (bbox.y * scale) + ((bbox.height * scale) / 2);
865
left: coords.left + middleX - (pinObj.width() / 2),
866
top: coords.top + middleY - (pinObj.height() / 2)
871
JQVMap.prototype.removePin = function(cc) {
872
cc = cc.toLowerCase();
873
jQuery('#' + this.getPinId(cc)).remove();
876
JQVMap.prototype.removePins = function(){
877
this.container.find('.jqvmap-pin').remove();
880
JQVMap.prototype.reset = function () {
881
for (var key in this.countries) {
882
this.countries[key].setFill(this.color);
884
this.scale = this.baseScale;
885
this.transX = this.baseTransX;
886
this.transY = this.baseTransY;
887
this.applyTransform();
888
this.zoomCurStep = 1;
891
JQVMap.prototype.resize = function () {
892
var curBaseScale = this.baseScale;
893
if (this.width / this.height > this.defaultWidth / this.defaultHeight) {
894
this.baseScale = this.height / this.defaultHeight;
895
this.baseTransX = Math.abs(this.width - this.defaultWidth * this.baseScale) / (2 * this.baseScale);
897
this.baseScale = this.width / this.defaultWidth;
898
this.baseTransY = Math.abs(this.height - this.defaultHeight * this.baseScale) / (2 * this.baseScale);
900
this.scale *= this.baseScale / curBaseScale;
901
this.transX *= this.baseScale / curBaseScale;
902
this.transY *= this.baseScale / curBaseScale;
905
JQVMap.prototype.select = function (cc, path) {
906
cc = cc.toLowerCase();
907
path = path || jQuery('#' + this.getCountryId(cc))[0];
909
if (!this.isSelected(cc)) {
910
if (this.multiSelectRegion) {
911
this.selectedRegions.push(cc);
913
this.selectedRegions = [cc];
916
jQuery(this.container).trigger('regionSelect.jqvmap', [cc]);
917
if (this.selectedColor && path) {
918
path.currentFillColor = this.selectedColor;
919
path.setFill(this.selectedColor);
924
JQVMap.prototype.selectIndex = function (cc) {
925
cc = cc.toLowerCase();
926
for (var i = 0; i < this.selectedRegions.length; i++) {
927
if (cc === this.selectedRegions[i]) {
934
JQVMap.prototype.setBackgroundColor = function (backgroundColor) {
935
this.container.css('background-color', backgroundColor);
938
JQVMap.prototype.setColors = function (key, color) {
939
if (typeof key === 'string') {
940
this.countries[key].setFill(color);
941
this.countries[key].setAttribute('original', color);
945
for (var code in colors) {
946
if (this.countries[code]) {
947
this.countries[code].setFill(colors[code]);
948
this.countries[code].setAttribute('original', colors[code]);
954
JQVMap.prototype.setNormalizeFunction = function (f) {
955
this.colorScale.setNormalizeFunction(f);
958
this.setValues(this.values);
962
JQVMap.prototype.setScale = function (scale) {
964
this.applyTransform();
967
JQVMap.prototype.setScaleColors = function (colors) {
968
this.colorScale.setColors(colors);
971
this.setValues(this.values);
975
JQVMap.prototype.setValues = function (values) {
977
min = Number.MAX_VALUE,
980
for (var cc in values) {
981
cc = cc.toLowerCase();
982
val = parseFloat(values[cc]);
999
this.colorScale.setMin(min);
1000
this.colorScale.setMax(max);
1003
for (cc in values) {
1004
cc = cc.toLowerCase();
1005
val = parseFloat(values[cc]);
1006
colors[cc] = isNaN(val) ? this.color : this.colorScale.getColor(val);
1008
this.setColors(colors);
1009
this.values = values;
1012
JQVMap.prototype.unhighlight = function (cc, path) {
1013
cc = cc.toLowerCase();
1014
path = path || jQuery('#' + this.getCountryId(cc))[0];
1016
if (path.currentFillColor) {
1017
path.setFill(path.currentFillColor);
1021
JQVMap.prototype.zoomIn = function () {
1023
var sliderDelta = (jQuery('#zoom').innerHeight() - 6 * 2 - 15 * 2 - 3 * 2 - 7 - 6) / (this.zoomMaxStep - this.zoomCurStep);
1025
if (map.zoomCurStep < map.zoomMaxStep) {
1026
map.transX -= (map.width / map.scale - map.width / (map.scale * map.zoomStep)) / 2;
1027
map.transY -= (map.height / map.scale - map.height / (map.scale * map.zoomStep)) / 2;
1028
map.setScale(map.scale * map.zoomStep);
1031
var $slider = jQuery('#zoomSlider');
1033
$slider.css('top', parseInt($slider.css('top'), 10) - sliderDelta);
1035
map.container.trigger('zoomIn');
1039
JQVMap.prototype.zoomOut = function () {
1041
var sliderDelta = (jQuery('#zoom').innerHeight() - 6 * 2 - 15 * 2 - 3 * 2 - 7 - 6) / (this.zoomMaxStep - this.zoomCurStep);
1043
if (map.zoomCurStep > 1) {
1044
map.transX += (map.width / (map.scale / map.zoomStep) - map.width / map.scale) / 2;
1045
map.transY += (map.height / (map.scale / map.zoomStep) - map.height / map.scale) / 2;
1046
map.setScale(map.scale / map.zoomStep);
1049
var $slider = jQuery('#zoomSlider');
1051
$slider.css('top', parseInt($slider.css('top'), 10) + sliderDelta);
1053
map.container.trigger('zoomOut');
1057
VectorCanvas.prototype.applyTransformParams = function (scale, transX, transY) {
1058
if (this.mode === 'svg') {
1059
this.rootGroup.setAttribute('transform', 'scale(' + scale + ') translate(' + transX + ', ' + transY + ')');
1061
this.rootGroup.coordorigin = (this.width - transX) + ',' + (this.height - transY);
1062
this.rootGroup.coordsize = this.width / scale + ',' + this.height / scale;
1066
VectorCanvas.prototype.createGroup = function (isRoot) {
1068
if (this.mode === 'svg') {
1069
node = this.createSvgNode('g');
1071
node = this.createVmlNode('group');
1072
node.style.width = this.width + 'px';
1073
node.style.height = this.height + 'px';
1074
node.style.left = '0px';
1075
node.style.top = '0px';
1076
node.coordorigin = '0 0';
1077
node.coordsize = this.width + ' ' + this.height;
1081
this.rootGroup = node;
1086
VectorCanvas.prototype.createPath = function (config) {
1088
if (this.mode === 'svg') {
1089
node = this.createSvgNode('path');
1090
node.setAttribute('d', config.path);
1092
if (this.params.borderColor !== null) {
1093
node.setAttribute('stroke', this.params.borderColor);
1095
if (this.params.borderWidth > 0) {
1096
node.setAttribute('stroke-width', this.params.borderWidth);
1097
node.setAttribute('stroke-linecap', 'round');
1098
node.setAttribute('stroke-linejoin', 'round');
1100
if (this.params.borderOpacity > 0) {
1101
node.setAttribute('stroke-opacity', this.params.borderOpacity);
1104
node.setFill = function (color) {
1105
this.setAttribute('fill', color);
1106
if (this.getAttribute('original') === null) {
1107
this.setAttribute('original', color);
1111
node.getFill = function () {
1112
return this.getAttribute('fill');
1115
node.getOriginalFill = function () {
1116
return this.getAttribute('original');
1119
node.setOpacity = function (opacity) {
1120
this.setAttribute('fill-opacity', opacity);
1123
node = this.createVmlNode('shape');
1124
node.coordorigin = '0 0';
1125
node.coordsize = this.width + ' ' + this.height;
1126
node.style.width = this.width + 'px';
1127
node.style.height = this.height + 'px';
1128
node.fillcolor = JQVMap.defaultFillColor;
1129
node.stroked = false;
1130
node.path = VectorCanvas.pathSvgToVml(config.path);
1132
var scale = this.createVmlNode('skew');
1134
scale.matrix = '0.01,0,0,0.01,0,0';
1135
scale.offset = '0,0';
1137
node.appendChild(scale);
1139
var fill = this.createVmlNode('fill');
1140
node.appendChild(fill);
1142
node.setFill = function (color) {
1143
this.getElementsByTagName('fill')[0].color = color;
1144
if (this.getAttribute('original') === null) {
1145
this.setAttribute('original', color);
1149
node.getFill = function () {
1150
return this.getElementsByTagName('fill')[0].color;
1152
node.getOriginalFill = function () {
1153
return this.getAttribute('original');
1155
node.setOpacity = function (opacity) {
1156
this.getElementsByTagName('fill')[0].opacity = parseInt(opacity * 100, 10) + '%';
1162
VectorCanvas.prototype.pathSvgToVml = function (path) {
1164
var cx = 0, cy = 0, ctrlx, ctrly;
1166
return path.replace(/([MmLlHhVvCcSs])((?:-?(?:\d+)?(?:\.\d+)?,?\s?)+)/g, function (segment, letter, coords) {
1167
coords = coords.replace(/(\d)-/g, '$1,-').replace(/\s+/g, ',').split(',');
1172
for (var i = 0, l = coords.length; i < l; i++) {
1173
coords[i] = Math.round(100 * coords[i]);
1180
result = 't' + coords.join(',');
1186
result = 'm' + coords.join(',');
1192
result = 'r' + coords.join(',');
1198
result = 'l' + coords.join(',');
1203
result = 'r' + coords[0] + ',0';
1208
result = 'l' + cx + ',' + cy;
1213
result = 'r0,' + coords[0];
1218
result = 'l' + cx + ',' + cy;
1222
ctrlx = cx + coords[coords.length - 4];
1223
ctrly = cy + coords[coords.length - 3];
1224
cx += coords[coords.length - 2];
1225
cy += coords[coords.length - 1];
1226
result = 'v' + coords.join(',');
1230
ctrlx = coords[coords.length - 4];
1231
ctrly = coords[coords.length - 3];
1232
cx = coords[coords.length - 2];
1233
cy = coords[coords.length - 1];
1234
result = 'c' + coords.join(',');
1238
coords.unshift(cy - ctrly);
1239
coords.unshift(cx - ctrlx);
1240
ctrlx = cx + coords[coords.length - 4];
1241
ctrly = cy + coords[coords.length - 3];
1242
cx += coords[coords.length - 2];
1243
cy += coords[coords.length - 1];
1244
result = 'v' + coords.join(',');
1248
coords.unshift(cy + cy - ctrly);
1249
coords.unshift(cx + cx - ctrlx);
1250
ctrlx = coords[coords.length - 4];
1251
ctrly = coords[coords.length - 3];
1252
cx = coords[coords.length - 2];
1253
cy = coords[coords.length - 1];
1254
result = 'c' + coords.join(',');
1263
}).replace(/z/g, '');
1266
VectorCanvas.prototype.setSize = function (width, height) {
1267
if (this.mode === 'svg') {
1268
this.canvas.setAttribute('width', width);
1269
this.canvas.setAttribute('height', height);
1271
this.canvas.style.width = width + 'px';
1272
this.canvas.style.height = height + 'px';
1273
this.canvas.coordsize = width + ' ' + height;
1274
this.canvas.coordorigin = '0 0';
1275
if (this.rootGroup) {
1276
var paths = this.rootGroup.getElementsByTagName('shape');
1277
for (var i = 0, l = paths.length; i < l; i++) {
1278
paths[i].coordsize = width + ' ' + height;
1279
paths[i].style.width = width + 'px';
1280
paths[i].style.height = height + 'px';
1282
this.rootGroup.coordsize = width + ' ' + height;
1283
this.rootGroup.style.width = width + 'px';
1284
this.rootGroup.style.height = height + 'px';
1288
this.height = height;