| 5 |
lars |
1 |
/*!
|
|
|
2 |
* jQVMap Version 1.0
|
|
|
3 |
*
|
|
|
4 |
* http://jqvmap.com
|
|
|
5 |
*
|
|
|
6 |
* Copyright 2012, Peter Schmalfeldt <manifestinteractive@gmail.com>
|
|
|
7 |
* Copyright 2011-2012, Kirill Lebedev
|
|
|
8 |
* Licensed under the MIT license.
|
|
|
9 |
*
|
|
|
10 |
* Fork Me @ https://github.com/manifestinteractive/jqvmap
|
|
|
11 |
*/
|
|
|
12 |
(function ($) {
|
|
|
13 |
|
|
|
14 |
var apiParams = {
|
|
|
15 |
colors: 1,
|
|
|
16 |
values: 1,
|
|
|
17 |
backgroundColor: 1,
|
|
|
18 |
scaleColors: 1,
|
|
|
19 |
normalizeFunction: 1,
|
|
|
20 |
enableZoom: 1,
|
|
|
21 |
showTooltip: 1,
|
|
|
22 |
borderColor: 1,
|
|
|
23 |
borderWidth: 1,
|
|
|
24 |
borderOpacity: 1,
|
|
|
25 |
selectedRegions: 1,
|
|
|
26 |
multiSelectRegion: 1
|
|
|
27 |
};
|
|
|
28 |
|
|
|
29 |
var apiEvents = {
|
|
|
30 |
onLabelShow: 'labelShow',
|
|
|
31 |
onRegionOver: 'regionMouseOver',
|
|
|
32 |
onRegionOut: 'regionMouseOut',
|
|
|
33 |
onRegionClick: 'regionClick',
|
|
|
34 |
onRegionSelect: 'regionSelect',
|
|
|
35 |
onRegionDeselect: 'regionDeselect'
|
|
|
36 |
};
|
|
|
37 |
|
|
|
38 |
$.fn.vectorMap = function (options) {
|
|
|
39 |
|
|
|
40 |
var defaultParams = {
|
|
|
41 |
map: 'world_en',
|
|
|
42 |
backgroundColor: '#a5bfdd',
|
|
|
43 |
color: '#f4f3f0',
|
|
|
44 |
hoverColor: '#c9dfaf',
|
|
|
45 |
selectedColor: '#c9dfaf',
|
|
|
46 |
scaleColors: ['#b6d6ff', '#005ace'],
|
|
|
47 |
normalizeFunction: 'linear',
|
|
|
48 |
enableZoom: true,
|
|
|
49 |
showTooltip: true,
|
|
|
50 |
borderColor: '#818181',
|
|
|
51 |
borderWidth: 1,
|
|
|
52 |
borderOpacity: 0.25,
|
|
|
53 |
selectedRegions: null,
|
|
|
54 |
multiSelectRegion: false
|
|
|
55 |
}, map = this.data('mapObject');
|
|
|
56 |
|
|
|
57 |
if (options === 'addMap') {
|
|
|
58 |
WorldMap.maps[arguments[1]] = arguments[2];
|
|
|
59 |
} else if (options === 'set' && apiParams[arguments[1]]) {
|
|
|
60 |
map['set' + arguments[1].charAt(0).toUpperCase() + arguments[1].substr(1)].apply(map, Array.prototype.slice.call(arguments, 2));
|
|
|
61 |
} else if (typeof options === 'string' &&
|
|
|
62 |
typeof map[options] === 'function') {
|
|
|
63 |
return map[options].apply(map, Array.prototype.slice.call(arguments, 1));
|
|
|
64 |
} else {
|
|
|
65 |
$.extend(defaultParams, options);
|
|
|
66 |
defaultParams.container = this;
|
|
|
67 |
this.css({ position: 'relative', overflow: 'hidden' });
|
|
|
68 |
|
|
|
69 |
map = new WorldMap(defaultParams);
|
|
|
70 |
|
|
|
71 |
this.data('mapObject', map);
|
|
|
72 |
|
|
|
73 |
for (var e in apiEvents) {
|
|
|
74 |
if (defaultParams[e]) {
|
|
|
75 |
this.bind(apiEvents[e] + '.jqvmap', defaultParams[e]);
|
|
|
76 |
}
|
|
|
77 |
}
|
|
|
78 |
}
|
|
|
79 |
};
|
|
|
80 |
|
|
|
81 |
var VectorCanvas = function (width, height, params) {
|
|
|
82 |
this.mode = window.SVGAngle ? 'svg' : 'vml';
|
|
|
83 |
this.params = params;
|
|
|
84 |
|
|
|
85 |
if (this.mode == 'svg') {
|
|
|
86 |
this.createSvgNode = function (nodeName) {
|
|
|
87 |
return document.createElementNS(this.svgns, nodeName);
|
|
|
88 |
};
|
|
|
89 |
} else {
|
|
|
90 |
try {
|
|
|
91 |
if (!document.namespaces.rvml) {
|
|
|
92 |
document.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
|
|
|
93 |
}
|
|
|
94 |
this.createVmlNode = function (tagName) {
|
|
|
95 |
return document.createElement('<rvml:' + tagName + ' class="rvml">');
|
|
|
96 |
};
|
|
|
97 |
} catch (e) {
|
|
|
98 |
this.createVmlNode = function (tagName) {
|
|
|
99 |
return document.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
|
|
|
100 |
};
|
|
|
101 |
}
|
|
|
102 |
|
|
|
103 |
document.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
|
|
|
104 |
}
|
|
|
105 |
|
|
|
106 |
if (this.mode == 'svg') {
|
|
|
107 |
this.canvas = this.createSvgNode('svg');
|
|
|
108 |
} else {
|
|
|
109 |
this.canvas = this.createVmlNode('group');
|
|
|
110 |
this.canvas.style.position = 'absolute';
|
|
|
111 |
}
|
|
|
112 |
|
|
|
113 |
this.setSize(width, height);
|
|
|
114 |
};
|
|
|
115 |
|
|
|
116 |
VectorCanvas.prototype = {
|
|
|
117 |
svgns: "http://www.w3.org/2000/svg",
|
|
|
118 |
mode: 'svg',
|
|
|
119 |
width: 0,
|
|
|
120 |
height: 0,
|
|
|
121 |
canvas: null,
|
|
|
122 |
|
|
|
123 |
setSize: function (width, height) {
|
|
|
124 |
if (this.mode == 'svg') {
|
|
|
125 |
this.canvas.setAttribute('width', width);
|
|
|
126 |
this.canvas.setAttribute('height', height);
|
|
|
127 |
} else {
|
|
|
128 |
this.canvas.style.width = width + "px";
|
|
|
129 |
this.canvas.style.height = height + "px";
|
|
|
130 |
this.canvas.coordsize = width + ' ' + height;
|
|
|
131 |
this.canvas.coordorigin = "0 0";
|
|
|
132 |
if (this.rootGroup) {
|
|
|
133 |
var pathes = this.rootGroup.getElementsByTagName('shape');
|
|
|
134 |
for (var i = 0, l = pathes.length; i < l; i++) {
|
|
|
135 |
pathes[i].coordsize = width + ' ' + height;
|
|
|
136 |
pathes[i].style.width = width + 'px';
|
|
|
137 |
pathes[i].style.height = height + 'px';
|
|
|
138 |
}
|
|
|
139 |
this.rootGroup.coordsize = width + ' ' + height;
|
|
|
140 |
this.rootGroup.style.width = width + 'px';
|
|
|
141 |
this.rootGroup.style.height = height + 'px';
|
|
|
142 |
}
|
|
|
143 |
}
|
|
|
144 |
this.width = width;
|
|
|
145 |
this.height = height;
|
|
|
146 |
},
|
|
|
147 |
|
|
|
148 |
createPath: function (config) {
|
|
|
149 |
var node;
|
|
|
150 |
if (this.mode == 'svg') {
|
|
|
151 |
node = this.createSvgNode('path');
|
|
|
152 |
node.setAttribute('d', config.path);
|
|
|
153 |
|
|
|
154 |
if (this.params.borderColor !== null) {
|
|
|
155 |
node.setAttribute('stroke', this.params.borderColor);
|
|
|
156 |
}
|
|
|
157 |
if (this.params.borderWidth > 0) {
|
|
|
158 |
node.setAttribute('stroke-width', this.params.borderWidth);
|
|
|
159 |
node.setAttribute('stroke-linecap', 'round');
|
|
|
160 |
node.setAttribute('stroke-linejoin', 'round');
|
|
|
161 |
}
|
|
|
162 |
if (this.params.borderOpacity > 0) {
|
|
|
163 |
node.setAttribute('stroke-opacity', this.params.borderOpacity);
|
|
|
164 |
}
|
|
|
165 |
|
|
|
166 |
node.setFill = function (color) {
|
|
|
167 |
this.setAttribute("fill", color);
|
|
|
168 |
if (this.getAttribute("original") === null) {
|
|
|
169 |
this.setAttribute("original", color);
|
|
|
170 |
}
|
|
|
171 |
};
|
|
|
172 |
|
|
|
173 |
node.getFill = function (color) {
|
|
|
174 |
return this.getAttribute("fill");
|
|
|
175 |
};
|
|
|
176 |
|
|
|
177 |
node.getOriginalFill = function () {
|
|
|
178 |
return this.getAttribute("original");
|
|
|
179 |
};
|
|
|
180 |
|
|
|
181 |
node.setOpacity = function (opacity) {
|
|
|
182 |
this.setAttribute('fill-opacity', opacity);
|
|
|
183 |
};
|
|
|
184 |
} else {
|
|
|
185 |
node = this.createVmlNode('shape');
|
|
|
186 |
node.coordorigin = "0 0";
|
|
|
187 |
node.coordsize = this.width + ' ' + this.height;
|
|
|
188 |
node.style.width = this.width + 'px';
|
|
|
189 |
node.style.height = this.height + 'px';
|
|
|
190 |
node.fillcolor = WorldMap.defaultFillColor;
|
|
|
191 |
node.stroked = false;
|
|
|
192 |
node.path = VectorCanvas.pathSvgToVml(config.path);
|
|
|
193 |
|
|
|
194 |
var scale = this.createVmlNode('skew');
|
|
|
195 |
scale.on = true;
|
|
|
196 |
scale.matrix = '0.01,0,0,0.01,0,0';
|
|
|
197 |
scale.offset = '0,0';
|
|
|
198 |
|
|
|
199 |
node.appendChild(scale);
|
|
|
200 |
|
|
|
201 |
var fill = this.createVmlNode('fill');
|
|
|
202 |
node.appendChild(fill);
|
|
|
203 |
|
|
|
204 |
node.setFill = function (color) {
|
|
|
205 |
this.getElementsByTagName('fill')[0].color = color;
|
|
|
206 |
if (this.getAttribute("original") === null) {
|
|
|
207 |
this.setAttribute("original", color);
|
|
|
208 |
}
|
|
|
209 |
};
|
|
|
210 |
|
|
|
211 |
node.getFill = function (color) {
|
|
|
212 |
return this.getElementsByTagName('fill')[0].color;
|
|
|
213 |
};
|
|
|
214 |
node.getOriginalFill = function () {
|
|
|
215 |
return this.getAttribute("original");
|
|
|
216 |
};
|
|
|
217 |
node.setOpacity = function (opacity) {
|
|
|
218 |
this.getElementsByTagName('fill')[0].opacity = parseInt(opacity * 100, 10) + '%';
|
|
|
219 |
};
|
|
|
220 |
}
|
|
|
221 |
return node;
|
|
|
222 |
},
|
|
|
223 |
|
|
|
224 |
createGroup: function (isRoot) {
|
|
|
225 |
var node;
|
|
|
226 |
if (this.mode == 'svg') {
|
|
|
227 |
node = this.createSvgNode('g');
|
|
|
228 |
} else {
|
|
|
229 |
node = this.createVmlNode('group');
|
|
|
230 |
node.style.width = this.width + 'px';
|
|
|
231 |
node.style.height = this.height + 'px';
|
|
|
232 |
node.style.left = '0px';
|
|
|
233 |
node.style.top = '0px';
|
|
|
234 |
node.coordorigin = "0 0";
|
|
|
235 |
node.coordsize = this.width + ' ' + this.height;
|
|
|
236 |
}
|
|
|
237 |
|
|
|
238 |
if (isRoot) {
|
|
|
239 |
this.rootGroup = node;
|
|
|
240 |
}
|
|
|
241 |
return node;
|
|
|
242 |
},
|
|
|
243 |
|
|
|
244 |
applyTransformParams: function (scale, transX, transY) {
|
|
|
245 |
if (this.mode == 'svg') {
|
|
|
246 |
this.rootGroup.setAttribute('transform', 'scale(' + scale + ') translate(' + transX + ', ' + transY + ')');
|
|
|
247 |
} else {
|
|
|
248 |
this.rootGroup.coordorigin = (this.width - transX) + ',' + (this.height - transY);
|
|
|
249 |
this.rootGroup.coordsize = this.width / scale + ',' + this.height / scale;
|
|
|
250 |
}
|
|
|
251 |
}
|
|
|
252 |
};
|
|
|
253 |
|
|
|
254 |
VectorCanvas.pathSvgToVml = function (path) {
|
|
|
255 |
var result = '';
|
|
|
256 |
var cx = 0, cy = 0, ctrlx, ctrly;
|
|
|
257 |
|
|
|
258 |
return path.replace(/([MmLlHhVvCcSs])((?:-?(?:\d+)?(?:\.\d+)?,?\s?)+)/g, function (segment, letter, coords, index) {
|
|
|
259 |
coords = coords.replace(/(\d)-/g, '$1,-').replace(/\s+/g, ',').split(',');
|
|
|
260 |
if (!coords[0]) {
|
|
|
261 |
coords.shift();
|
|
|
262 |
}
|
|
|
263 |
|
|
|
264 |
for (var i = 0, l = coords.length; i < l; i++) {
|
|
|
265 |
coords[i] = Math.round(100 * coords[i]);
|
|
|
266 |
}
|
|
|
267 |
|
|
|
268 |
switch (letter) {
|
|
|
269 |
case 'm':
|
|
|
270 |
cx += coords[0];
|
|
|
271 |
cy += coords[1];
|
|
|
272 |
return 't' + coords.join(',');
|
|
|
273 |
break;
|
|
|
274 |
|
|
|
275 |
case 'M':
|
|
|
276 |
cx = coords[0];
|
|
|
277 |
cy = coords[1];
|
|
|
278 |
return 'm' + coords.join(',');
|
|
|
279 |
break;
|
|
|
280 |
|
|
|
281 |
case 'l':
|
|
|
282 |
cx += coords[0];
|
|
|
283 |
cy += coords[1];
|
|
|
284 |
return 'r' + coords.join(',');
|
|
|
285 |
break;
|
|
|
286 |
|
|
|
287 |
case 'L':
|
|
|
288 |
cx = coords[0];
|
|
|
289 |
cy = coords[1];
|
|
|
290 |
return 'l' + coords.join(',');
|
|
|
291 |
break;
|
|
|
292 |
|
|
|
293 |
case 'h':
|
|
|
294 |
cx += coords[0];
|
|
|
295 |
return 'r' + coords[0] + ',0';
|
|
|
296 |
break;
|
|
|
297 |
|
|
|
298 |
case 'H':
|
|
|
299 |
cx = coords[0];
|
|
|
300 |
return 'l' + cx + ',' + cy;
|
|
|
301 |
break;
|
|
|
302 |
|
|
|
303 |
case 'v':
|
|
|
304 |
cy += coords[0];
|
|
|
305 |
return 'r0,' + coords[0];
|
|
|
306 |
break;
|
|
|
307 |
|
|
|
308 |
case 'V':
|
|
|
309 |
cy = coords[0];
|
|
|
310 |
return 'l' + cx + ',' + cy;
|
|
|
311 |
break;
|
|
|
312 |
|
|
|
313 |
case 'c':
|
|
|
314 |
ctrlx = cx + coords[coords.length - 4];
|
|
|
315 |
ctrly = cy + coords[coords.length - 3];
|
|
|
316 |
cx += coords[coords.length - 2];
|
|
|
317 |
cy += coords[coords.length - 1];
|
|
|
318 |
return 'v' + coords.join(',');
|
|
|
319 |
break;
|
|
|
320 |
|
|
|
321 |
case 'C':
|
|
|
322 |
ctrlx = coords[coords.length - 4];
|
|
|
323 |
ctrly = coords[coords.length - 3];
|
|
|
324 |
cx = coords[coords.length - 2];
|
|
|
325 |
cy = coords[coords.length - 1];
|
|
|
326 |
return 'c' + coords.join(',');
|
|
|
327 |
break;
|
|
|
328 |
|
|
|
329 |
case 's':
|
|
|
330 |
coords.unshift(cy - ctrly);
|
|
|
331 |
coords.unshift(cx - ctrlx);
|
|
|
332 |
ctrlx = cx + coords[coords.length - 4];
|
|
|
333 |
ctrly = cy + coords[coords.length - 3];
|
|
|
334 |
cx += coords[coords.length - 2];
|
|
|
335 |
cy += coords[coords.length - 1];
|
|
|
336 |
return 'v' + coords.join(',');
|
|
|
337 |
break;
|
|
|
338 |
|
|
|
339 |
case 'S':
|
|
|
340 |
coords.unshift(cy + cy - ctrly);
|
|
|
341 |
coords.unshift(cx + cx - ctrlx);
|
|
|
342 |
ctrlx = coords[coords.length - 4];
|
|
|
343 |
ctrly = coords[coords.length - 3];
|
|
|
344 |
cx = coords[coords.length - 2];
|
|
|
345 |
cy = coords[coords.length - 1];
|
|
|
346 |
return 'c' + coords.join(',');
|
|
|
347 |
break;
|
|
|
348 |
|
|
|
349 |
default:
|
|
|
350 |
return false;
|
|
|
351 |
break;
|
|
|
352 |
}
|
|
|
353 |
|
|
|
354 |
return '';
|
|
|
355 |
|
|
|
356 |
}).replace(/z/g, '');
|
|
|
357 |
};
|
|
|
358 |
|
|
|
359 |
var WorldMap = function (params) {
|
|
|
360 |
params = params || {};
|
|
|
361 |
var map = this;
|
|
|
362 |
var mapData = WorldMap.maps[params.map];
|
|
|
363 |
|
|
|
364 |
this.selectedRegions = [];
|
|
|
365 |
this.multiSelectRegion = params.multiSelectRegion;
|
|
|
366 |
|
|
|
367 |
this.container = params.container;
|
|
|
368 |
|
|
|
369 |
this.defaultWidth = mapData.width;
|
|
|
370 |
this.defaultHeight = mapData.height;
|
|
|
371 |
|
|
|
372 |
this.color = params.color;
|
|
|
373 |
this.selectedColor = params.selectedColor;
|
|
|
374 |
this.hoverColor = params.hoverColor;
|
|
|
375 |
this.hoverOpacity = params.hoverOpacity;
|
|
|
376 |
this.setBackgroundColor(params.backgroundColor);
|
|
|
377 |
|
|
|
378 |
this.width = params.container.width();
|
|
|
379 |
this.height = params.container.height();
|
|
|
380 |
|
|
|
381 |
this.resize();
|
|
|
382 |
|
|
|
383 |
jQuery(window).resize(function () {
|
|
|
384 |
map.width = params.container.width();
|
|
|
385 |
map.height = params.container.height();
|
|
|
386 |
map.resize();
|
|
|
387 |
map.canvas.setSize(map.width, map.height);
|
|
|
388 |
map.applyTransform();
|
|
|
389 |
});
|
|
|
390 |
|
|
|
391 |
this.canvas = new VectorCanvas(this.width, this.height, params);
|
|
|
392 |
params.container.append(this.canvas.canvas);
|
|
|
393 |
|
|
|
394 |
this.makeDraggable();
|
|
|
395 |
|
|
|
396 |
this.rootGroup = this.canvas.createGroup(true);
|
|
|
397 |
|
|
|
398 |
this.index = WorldMap.mapIndex;
|
|
|
399 |
this.label = jQuery('<div/>').addClass('jqvmap-label').appendTo(jQuery('body'));
|
|
|
400 |
|
|
|
401 |
if (params.enableZoom) {
|
|
|
402 |
jQuery('<div/>').addClass('jqvmap-zoomin').text('+').appendTo(params.container);
|
|
|
403 |
jQuery('<div/>').addClass('jqvmap-zoomout').html('−').appendTo(params.container);
|
|
|
404 |
}
|
|
|
405 |
|
|
|
406 |
map.countries = [];
|
|
|
407 |
|
|
|
408 |
for (var key in mapData.pathes) {
|
|
|
409 |
var path = this.canvas.createPath({
|
|
|
410 |
path: mapData.pathes[key].path
|
|
|
411 |
});
|
|
|
412 |
|
|
|
413 |
path.setFill(this.color);
|
|
|
414 |
path.id = map.getCountryId(key);
|
|
|
415 |
map.countries[key] = path;
|
|
|
416 |
|
|
|
417 |
if (this.canvas.mode == 'svg') {
|
|
|
418 |
path.setAttribute('class', 'jvectormap-region');
|
|
|
419 |
} else {
|
|
|
420 |
jQuery(path).addClass('jvectormap-region');
|
|
|
421 |
}
|
|
|
422 |
|
|
|
423 |
jQuery(this.rootGroup).append(path);
|
|
|
424 |
}
|
|
|
425 |
|
|
|
426 |
jQuery(params.container).delegate(this.canvas.mode == 'svg' ? 'path' : 'shape', 'mouseover mouseout', function (e) {
|
|
|
427 |
var path = e.target,
|
|
|
428 |
code = e.target.id.split('_').pop(),
|
|
|
429 |
labelShowEvent = $.Event('labelShow.jqvmap'),
|
|
|
430 |
regionMouseOverEvent = $.Event('regionMouseOver.jqvmap');
|
|
|
431 |
|
|
|
432 |
if (e.type == 'mouseover') {
|
|
|
433 |
jQuery(params.container).trigger(regionMouseOverEvent, [code, mapData.pathes[code].name]);
|
|
|
434 |
if (!regionMouseOverEvent.isDefaultPrevented()) {
|
|
|
435 |
map.highlight(code, path);
|
|
|
436 |
}
|
|
|
437 |
if (params.showTooltip) {
|
|
|
438 |
map.label.text(mapData.pathes[code].name);
|
|
|
439 |
jQuery(params.container).trigger(labelShowEvent, [map.label, code]);
|
|
|
440 |
|
|
|
441 |
if (!labelShowEvent.isDefaultPrevented()) {
|
|
|
442 |
map.label.show();
|
|
|
443 |
map.labelWidth = map.label.width();
|
|
|
444 |
map.labelHeight = map.label.height();
|
|
|
445 |
}
|
|
|
446 |
}
|
|
|
447 |
} else {
|
|
|
448 |
map.unhighlight(code, path);
|
|
|
449 |
|
|
|
450 |
map.label.hide();
|
|
|
451 |
jQuery(params.container).trigger('regionMouseOut.jqvmap', [code, mapData.pathes[code].name]);
|
|
|
452 |
}
|
|
|
453 |
});
|
|
|
454 |
|
|
|
455 |
jQuery(params.container).delegate(this.canvas.mode == 'svg' ? 'path' : 'shape', 'click', function (e) {
|
|
|
456 |
if (!params.multiSelectRegion) {
|
|
|
457 |
for (var key in mapData.pathes) {
|
|
|
458 |
map.countries[key].currentFillColor = map.countries[key].getOriginalFill();
|
|
|
459 |
map.countries[key].setFill(map.countries[key].getOriginalFill());
|
|
|
460 |
}
|
|
|
461 |
}
|
|
|
462 |
|
|
|
463 |
var path = e.target;
|
|
|
464 |
var code = e.target.id.split('_').pop();
|
|
|
465 |
|
|
|
466 |
jQuery(params.container).trigger('regionClick.jqvmap', [code, mapData.pathes[code].name]);
|
|
|
467 |
|
|
|
468 |
if (map.selectedRegions.indexOf(code) !== -1) {
|
|
|
469 |
map.deselect(code, path);
|
|
|
470 |
} else {
|
|
|
471 |
map.select(code, path);
|
|
|
472 |
}
|
|
|
473 |
|
|
|
474 |
//console.log(selectedRegions);
|
|
|
475 |
|
|
|
476 |
});
|
|
|
477 |
|
|
|
478 |
if (params.showTooltip) {
|
|
|
479 |
params.container.mousemove(function (e) {
|
|
|
480 |
if (map.label.is(':visible')) {
|
|
|
481 |
map.label.css({
|
|
|
482 |
left: e.pageX - 15 - map.labelWidth,
|
|
|
483 |
top: e.pageY - 15 - map.labelHeight
|
|
|
484 |
});
|
|
|
485 |
}
|
|
|
486 |
});
|
|
|
487 |
}
|
|
|
488 |
|
|
|
489 |
this.setColors(params.colors);
|
|
|
490 |
|
|
|
491 |
this.canvas.canvas.appendChild(this.rootGroup);
|
|
|
492 |
|
|
|
493 |
this.applyTransform();
|
|
|
494 |
|
|
|
495 |
this.colorScale = new ColorScale(params.scaleColors, params.normalizeFunction, params.valueMin, params.valueMax);
|
|
|
496 |
|
|
|
497 |
if (params.values) {
|
|
|
498 |
this.values = params.values;
|
|
|
499 |
this.setValues(params.values);
|
|
|
500 |
}
|
|
|
501 |
|
|
|
502 |
if (params.selectedRegions) {
|
|
|
503 |
if (params.selectedRegions instanceof Array) {
|
|
|
504 |
for(var k in params.selectedRegions) {
|
|
|
505 |
this.select(params.selectedRegions[k].toLowerCase());
|
|
|
506 |
}
|
|
|
507 |
} else {
|
|
|
508 |
this.select(params.selectedRegions.toLowerCase());
|
|
|
509 |
}
|
|
|
510 |
}
|
|
|
511 |
|
|
|
512 |
this.bindZoomButtons();
|
|
|
513 |
|
|
|
514 |
WorldMap.mapIndex++;
|
|
|
515 |
};
|
|
|
516 |
|
|
|
517 |
WorldMap.prototype = {
|
|
|
518 |
transX: 0,
|
|
|
519 |
transY: 0,
|
|
|
520 |
scale: 1,
|
|
|
521 |
baseTransX: 0,
|
|
|
522 |
baseTransY: 0,
|
|
|
523 |
baseScale: 1,
|
|
|
524 |
width: 0,
|
|
|
525 |
height: 0,
|
|
|
526 |
countries: {},
|
|
|
527 |
countriesColors: {},
|
|
|
528 |
countriesData: {},
|
|
|
529 |
zoomStep: 1.4,
|
|
|
530 |
zoomMaxStep: 4,
|
|
|
531 |
zoomCurStep: 1,
|
|
|
532 |
|
|
|
533 |
setColors: function (key, color) {
|
|
|
534 |
if (typeof key == 'string') {
|
|
|
535 |
this.countries[key].setFill(color);
|
|
|
536 |
this.countries[key].setAttribute("original", color);
|
|
|
537 |
} else {
|
|
|
538 |
var colors = key;
|
|
|
539 |
|
|
|
540 |
for (var code in colors) {
|
|
|
541 |
if (this.countries[code]) {
|
|
|
542 |
this.countries[code].setFill(colors[code]);
|
|
|
543 |
this.countries[code].setAttribute("original", colors[code]);
|
|
|
544 |
}
|
|
|
545 |
}
|
|
|
546 |
}
|
|
|
547 |
},
|
|
|
548 |
|
|
|
549 |
setValues: function (values) {
|
|
|
550 |
var max = 0,
|
|
|
551 |
min = Number.MAX_VALUE,
|
|
|
552 |
val;
|
|
|
553 |
|
|
|
554 |
for (var cc in values) {
|
|
|
555 |
val = parseFloat(values[cc]);
|
|
|
556 |
if (val > max) {
|
|
|
557 |
max = values[cc];
|
|
|
558 |
}
|
|
|
559 |
if (val && val < min) {
|
|
|
560 |
min = val;
|
|
|
561 |
}
|
|
|
562 |
}
|
|
|
563 |
|
|
|
564 |
this.colorScale.setMin(min);
|
|
|
565 |
this.colorScale.setMax(max);
|
|
|
566 |
|
|
|
567 |
var colors = {};
|
|
|
568 |
for (cc in values) {
|
|
|
569 |
val = parseFloat(values[cc]);
|
|
|
570 |
if (val) {
|
|
|
571 |
colors[cc] = this.colorScale.getColor(val);
|
|
|
572 |
} else {
|
|
|
573 |
colors[cc] = this.color;
|
|
|
574 |
}
|
|
|
575 |
}
|
|
|
576 |
this.setColors(colors);
|
|
|
577 |
this.values = values;
|
|
|
578 |
},
|
|
|
579 |
|
|
|
580 |
setBackgroundColor: function (backgroundColor) {
|
|
|
581 |
this.container.css('background-color', backgroundColor);
|
|
|
582 |
},
|
|
|
583 |
|
|
|
584 |
setScaleColors: function (colors) {
|
|
|
585 |
this.colorScale.setColors(colors);
|
|
|
586 |
|
|
|
587 |
if (this.values) {
|
|
|
588 |
this.setValues(this.values);
|
|
|
589 |
}
|
|
|
590 |
},
|
|
|
591 |
|
|
|
592 |
setNormalizeFunction: function (f) {
|
|
|
593 |
this.colorScale.setNormalizeFunction(f);
|
|
|
594 |
|
|
|
595 |
if (this.values) {
|
|
|
596 |
this.setValues(this.values);
|
|
|
597 |
}
|
|
|
598 |
},
|
|
|
599 |
|
|
|
600 |
highlight: function (cc, path) {
|
|
|
601 |
path = path || $('#' + this.getCountryId(cc))[0];
|
|
|
602 |
if (this.hoverOpacity) {
|
|
|
603 |
path.setOpacity(this.hoverOpacity);
|
|
|
604 |
} else if (this.hoverColor) {
|
|
|
605 |
path.currentFillColor = path.getFill() + '';
|
|
|
606 |
path.setFill(this.hoverColor);
|
|
|
607 |
}
|
|
|
608 |
},
|
|
|
609 |
|
|
|
610 |
unhighlight: function (cc, path) {
|
|
|
611 |
path = path || $('#' + this.getCountryId(cc))[0];
|
|
|
612 |
path.setOpacity(1);
|
|
|
613 |
if (path.currentFillColor) {
|
|
|
614 |
path.setFill(path.currentFillColor);
|
|
|
615 |
}
|
|
|
616 |
},
|
|
|
617 |
|
|
|
618 |
select: function (cc, path) {
|
|
|
619 |
path = path || $('#' + this.getCountryId(cc))[0];
|
|
|
620 |
if(this.selectedRegions.indexOf(cc) < 0) {
|
|
|
621 |
if (this.multiSelectRegion) {
|
|
|
622 |
this.selectedRegions.push(cc);
|
|
|
623 |
} else {
|
|
|
624 |
this.selectedRegions = [cc];
|
|
|
625 |
}
|
|
|
626 |
// MUST BE after the change of selectedRegions
|
|
|
627 |
// Otherwise, we might loop
|
|
|
628 |
$(this.container).trigger('regionSelect.jqvmap', [cc]);
|
|
|
629 |
if (this.selectedColor) {
|
|
|
630 |
path.currentFillColor = this.selectedColor;
|
|
|
631 |
path.setFill(this.selectedColor);
|
|
|
632 |
}
|
|
|
633 |
}
|
|
|
634 |
},
|
|
|
635 |
|
|
|
636 |
deselect: function (cc, path) {
|
|
|
637 |
path = path || $('#' + this.getCountryId(cc))[0];
|
|
|
638 |
if(this.selectedRegions.indexOf(cc) >= 0) {
|
|
|
639 |
this.selectedRegions.splice(this.selectedRegions.indexOf(cc), 1);
|
|
|
640 |
// MUST BE after the change of selectedRegions
|
|
|
641 |
// Otherwise, we might loop
|
|
|
642 |
$(this.container).trigger('regionDeselect.jqvmap', [cc]);
|
|
|
643 |
path.currentFillColor = path.getOriginalFill();
|
|
|
644 |
path.setFill(path.getOriginalFill());
|
|
|
645 |
}
|
|
|
646 |
},
|
|
|
647 |
|
|
|
648 |
isSelected: function(cc) {
|
|
|
649 |
return this.selectedRegions.indexOf(cc) >= 0;
|
|
|
650 |
},
|
|
|
651 |
|
|
|
652 |
resize: function () {
|
|
|
653 |
var curBaseScale = this.baseScale;
|
|
|
654 |
if (this.width / this.height > this.defaultWidth / this.defaultHeight) {
|
|
|
655 |
this.baseScale = this.height / this.defaultHeight;
|
|
|
656 |
this.baseTransX = Math.abs(this.width - this.defaultWidth * this.baseScale) / (2 * this.baseScale);
|
|
|
657 |
} else {
|
|
|
658 |
this.baseScale = this.width / this.defaultWidth;
|
|
|
659 |
this.baseTransY = Math.abs(this.height - this.defaultHeight * this.baseScale) / (2 * this.baseScale);
|
|
|
660 |
}
|
|
|
661 |
this.scale *= this.baseScale / curBaseScale;
|
|
|
662 |
this.transX *= this.baseScale / curBaseScale;
|
|
|
663 |
this.transY *= this.baseScale / curBaseScale;
|
|
|
664 |
},
|
|
|
665 |
|
|
|
666 |
reset: function () {
|
|
|
667 |
this.countryTitle.reset();
|
|
|
668 |
for (var key in this.countries) {
|
|
|
669 |
this.countries[key].setFill(WorldMap.defaultColor);
|
|
|
670 |
}
|
|
|
671 |
this.scale = this.baseScale;
|
|
|
672 |
this.transX = this.baseTransX;
|
|
|
673 |
this.transY = this.baseTransY;
|
|
|
674 |
this.applyTransform();
|
|
|
675 |
},
|
|
|
676 |
|
|
|
677 |
applyTransform: function () {
|
|
|
678 |
var maxTransX, maxTransY, minTransX, minTransY;
|
|
|
679 |
if (this.defaultWidth * this.scale <= this.width) {
|
|
|
680 |
maxTransX = (this.width - this.defaultWidth * this.scale) / (2 * this.scale);
|
|
|
681 |
minTransX = (this.width - this.defaultWidth * this.scale) / (2 * this.scale);
|
|
|
682 |
} else {
|
|
|
683 |
maxTransX = 0;
|
|
|
684 |
minTransX = (this.width - this.defaultWidth * this.scale) / this.scale;
|
|
|
685 |
}
|
|
|
686 |
|
|
|
687 |
if (this.defaultHeight * this.scale <= this.height) {
|
|
|
688 |
maxTransY = (this.height - this.defaultHeight * this.scale) / (2 * this.scale);
|
|
|
689 |
minTransY = (this.height - this.defaultHeight * this.scale) / (2 * this.scale);
|
|
|
690 |
} else {
|
|
|
691 |
maxTransY = 0;
|
|
|
692 |
minTransY = (this.height - this.defaultHeight * this.scale) / this.scale;
|
|
|
693 |
}
|
|
|
694 |
|
|
|
695 |
if (this.transY > maxTransY) {
|
|
|
696 |
this.transY = maxTransY;
|
|
|
697 |
}
|
|
|
698 |
else if (this.transY < minTransY) {
|
|
|
699 |
this.transY = minTransY;
|
|
|
700 |
}
|
|
|
701 |
if (this.transX > maxTransX) {
|
|
|
702 |
this.transX = maxTransX;
|
|
|
703 |
}
|
|
|
704 |
else if (this.transX < minTransX) {
|
|
|
705 |
this.transX = minTransX;
|
|
|
706 |
}
|
|
|
707 |
|
|
|
708 |
this.canvas.applyTransformParams(this.scale, this.transX, this.transY);
|
|
|
709 |
},
|
|
|
710 |
|
|
|
711 |
makeDraggable: function () {
|
|
|
712 |
var mouseDown = false;
|
|
|
713 |
var oldPageX, oldPageY;
|
|
|
714 |
var self = this;
|
|
|
715 |
|
|
|
716 |
self.isMoving = false;
|
|
|
717 |
self.isMovingTimeout = false;
|
|
|
718 |
|
|
|
719 |
this.container.mousemove(function (e) {
|
|
|
720 |
|
|
|
721 |
if (mouseDown) {
|
|
|
722 |
var curTransX = self.transX;
|
|
|
723 |
var curTransY = self.transY;
|
|
|
724 |
|
|
|
725 |
self.transX -= (oldPageX - e.pageX) / self.scale;
|
|
|
726 |
self.transY -= (oldPageY - e.pageY) / self.scale;
|
|
|
727 |
|
|
|
728 |
self.applyTransform();
|
|
|
729 |
|
|
|
730 |
oldPageX = e.pageX;
|
|
|
731 |
oldPageY = e.pageY;
|
|
|
732 |
|
|
|
733 |
self.isMoving = true;
|
|
|
734 |
if (self.isMovingTimeout) {
|
|
|
735 |
clearTimeout(self.isMovingTimeout);
|
|
|
736 |
}
|
|
|
737 |
}
|
|
|
738 |
|
|
|
739 |
return false;
|
|
|
740 |
|
|
|
741 |
}).mousedown(function (e) {
|
|
|
742 |
|
|
|
743 |
mouseDown = true;
|
|
|
744 |
oldPageX = e.pageX;
|
|
|
745 |
oldPageY = e.pageY;
|
|
|
746 |
|
|
|
747 |
return false;
|
|
|
748 |
|
|
|
749 |
}).mouseup(function () {
|
|
|
750 |
|
|
|
751 |
mouseDown = false;
|
|
|
752 |
|
|
|
753 |
self.isMovingTimeout = setTimeout(function () {
|
|
|
754 |
self.isMoving = false;
|
|
|
755 |
}, 100);
|
|
|
756 |
|
|
|
757 |
return false;
|
|
|
758 |
|
|
|
759 |
});
|
|
|
760 |
},
|
|
|
761 |
|
|
|
762 |
bindZoomButtons: function () {
|
|
|
763 |
var map = this;
|
|
|
764 |
var sliderDelta = (jQuery('#zoom').innerHeight() - 6 * 2 - 15 * 2 - 3 * 2 - 7 - 6) / (this.zoomMaxStep - this.zoomCurStep);
|
|
|
765 |
|
|
|
766 |
this.container.find('.jqvmap-zoomin').click(function () {
|
|
|
767 |
if (map.zoomCurStep < map.zoomMaxStep) {
|
|
|
768 |
var curTransX = map.transX;
|
|
|
769 |
var curTransY = map.transY;
|
|
|
770 |
var curScale = map.scale;
|
|
|
771 |
|
|
|
772 |
map.transX -= (map.width / map.scale - map.width / (map.scale * map.zoomStep)) / 2;
|
|
|
773 |
map.transY -= (map.height / map.scale - map.height / (map.scale * map.zoomStep)) / 2;
|
|
|
774 |
map.setScale(map.scale * map.zoomStep);
|
|
|
775 |
map.zoomCurStep++;
|
|
|
776 |
|
|
|
777 |
jQuery('#zoomSlider').css('top', parseInt(jQuery('#zoomSlider').css('top'), 10) - sliderDelta);
|
|
|
778 |
}
|
|
|
779 |
});
|
|
|
780 |
|
|
|
781 |
this.container.find('.jqvmap-zoomout').click(function () {
|
|
|
782 |
if (map.zoomCurStep > 1) {
|
|
|
783 |
var curTransX = map.transX;
|
|
|
784 |
var curTransY = map.transY;
|
|
|
785 |
var curScale = map.scale;
|
|
|
786 |
|
|
|
787 |
map.transX += (map.width / (map.scale / map.zoomStep) - map.width / map.scale) / 2;
|
|
|
788 |
map.transY += (map.height / (map.scale / map.zoomStep) - map.height / map.scale) / 2;
|
|
|
789 |
map.setScale(map.scale / map.zoomStep);
|
|
|
790 |
map.zoomCurStep--;
|
|
|
791 |
|
|
|
792 |
jQuery('#zoomSlider').css('top', parseInt(jQuery('#zoomSlider').css('top'), 10) + sliderDelta);
|
|
|
793 |
}
|
|
|
794 |
});
|
|
|
795 |
},
|
|
|
796 |
|
|
|
797 |
setScale: function (scale) {
|
|
|
798 |
this.scale = scale;
|
|
|
799 |
this.applyTransform();
|
|
|
800 |
},
|
|
|
801 |
|
|
|
802 |
getCountryId: function (cc) {
|
|
|
803 |
return 'jqvmap' + this.index + '_' + cc;
|
|
|
804 |
}
|
|
|
805 |
};
|
|
|
806 |
|
|
|
807 |
WorldMap.xlink = "http://www.w3.org/1999/xlink";
|
|
|
808 |
WorldMap.mapIndex = 1;
|
|
|
809 |
WorldMap.maps = {};
|
|
|
810 |
|
|
|
811 |
var ColorScale = function (colors, normalizeFunction, minValue, maxValue) {
|
|
|
812 |
if (colors) {
|
|
|
813 |
this.setColors(colors);
|
|
|
814 |
}
|
|
|
815 |
if (normalizeFunction) {
|
|
|
816 |
this.setNormalizeFunction(normalizeFunction);
|
|
|
817 |
}
|
|
|
818 |
if (minValue) {
|
|
|
819 |
this.setMin(minValue);
|
|
|
820 |
}
|
|
|
821 |
if (minValue) {
|
|
|
822 |
this.setMax(maxValue);
|
|
|
823 |
}
|
|
|
824 |
};
|
|
|
825 |
|
|
|
826 |
ColorScale.prototype = {
|
|
|
827 |
colors: [],
|
|
|
828 |
|
|
|
829 |
setMin: function (min) {
|
|
|
830 |
this.clearMinValue = min;
|
|
|
831 |
|
|
|
832 |
if (typeof this.normalize === 'function') {
|
|
|
833 |
this.minValue = this.normalize(min);
|
|
|
834 |
} else {
|
|
|
835 |
this.minValue = min;
|
|
|
836 |
}
|
|
|
837 |
},
|
|
|
838 |
|
|
|
839 |
setMax: function (max) {
|
|
|
840 |
this.clearMaxValue = max;
|
|
|
841 |
if (typeof this.normalize === 'function') {
|
|
|
842 |
this.maxValue = this.normalize(max);
|
|
|
843 |
} else {
|
|
|
844 |
this.maxValue = max;
|
|
|
845 |
}
|
|
|
846 |
},
|
|
|
847 |
|
|
|
848 |
setColors: function (colors) {
|
|
|
849 |
for (var i = 0; i < colors.length; i++) {
|
|
|
850 |
colors[i] = ColorScale.rgbToArray(colors[i]);
|
|
|
851 |
}
|
|
|
852 |
this.colors = colors;
|
|
|
853 |
},
|
|
|
854 |
|
|
|
855 |
setNormalizeFunction: function (f) {
|
|
|
856 |
if (f === 'polynomial') {
|
|
|
857 |
this.normalize = function (value) {
|
|
|
858 |
return Math.pow(value, 0.2);
|
|
|
859 |
};
|
|
|
860 |
}
|
|
|
861 |
else if (f === 'linear') {
|
|
|
862 |
delete this.normalize;
|
|
|
863 |
} else {
|
|
|
864 |
this.normalize = f;
|
|
|
865 |
}
|
|
|
866 |
this.setMin(this.clearMinValue);
|
|
|
867 |
this.setMax(this.clearMaxValue);
|
|
|
868 |
},
|
|
|
869 |
|
|
|
870 |
getColor: function (value) {
|
|
|
871 |
if (typeof this.normalize === 'function') {
|
|
|
872 |
value = this.normalize(value);
|
|
|
873 |
}
|
|
|
874 |
|
|
|
875 |
var lengthes = [];
|
|
|
876 |
var fullLength = 0;
|
|
|
877 |
var l;
|
|
|
878 |
|
|
|
879 |
for (var i = 0; i < this.colors.length - 1; i++) {
|
|
|
880 |
l = this.vectorLength(this.vectorSubtract(this.colors[i + 1], this.colors[i]));
|
|
|
881 |
lengthes.push(l);
|
|
|
882 |
fullLength += l;
|
|
|
883 |
}
|
|
|
884 |
|
|
|
885 |
var c = (this.maxValue - this.minValue) / fullLength;
|
|
|
886 |
|
|
|
887 |
for (i = 0; i < lengthes.length; i++) {
|
|
|
888 |
lengthes[i] *= c;
|
|
|
889 |
}
|
|
|
890 |
|
|
|
891 |
i = 0;
|
|
|
892 |
value -= this.minValue;
|
|
|
893 |
|
|
|
894 |
while (value - lengthes[i] >= 0) {
|
|
|
895 |
value -= lengthes[i];
|
|
|
896 |
i++;
|
|
|
897 |
}
|
|
|
898 |
|
|
|
899 |
var color;
|
|
|
900 |
if (i == this.colors.length - 1) {
|
|
|
901 |
color = this.vectorToNum(this.colors[i]).toString(16);
|
|
|
902 |
} else {
|
|
|
903 |
color = (this.vectorToNum(this.vectorAdd(this.colors[i], this.vectorMult(this.vectorSubtract(this.colors[i + 1], this.colors[i]), (value) / (lengthes[i]))))).toString(16);
|
|
|
904 |
}
|
|
|
905 |
|
|
|
906 |
while (color.length < 6) {
|
|
|
907 |
color = '0' + color;
|
|
|
908 |
}
|
|
|
909 |
return '#' + color;
|
|
|
910 |
},
|
|
|
911 |
|
|
|
912 |
vectorToNum: function (vector) {
|
|
|
913 |
var num = 0;
|
|
|
914 |
for (var i = 0; i < vector.length; i++) {
|
|
|
915 |
num += Math.round(vector[i]) * Math.pow(256, vector.length - i - 1);
|
|
|
916 |
}
|
|
|
917 |
return num;
|
|
|
918 |
},
|
|
|
919 |
|
|
|
920 |
vectorSubtract: function (vector1, vector2) {
|
|
|
921 |
var vector = [];
|
|
|
922 |
for (var i = 0; i < vector1.length; i++) {
|
|
|
923 |
vector[i] = vector1[i] - vector2[i];
|
|
|
924 |
}
|
|
|
925 |
return vector;
|
|
|
926 |
},
|
|
|
927 |
|
|
|
928 |
vectorAdd: function (vector1, vector2) {
|
|
|
929 |
var vector = [];
|
|
|
930 |
for (var i = 0; i < vector1.length; i++) {
|
|
|
931 |
vector[i] = vector1[i] + vector2[i];
|
|
|
932 |
}
|
|
|
933 |
return vector;
|
|
|
934 |
},
|
|
|
935 |
|
|
|
936 |
vectorMult: function (vector, num) {
|
|
|
937 |
var result = [];
|
|
|
938 |
for (var i = 0; i < vector.length; i++) {
|
|
|
939 |
result[i] = vector[i] * num;
|
|
|
940 |
}
|
|
|
941 |
return result;
|
|
|
942 |
},
|
|
|
943 |
|
|
|
944 |
vectorLength: function (vector) {
|
|
|
945 |
var result = 0;
|
|
|
946 |
for (var i = 0; i < vector.length; i++) {
|
|
|
947 |
result += vector[i] * vector[i];
|
|
|
948 |
}
|
|
|
949 |
return Math.sqrt(result);
|
|
|
950 |
}
|
|
|
951 |
};
|
|
|
952 |
|
|
|
953 |
ColorScale.arrayToRgb = function (ar) {
|
|
|
954 |
var rgb = '#';
|
|
|
955 |
var d;
|
|
|
956 |
for (var i = 0; i < ar.length; i++) {
|
|
|
957 |
d = ar[i].toString(16);
|
|
|
958 |
rgb += d.length == 1 ? '0' + d : d;
|
|
|
959 |
}
|
|
|
960 |
return rgb;
|
|
|
961 |
};
|
|
|
962 |
|
|
|
963 |
ColorScale.rgbToArray = function (rgb) {
|
|
|
964 |
rgb = rgb.substr(1);
|
|
|
965 |
return [parseInt(rgb.substr(0, 2), 16), parseInt(rgb.substr(2, 2), 16), parseInt(rgb.substr(4, 2), 16)];
|
|
|
966 |
};
|
|
|
967 |
|
|
|
968 |
})(jQuery);
|