1/** 2 * mapSvg 5.5.18 - Interactive Map Plugin 3 * 4 * Author - Roman S. Stepanov 5 * http://codecanyon.net/user/Yatek/portfolio?ref=Yatek 6 * 7 * Version : 5.5.18 8 * Released: Deember 7, 2013 9 * 10 * You must purchase Regular or Extended license to use mapSvg plugin. 11 * Visit plugin's page @ CodeCanyon: http://codecanyon.net/item/jquery-interactive-svg-map-plugin/1694201 12 * Licenses: http://codecanyon.net/licenses/regular_extended 13 */ 14 15 (function( $ ) { 16 17 var instances = {}, 18 globalID = 0, 19 userAgent = navigator.userAgent.toLowerCase(); 20 21 // Get plugin's path 22 var scripts = document.getElementsByTagName('script'); 23 var myScript = scripts[scripts.length - 1].src.split('/'); 24 myScript.pop(); 25 var pluginJSURL = myScript.join('/')+'/'; 26 myScript.pop(); 27 var pluginRootURL = myScript.join('/')+'/'; 28 29 // Check for iPad/Iphone/Andriod 30 var touchDevice = 31 (userAgent.indexOf("ipad") > -1) || 32 (userAgent.indexOf("iphone") > -1) || 33 (userAgent.indexOf("ipod") > -1) || 34 (userAgent.indexOf("android") > -1); 35 36 var _browser = {}; 37 38 _browser.ie = userAgent.indexOf("msie") > -1 ? {} : false; 39 if(_browser.ie) 40 _browser.ie.old = (navigator.userAgent.match(/MSIE [6-8]/) !== null); 41 42 _browser.firefox = userAgent.indexOf("firefox") > -1; 43 44 if (!String.prototype.trim) { 45 String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g, '');}; 46 } 47 48 49 // Create function for retrieving mouse coordinates 50 if (touchDevice){ 51 var mouseCoords = function(e){ 52 return e.touches[0] ? 53 {'x':e.touches[0].pageX, 'y':e.touches[0].pageY} : 54 {'x':e.changedTouches[0].pageX, 'y':e.changedTouches[0].pageY}; 55 }; 56 }else{ 57 var mouseCoords = function(e){ 58 59 //return e.pageX ? 60 //{'x':e.pageX, 'y':e.pageY} : 61 //{'x':e.clientX + $('html').scrollLeft(), 'y':e.clientY + $('html').scrollTop()}; 62 return {'x':e.clientX + $(window).scrollLeft(), 'y':e.clientY + $(window).scrollTop()}; 63 64 }; 65 } 66 67 // This data is needed for lat-lon to x-y conversions 68 var CBK = [128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296, 8589934592, 17179869184, 34359738368, 68719476736, 137438953472] 69 var CEK = [0.7111111111111111, 1.4222222222222223, 2.8444444444444446, 5.688888888888889, 11.377777777777778, 22.755555555555556, 45.51111111111111, 91.02222222222223, 182.04444444444445, 364.0888888888889, 728.1777777777778, 1456.3555555555556, 2912.711111111111, 5825.422222222222, 11650.844444444445, 23301.68888888889, 46603.37777777778, 93206.75555555556, 186413.51111111112, 372827.02222222224, 745654.0444444445, 1491308.088888889, 2982616.177777778, 5965232.355555556, 11930464.711111112, 23860929.422222223, 47721858.844444446, 95443717.68888889, 190887435.37777779, 381774870.75555557, 763549741.5111111] 70 var CFK = [40.74366543152521, 81.48733086305042, 162.97466172610083, 325.94932345220167, 651.8986469044033, 1303.7972938088067, 2607.5945876176133, 5215.189175235227, 10430.378350470453, 20860.756700940907, 41721.51340188181, 83443.02680376363, 166886.05360752725, 333772.1072150545, 667544.214430109, 1335088.428860218, 2670176.857720436, 5340353.715440872, 10680707.430881744, 21361414.86176349, 42722829.72352698, 85445659.44705395, 170891318.8941079, 341782637.7882158, 683565275.5764316, 1367130551.1528633, 2734261102.3057265, 5468522204.611453, 10937044409.222906, 21874088818.445812, 43748177636.891624] 71 72 // Default options 73 var defaults = { 74 keepSourceStyles : false, 75 loadingText : 'Harita Yükleniyor...', 76 //colors : {base: "#E1F1F1", background: "#eeeeee", hover: "#548eac", selected: "#065A85", stroke: "#7eadc0"}, 77 colors: { background: "#4b566c", selected: 5, hover: 2, base: "#FFFFFF", hover: "#FFFFFF", stroke: "#000000" }, 78 regions : {},
79 viewBox : [], 80 cursor : 'pointer', 81 scale : 1, 82 tooltipsMode : 'hover', 83 tooltips : {show: 'hover', mode: 'names'}, 84 onClick : null, 85 mouseOver : null, 86 mouseOut : null, 87 disableAll : false, 88 hideAll : false, 89 marks : null, 90 hover_mode : 'brightness', 91 selected_mode : 'brightness', 92 hover_brightness : 1, 93 selected_brightness : 5, 94 pan : false, 95 panLimit : true, 96 panBackground : false, 97 zoom : false, 98 popover : {width: 'auto', height: 'auto'}, 99 buttons : true, 100 zoomLimit : [0,5], 101 zoomDelta : 1.2, 102 zoomButtons : {'show': true, 'location': 'right'}, 103 multiSelect : false 104 105 }; 106 107 // Default mark style 108 var markOptions = {attrs: {'cursor': 'pointer', 'src': pluginRootURL+'markers/_pin_default.png'}}; 109 110 111/** Main Class **/ 112var mapSVG = function(elem, options){ 113 114 var _data; 115 116 this.methods = { 117 118 119 // destroy 120 destroy : function(){ 121 delete instances[_data.$map.attr('id')]; 122 _data.$map.empty(); 123 return _this; 124 }, 125 getData : function(){ 126 return _data; 127 }, 128 // GET SCALE VALUE 129 getScale: function(){ 130 131 var ratio_def = _data.svgDefault.width / _data.svgDefault.height; 132 var ratio_new = _data.options.width / _data.options.height; 133 var scale1, scale2; 134 135 var size = _data.options.responsive ? [_data.$map.width(), _data.$map.height()] : [_data.options.width, _data.options.height]; 136 137 if(ratio_new < ratio_def ){ 138 // Calculate scale by height 139 scale1 = _data.svgDefault.width / _data.svgDefault.viewBox[2]; 140 scale2 = size[0] / _data.viewBox[2]; 141 }else{ 142 // Calculate scale by width 143 scale1 = _data.svgDefault.height / _data.svgDefault.viewBox[3]; 144 scale2 = size[1] / _data.viewBox[3]; 145 } 146 147 return (1 - (scale1-scale2)); 148 }, 149 fluidResize : function(w,h){ 150 151 if(!w || !h){ 152 w = _data.$map.width(); 153 h = _data.$map.height(); 154 } 155 156 _data.R.setSize(w,h); 157 158 _data.scale = _this.getScale(); 159 _this.marksAdjustPosition(); 160 161 //_data.R.setViewBox(_data.viewBox[0], _data.viewBox[1], _data.viewBox[2], _data.viewBox[3], true); 162 }, 163 // GET VIEBOX [x,y,width,height] 164 getViewBox : function(){ 165 return _data.viewBox; 166 }, 167 // SET VIEWBOX 168 setViewBox : function(v){ 169 170 if(typeof v == 'string'){ 171 var coords = _data.R.getById(v).getBBox(); 172 _data.viewBox = [coords.x-5, coords.y-5, coords.width+10, coords.height+10]; 173 var isZooming = true; 174 }else{ 175 var d = (v && v.length==4) ? v : _data.svgDefault.viewBox; 176 var isZooming = parseInt(d[2]) != _data.viewBox[2] || parseInt(d[3]) != _data.viewBox[3]; 177 _data.viewBox = [parseFloat(d[0]), parseFloat(d[1]), parseFloat(d[2]), parseFloat(d[3])]; 178 } 179 /* 180 var vbRatio = _data.viewBox[2]/_data.viewBox[3]; 181 var whRatio = _data.options.width / _data.options.height; 182 183 if( vbRatio != whRatio ){ 184 if(vbRatio>whRatio){ // add height to VB 185 var newvb3 = _data.viewBox[2] / whRatio; 186 _data.viewBox[1] -= (newvb3-_data.viewBox[3])/2; 187 _data.viewBox[3] = newvb3; 188 }else{ // add width to VB
189 var newvb2 = _data.viewBox[3] * whRatio; 190 _data.viewBox[0] -= (newvb2 - _data.viewBox[2])/2; 191 _data.viewBox[2] = newvb2; 192 } 193 } 194 */ 195 196 197 _data.R.setViewBox(_data.viewBox[0], _data.viewBox[1], _data.viewBox[2], _data.viewBox[3], true); 198 199 if(isZooming){ 200 _data.scale = _this.getScale(); 201 _this.marksAdjustPosition(); 202 if((_browser.ie && !_browser.ie.old) || _browser.firefox){ 203 _this.mapAdjustStrokes(); 204 } 205 206 } 207 208 return true; 209 }, 210 // SET VIEWBOX BY SIZE 211 viewBoxSetBySize : function(width,height){ 212 213 _data._viewBox = _this.viewBoxGetBySize(width,height); 214 _data.viewBox = $.extend([],_data._viewBox); 215 _data.scale = _this.getScale(); 216 217 _data.R.setViewBox(_data.viewBox[0], _data.viewBox[1], _data.viewBox[2], _data.viewBox[3], true); 218 219 _this.marksAdjustPosition(); 220 221 return _data.viewBox; 222 },
223 viewBoxGetBySize : function(width, height){ 224 225 226 var new_ratio = width / height; 227 var old_ratio = _data.svgDefault.viewBox[2] / _data.svgDefault.viewBox[3]; 228 229 var vb = $.extend([],_data.svgDefault.viewBox); 230 231 if (new_ratio != old_ratio){ 232 vb[2] = width*_data.svgDefault.viewBox[2] / _data.svgDefault.width; 233 vb[3] = height*_data.svgDefault.viewBox[3] / _data.svgDefault.height; 234 235 } 236 237 return vb; 238 }, 239 viewBoxReset : function(){ 240 _this.setViewBox(); 241 }, 242 mapAdjustStrokes : function(){ 243 _data.R.forEach(function(region){ 244 if(region.default_attr && region.default_attr['stroke-width']) 245 region.attr( {'stroke-width': region.default_attr['stroke-width'] / _data.scale } ); 246 }); 247 }, 248 // ZOOM 249 zoomIn: function(){ 250 _this.zoom(1); 251 }, 252 zoomOut: function(){ 253 _this.zoom(-1); 254 }, 255 touchZoomStart : function (touchScale){ 256 257 touchZoomStart = _data._scale; 258 _data.scale = _data.scale * zoom_k; 259 zoom = _data._scale; 260 _data._scale = _data._scale * zoom_k; 261 262 263 var vWidth = _data.viewBox[2]; 264 var vHeight = _data.viewBox[3]; 265 var newViewBox = []; 266 267 newViewBox[2] = _data._viewBox[2] / _data._scale; 268 newViewBox[3] = _data._viewBox[3] / _data._scale; 269 270 newViewBox[0] = _data.viewBox[0] + (vWidth - newViewBox[2]) / 2; 271 newViewBox[1] = viewBox[1] + (vHeight - newViewBox[3]) / 2; 272 273 _this.setViewBox(newViewBox, true); 274 275 }, 276 touchZoomMove : function(){ 277 278 }, 279 touchZoomEnd : function(){ 280 281 }, 282 zoom : function (delta, exact){ 283 284 var vWidth = _data.viewBox[2]; 285 var vHeight = _data.viewBox[3]; 286 var newViewBox = []; 287 288 if(!exact){ 289 // check for zoom limit 290 var d = delta > 0 ? 1 : -1; 291 _data._zoomLevel = _data.zoomLevel; 292 _data._zoomLevel += d; 293 if(_data._zoomLevel > _data.options.zoomLimit[1] || _data._zoomLevel < _data.options.zoomLimit[0]) return false; 294 295 _data.zoomLevel = _data._zoomLevel; 296 297 var zoom_k = d * _data.options.zoomDelta; 298 if (zoom_k < 1) zoom_k = -1/zoom_k; 299 300 _data._scale = _data._scale * zoom_k; 301 newViewBox[2] = _data._viewBox[2] / _data._scale; 302 newViewBox[3] = _data._viewBox[3] / _data._scale; 303 }else{ 304 _data._scale = exact; 305 newViewBox[2] = _data.touchZoomStartViewBox[2] / _data._scale; 306 newViewBox[3] = _data.touchZoomStartViewBox[3] / _data._scale; 307 } 308 309 newViewBox[0] = _data.viewBox[0] + (vWidth - newViewBox[2]) / 2; 310 newViewBox[1] = _data.viewBox[1] + (vHeight - newViewBox[3]) / 2; 311 312 _this.setViewBox(newViewBox, true); 313 }, 314 // MARK : UPDATE 315 markUpdate : function(mark, data){ 316 317 if(data.attrs['src']=="") 318 delete data.attrs['src']; 319 if(data.attrs['href']=="") 320 delete data.attrs['href']; 321 322 var img = new Image(); 323 324 img.onload = function(){ 325 326 data.data.width = this.width; 327 data.data.height = this.height; 328 data.attrs.width = parseFloat(data.data.width/_data.scale).toFixed(2); 329 data.attrs.height = parseFloat(data.data.height/_data.scale).toFixed(2); 330 331 // we don't want href to be active in edit mode 332 if(_data.options.editMode && data.attrs.href){ 333 mark.data('href',data.attrs.href); 334 delete data.attrs.href; 335 }else if(_data.options.editMode && !data.attrs.href){ 336 mark.removeData('href'); 337 } 338 339 mark.data(data.data); 340 mark.attr(data.attrs); 341 }; 342 343 img.src = data.attrs.src; 344 345 }, 346 // MARK : DELETE 347 markDelete: function(mark){ 348 mark.remove(); 349 }, 350 // MARK : ADD 351 markAdd : function(opts, create) { 352 353 // Join default mark options with user-defined options 354 var mark = $.extend(true, {}, markOptions, opts); 355 356 357 if (mark.width && mark.height){ 358 359 return _this.markAddFinalStep(mark, create); 360 361 }else{ 362 363 var img = new Image(); 364 365 366 img.onload = function(){ 367 368 mark.width = this.width; 369 mark.height = this.height; 370 371 return _this.markAddFinalStep(mark, create); 372 }; 373 374 img.src = mark.attrs.src; 375 } 376 }, 377 markAddFinalStep : function(mark, create){ 378 // We don't need to open a link in edit mode 379 var markAttrs = $.extend(true, {}, mark.attrs); 380 381 var width = parseFloat(mark.width/_data.scale).toFixed(2); 382 var height = parseFloat(mark.height/_data.scale).toFixed(2); 383 384 385 // Get mark's xy OR convert lat/lon to x/y
386 var xy = mark.xy ? mark.xy : 387 (mark.attrs.x ? [mark.attrs.x, mark.attrs.y] : 388 (mark.c ? _this.ll2px(mark) : false) 389 ); 390 391 if(!xy) return false; 392 393 if(create){ 394 xy[0] = xy[0]/_data.scale - mark.width/(2*_data.scale) + (_data.viewBox[0] - _data._viewBox[0]); 395 xy[1] = (xy[1]-mark.height)/_data.scale + (_data.viewBox[1] - _data._viewBox[1]); 396 xy = _this.markGetDefaultCoords(xy[0],xy[1],mark.width,mark.height,this.getScale()); 397 } 398 399 xy[0] = parseFloat(xy[0]).toFixed(4); 400 xy[1] = parseFloat(xy[1]).toFixed(4); 401 402 //if(_data.options.editMode) 403 // delete markAttrs.href; 404 // we don't want href to be active in edit mode 405 if(_data.options.editMode && markAttrs.href){ 406 mark.href = markAttrs.href; 407 delete markAttrs.href; 408 } 409 410 411 delete markAttrs.width; 412 delete markAttrs.height; 413 414 415 // Add mark (image) 416 var RMark = _data.R.image(mark.attrs.src, xy[0], xy[1], width, height) 417 .attr(markAttrs) 418 .data(mark); 419 RMark.mapsvg_type = 'mark'; 420 421 422 if(mark.id) 423 RMark.node.id = mark.id; 424 425 if(!_data.options.editMode){ 426 if(!touchDevice){ 427 RMark.mousedown(function(e){ 428 console.log('mark clicked'); 429 console.log(this.data('popover')); 430 if(this.data('popover')){ 431 432 _this.showPopover(e, this.data('popover')); 433 } 434 if(_data.options.onClick) 435 return _data.options.onClick.call(this, e, _this); 436 437 }); 438 439 if(_data.options.mouseOver){ 440 RMark.mouseover(function(e){ 441 return _data.options.mouseOver.call(this, e, _this); 442 }); 443 } 444 if(_data.options.mouseOut){ 445 RMark.mouseout(function(e){ 446 return _data.options.mouseOver.call(this, e, _this); 447 }); 448 } 449 450 }else{ 451 RMark.touchstart(function(e){ 452 if(this.attrs.href){ 453 window.location.href = this.attrs.href; 454 }else if(this.data('popover')){ 455 _this.showPopover(e, this.data('popover')); 456 } 457 if(_data.options.onClick) 458 return _data.options.onClick.call(this, e, _this); 459 460 }); 461 } 462 } 463 464 _this.markEventHandlersSet(_data.options.editMode, RMark); 465 _data.RMarks.push(RMark); 466 467 468 // Call edit window 469 if(create) 470 _data.options.marksEditHandler.call(RMark); 471 472 _this.markAdjustPosition(RMark); 473 474 475 return RMark; 476 477 }, 478 marksAdjustPosition : function(mark){ 479 480 if(!mark && (!_data.RMarks || _data.RMarks.length < 1)) return false; 481 482 // We want a marker "tip" to be on bottom side (like a pin) 483 // But Raphael starts to draw an image from left top corner. 484 // At the same time we don't want a mark to be scaled in size when map scales; 485 // Mark always should stay the same size. 486 // In this case coordinates of bottom point of image will vary with map scaling. 487 // So we have to calculate the offset. 488 489 var dx, dy; 490 491 for (var m in _data.RMarks.items){ 492 var w = _data.RMarks.items[m].data('width'); 493 var h = _data.RMarks.items[m].data('height'); 494 dx = w/2 - w/(2*_data.scale); 495 dy = h - h/_data.scale; 496 if(_browser.ie){ 497 w = parseInt(w); 498 h = parseInt(h); 499 } 500 501 _data.RMarks.items[m].attr({width: w/_data.scale, height: h/_data.scale}).transform('t'+dx+','+dy); 502 } 503 504 }, 505 markAdjustPosition : function(mark){ 506 var w = mark.data('width'); 507 var h = mark.data('height'); 508 var dx = w/2 - w/(2*_data.scale); 509 var dy = h - h/_data.scale; 510 mark.attr({width: w/(_data.scale), height: h/(_data.scale)}).transform('t'+dx+','+dy); 511 }, 512 // GET MARK COORDINATES TRANSLATED TO 1:1 SCALE (used when saving new added marks) 513 markGetDefaultCoords : function(markX, markY, markWidth, markHeight, mapScale){ 514 markX = parseFloat(markX); 515 markY = parseFloat(markY); 516 markWidth = parseFloat(markWidth); 517 markHeight = parseFloat(markHeight); 518 markX = parseFloat(markX + markWidth/(2*mapScale) - markWidth/2).toFixed(2); 519 markY = parseFloat(markY + markHeight/mapScale - markHeight).toFixed(2); 520 return [markX, markY]; 521 }, 522 // MARK MOVE & EDIT HANDLERS 523 markMoveStart : function(){ 524 // storing original coordinates 525 this.data('ox', parseFloat(this.attr('x'))); 526 this.data('oy', parseFloat(this.attr('y'))); 527 }, 528 markMove : function (dx, dy) { 529 dx = dx/_data.scale; 530 dy = dy/_data.scale; 531 this.attr({x: this.data('ox') + dx, y: this.data('oy') + dy}); 532 }, 533 markMoveEnd : function () { 534 // if coordinates are same then it was a "click" and we should start editing 535 if(this.data('ox') == this.attr('x') && this.data('oy') == this.attr('y')){ 536 options.marksEditHandler.call(this); 537 } 538 }, 539 panStart : function (e){ 540 541 542 if(e.target.id == 'btnZoomIn' || e.target.id == 'btnZoomOut') 543 return false; 544 545 if(_data.options.editMode && e.target.nodeName == "image") 546 return false; 547 548 e.preventDefault(); 549 var ce = e.touches && e.touches[0] ? e.touches[0] : e; 550 551 _data.pan = {}; 552 553 // initial viewbox when panning started 554 _data.pan.vxi = _data.viewBox[0]; 555 _data.pan.vyi = _data.viewBox[1]; 556 // mouse coordinates when panning started 557 _data.pan.x = ce.clientX; 558 _data.pan.y = ce.clientY; 559 // mouse delta 560 _data.pan.dx = 0; 561 _data.pan.dy = 0; 562 // new viewbox x/y 563 _data.pan.vx = 0; 564 _data.pan.vy = 0; 565 566 if(!touchDevice) 567 $('body').on('mousemove', _this.panMove).on('mouseup', _this.panEnd); 568 }, 569 panMove : function (e){ 570 571 e.preventDefault(); 572 573 _data.isPanning = true; 574 575 _data.RMap.attr({'cursor': 'move'}); 576 $('body').css({'cursor': 'move'}); 577 578 var ce = e.touches && e.touches[0] ? e.touches[0] : e; 579 580 // delta x/y 581 _data.pan.dx = (_data.pan.x - ce.clientX); 582 _data.pan.dy = (_data.pan.y - ce.clientY); 583 584 // new viewBox x/y 585 var vx = parseInt(_data.pan.vxi + _data.pan.dx /_data.scale); 586 var vy = parseInt(_data.pan.vyi + _data.pan.dy /_data.scale); 587 588 // Limit pan to map's boundaries 589 if(_data.options.panLimit){ 590 if(vx < _data.svgDefault.viewBox[0]) 591 vx = _data.svgDefault.viewBox[0]; 592 else if(_data.viewBox[2] + vx > _data.svgDefault.viewBox[2]) 593 vx = _data.svgDefault.viewBox[2]-_data.viewBox[2]; 594 595 if(vy < _data.svgDefault.viewBox[1]) 596 vy = _data.svgDefault.viewBox[1]; 597 else if(_data.viewBox[3] + vy > _data.svgDefault.viewBox[3]) 598 vy = _data.svgDefault.viewBox[3]-_data.viewBox[3]; 599 } 600 601 _data.pan.vx = vx; 602 _data.pan.vy = vy; 603 604 605 // set new viewBox 606 _this.setViewBox([_data.pan.vx, _data.pan.vy, _data.viewBox[2], _data.viewBox[3]]); 607 //_data.$map.css({'-webkit-transform' : 'translate('+vx+'px,'+vy+'px'}); 608 609 }, 610 panEnd : function (e){ 611 612 _data.isPanning = false; 613 614 // call regionClickHandler if mouse did not move more than 5 pixels 615 if (Math.abs(_data.pan.dx)<5 && Math.abs(_data.pan.dy)<5){ 616 if(_data.options.editMode) 617 _this.markAddClickHandler(e); 618 if(_data.region_clicked) 619 _this.regionClickHandler(e, _data.region_clicked); 620 } 621 622 623 $('body').css({'cursor': 'default'}); 624 _data.RMap.attr({'cursor': _data.options.cursor}); 625 626 _data.viewBox[0] = _data.pan.vx || _data.viewBox[0]; 627 _data.viewBox[1] = _data.pan.vy || _data.viewBox[1] ; 628 629 if(!touchDevice) 630 $('body').off('mousemove', _this.panMove).off('mouseup', _this.panEnd); 631 }, 632 // REMEMBER WHICH REGION WAS CLICKED BEFORE START PANNING 633 panRegionClickHandler : function (e, region) { 634 _data.region_clicked = region; 635 }, 636 touchStart : function (e){ 637 e.preventDefault(); 638 if(_data.options.zoom && e.touches && e.touches.length == 2){ 639 _data.touchZoomStartViewBox = _data.viewBox; 640 _data.touchZoomStart = _data.scale; 641 _data.touchZoomEnd = 1; 642 }else{ 643 _this.panStart(e); 644 _data.isPanning = true; 645 } 646 }, 647 touchMove : function (e){ 648 e.preventDefault(); 649 if(_data.options.zoom && e.touches && e.touches.length >= 2){ 650 _this.zoom(null, e.scale); 651 _data.isPanning = false; 652 }else if(_data.isPanning){ 653 _this.panMove(e); 654 } 655 }, 656 touchEnd : function (e){ 657 e.preventDefault(); 658 if(_data.touchZoomStart){ 659 _data.touchZoomStart = false; 660 _data.touchZoomEnd = false; 661 }else if(_data.isPanning){ 662 _this.panEnd(e); 663 } 664 }, 665 marksHide : function(){ 666 _data.RMarks.hide(); 667 }, 668 marksShow : function(){ 669 _data.RMarks.show(); 670 }, 671 // GET ALL MARKS 672 marksGet : function(){ 673 var _marks = []; 674 $.each(_data.RMarks, function(i, m){ 675 if(m.attrs){ 676 // If mark exist 677 var attrs = $.extend({},m.attrs); 678 /* 679 if(!m.data('placed')){ 680 var xy = _this.markGetDefaultCoords(m.attrs.x, m.attrs.y, m.data('width'), m.data('height'), _data.scale); 681 attrs.x = xy[0]; 682 attrs.y = xy[1]; 683 } 684 */ 685 686 if(m.data('href')) 687 attrs.href = m.data('href'); 688 689 _marks.push({ 690 attrs: attrs, 691 tooltip: m.data('tooltip'), 692 popover: m.data('popover'), 693 width: m.data('width'), 694 height: m.data('height'), 695 href: m.data('href') 696 //placed: true 697 }); 698 } 699 }); 700 return _marks; 701 }, 702 // GET SELECTED REGION OR ARRAY OF SELECTED REGIONS 703 getSelected : function(){ 704 return _data.selected_id; 705 }, 706 // SELECT REGION 707 selectRegion : function(id){ 708 var region = _data.R.getById(id); 709 if(!region || region.disabled) return false; 710 711 if(_data.options.multiSelect){ 712 // if multi select is ON 713 var i = $.inArray(id, _data.selected_id); 714 715 if(i >= 0){ 716 // if selected, deselect 717 region.attr({'fill' : region.default_attr.fill}); 718 _data.selected_id.splice(i,1); 719 return; 720 }else{ 721 // select 722 _data.selected_id.push(id); 723 } 724 }else{ 725 // single select 726 if(_data.selected_id){ 727 var selectedRegion = _data.R.getById(_data.selected_id); 728 selectedRegion.attr(selectedRegion.default_attr); 729 if(_browser.ie && !_browser.ie.old) 730 _this.mapAdjustStrokes(); 731 } 732 _data.selected_id = id; 733 } 734 735 region.attr(region.selected_attr); 736 }, 737 // UNHIGHLIGHT REGION 738 unhighlightRegion : function(id){ 739 var region = _data.R.getById(id); 740 if(region.disabled 741 || (_data.options.multiSelect && $.inArray(id,_data.selected_id)>=0) 742 || _data.selected_id == id 743 ) return false; 744 745 region.attr({'fill' : region.default_attr.fill}); 746 }, 747 // HIGHLIGHT REGION 748 highlightRegion : function(id){ 749 var region = _data.R.getById(id); 750 if(_data.isPanning 751 || region.disabled 752 || (_data.options.multiSelect && $.inArray(id,_data.selected_id)>=0) 753 || _data.selected_id == id 754 ) 755 return false; 756 757 region.attr(region.hover_attr); 758 }, 759 // CONVERT LAT/LON TO X/Y (works only with world_high.svg map!) 760 ll2px : function(mark){ 761 762 var latlng = mark.c; 763 764 var lat = parseFloat(latlng[0]); 765 var lng = parseFloat(latlng[1]); 766 767 var czoom = 2; 768 769 var cbk = CBK[czoom]; 770 //var scale = options.width/1024; 771 var scale_ = 1; 772 773 var x = Math.round(cbk + (lng * CEK[czoom])); 774 775 var foo = Math.sin(lat * 3.14159 / 180) 776 if (foo < -0.9999)
777 foo = -0.9999; 778 else if (foo > 0.9999) 779 foo = 0.9999; 780 781 var y = Math.round(cbk + (0.5 * Math.log((1+foo)/(1-foo)) * (-CFK[czoom]))); 782 783 var coordsXY = [x-(33.8+(mark.width/2)), y-(141.7+mark.height)]; 784 785 return coordsXY; 786 }, 787 // CHECK IF REGION IS DISABLED 788 isRegionDisabled : function (name, svgfill){ 789 790 if(_data.options.regions[name] && (_data.options.regions[name].disabled || svgfill == 'none') ){ 791 return true; 792 }else if( 793 (_data.options.regions[name] == undefined || _this.parseBoolean(_data.options.regions[name].disabled)) && 794 (_data.options.disableAll || svgfill == 'none' || name == 'labels' || name == 'Labels') 795 796 ){ 797 return true; 798 }else{ 799 return false; 800 } 801 }, 802 regionClickHandler : function(e, region){ 803 804 if(!region) return false; 805 806 _data.region_clicked = null; 807 _this.selectRegion(region.name); 808 809 _this.showPopover(e, region.popover); 810 811 if(_data.options.onClick) 812 return _data.options.onClick.call(region, e, _this); 813 814 if(touchDevice && region.attrs.href) 815 window.location.href = region.attrs.href; 816 817 }, 818 renderSVGPath : function (item, parentTransform, parentStyle){ 819 820 var path = _data.R.path($(item).attr('d')); 821 var rObj = _this.initRaphaelObject( path, item, parentTransform, parentStyle); 822 823 _this.regionAdd(rObj); 824 }, 825 renderSVGImage: function (item, parentTransform, parentStyle){ 826 827 var src = $(item).attr('xlink:href'), 828 x = $(item).attr('x') || 0, 829 y = $(item).attr('y') || 0, 830 w = $(item).attr('width') || 0, 831 h = $(item).attr('height') || 0; 832 833 if (!_this.fileExists(src)) 834 return false; 835 836 var rObj = _data.R.image(src, x, y, w, h) 837 _this.initRaphaelObject( rObj, item, parentTransform, parentStyle ); 838 return rObj; 839 }, 840 renderSVGPolygon : function (item, parentTransform, parentStyle){ 841 //var points = item.getAttribute('points').trim().replace(/ +(?= )/g,'').split(/\s+|,/); 842 var points = item.attr('points').trim().replace(/ +(?= )/g,'').split(/\s+|,/); 843 var x0 = points.shift(), 844 y0 = points.shift(); 845 var pathdata = 'M'+x0+','+y0+' L'+points.join(' ')+'z'; 846 var rObj = _this.initRaphaelObject( _data.R.path(pathdata), item, parentTransform, parentStyle); 847 _this.regionAdd(rObj); 848 return rObj; 849 }, 850 renderSVGPolyline : function (item, parentTransform, parentStyle){ 851 //var points = item.getAttribute('points').trim().replace(/ +(?= )/g,'').split(/\s+|,/); 852 var points = item.attr('points').trim().replace(/ +(?= )/g,'').split(/\s+|,/); 853 var x0 = points.shift(), 854 y0 = points.shift(); 855 var pathdata = 'M'+x0+','+y0+' L'+points.join(' '); 856 var rObj = _this.initRaphaelObject( _data.R.path(pathdata), item, parentTransform, parentStyle); 857 return rObj; 858 }, 859 renderSVGCircle: function (item, parentTransform, parentStyle){ 860 var x = $(item).attr('cx') || 0, 861 y = $(item).attr('cy') || 0; 862 r = $(item).attr('r') || 0; 863 var rObj = _this.initRaphaelObject( _data.R.circle(x,y,r), item, parentTransform, parentStyle); 864 865 _this.regionAdd(rObj); 866 return rObj; 867 }, 868 renderSVGEllipse: function (item, parentTransform, parentStyle){ 869 var x = $(item).attr('cx') || 0, 870 y = $(item).attr('cy') || 0; 871 rx = $(item).attr('rx') || 0; 872 ry = $(item).attr('ry') || 0; 873 var rObj = _this.initRaphaelObject( _data.R.ellipse(x,y,rx,ry), item, parentTransform, parentStyle); 874 _this.regionAdd(rObj); 875 return rObj; 876 }, 877 renderSVGRect: function (item, parentTransform, parentStyle){ 878 var x = $(item).attr('x') || 0, 879 y = $(item).attr('y') || 0, 880 w = $(item).attr('width') || 0, 881 h = $(item).attr('height') || 0; 882 r = $(item).attr('rx') || $(item).attr('ry') || 0; 883 var rObj = _this.initRaphaelObject( _data.R.rect(x,y,w,h,r), item, parentTransform, parentStyle); 884 _this.regionAdd(rObj); 885 return rObj; 886 }, 887 renderSVGText : function (textObj){ 888 889 var tspans = $(textObj).find('tspan'); 890 891 var x = parseFloat($(textObj).attr('x')) || 0; 892 var y = parseFloat($(textObj).attr('y')) || 0; 893 894 tspans.each(function(i,tspan){ 895 var t = _this.renderSVGTspan($(tspan), {x: x, y: y}); 896 897 t.attr(_this.styleSVG2Raphael(textObj)); 898 t.attr(_this.styleSVG2Raphael($(tspan))); 899 900 t.transform( _this.transformSVG2Raphael(textObj) ); 901 t.transform( _this.transformSVG2Raphael($(tspan))); 902 903 }); 904 905 if(tspans.length == 0){ 906 var t = _this.renderSVGTspan(textObj); 907 t.attr(_this.styleSVG2Raphael(textObj)); 908 t.transform( _this.transformSVG2Raphael(textObj) ); 909 } 910 911 return t; 912 }, 913 renderSVGTspan : function (textObj, parent){ 914 915 parent = parent || {x: 0, y: 0}; 916 917 var x = parseFloat($(textObj).attr('x')) || parent.x; 918 var y = parseFloat($(textObj).attr('y')) || parent.y; 919 920 if($(textObj).attr('dx')) 921 x += parent.x + $(textObj).attr('dx'); 922 if($(textObj).attr('dy')) 923 y += parent.y + $(textObj).attr('dy'); 924 925 text = $(textObj).text(); 926 927 928 var rObj = _data.R.text(x, y, text).attr({'text-anchor': 'start'}).toFront(); 929 930 rObj.mapsvg_type = 'text'; 931 932 $(rObj.node).css({ 933 "-webkit-touch-callout": "none", 934 "-webkit-user-select": "none", 935 'pointer-events': 'none' 936 }); 937 return rObj; 938 },
939 initRaphaelObject : function (rObj, svgItem, parentTransform, parentStyle){ 940 941 var _parentStyle = parentStyle || {}; 942 var _parentTransform = parentTransform || ''; 943 944 rObj.id = $(svgItem).attr('id') || rObj.type+(globalID++); 945 rObj.node.id = rObj.id; 946 rObj.name = rObj.id; 947 948 var style = _this.styleSVG2Raphael(svgItem, parentStyle); 949 rObj.attr(style); 950 951 var transform = _this.transformSVG2Raphael(svgItem) + _parentTransform; 952 rObj.transform(transform); 953 954 return rObj; 955 }, 956 styleSVG2Raphael : function(svgItem, parentStyle){ 957 var parentStyle = parentStyle || {}; 958 var style = {}; 959 var attrs = $(svgItem).get(0).attributes; 960 var style_attrs = ["fill","fill-opacity","opacity", "font","font-name","font-family","font-size","font-weight","stroke","stroke-lincap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width"]; 961 962 if($(svgItem).attr('style')){ 963 var _style = $(svgItem).attr('style').split(';'); 964 $.each(_style, function(i, val){ 965 966 var p = val.split(':'); 967 p[0] = p[0].trim(); 968 if(p[1]) 969 p[1] = p[1].trim(); 970 if(p[0]=='font-size') 971 p[1] = parseInt(p[1].replace('px','')); 972 if(_this.isNumber(p[0])) 973 p[1] = parseFloat(p[1]); 974 style[p[0]] = p[1]; 975 }); 976 } 977 978 if(attrs) 979 $.each(attrs, function(i,attr){ 980 if ($.inArray(attr.name, style_attrs) > -1){ 981 if(attr.name=='font-size'){ 982 attr.value = parseInt(attr.value.replace('px','')); 983 } 984 style[attr.name] = attr.value; 985 } 986 }); 987 988 if(style['font-size']) 989 style['font-size'] = parseInt(style['font-size']); 990 991 992 if(style['font-family']) 993 style['font-family'] = style['font-family']+', Arial'; 994 995 996 // Combine with parent styles 997 var final_style = $.extend({}, parentStyle, style); 998 999 if(final_style['stroke']==undefined && final_style['fill']==undefined){ 1000 final_style['stroke'] = 'none'; 1001 //final_style['fill'] = "#000000"; 1002 final_style['fill'] = "none" 1003 }else if (final_style['stroke']==undefined){ 1004 final_style['stroke'] = 'none'; 1005 }else if(final_style['fill']==undefined){ 1006 final_style['fill'] = 'none'; 1007 } 1008 1009 return final_style; 1010 }, 1011 transformSVG2Raphael : function(svgItem){ 1012 1013 var _transform = $(svgItem).attr('transform'); 1014 var m; 1015 1016 if(_transform){ 1017 1018 var tparts = _transform.split(')'); 1019 var rtransform = []; 1020 1021 for (t in tparts){ 1022 if(tparts[t] != ""){ 1023 var kv = tparts[t].split('('); 1024 1025 if (kv[0]!='matrix'){ 1026 kv[0] = kv[0].slice(0,1).toLowerCase(); 1027 rtransform.push(kv[0]+kv[1]); 1028 }else{ 1029 1030 if( kv[1].indexOf(",") != -1 ) 1031 m = kv[1].split(','); 1032 else 1033 m = kv[1].split(' '); 1034 1035 var transform_string = Raphael.matrix(parseFloat(m[0]),parseFloat(m[1]),parseFloat(m[2]),parseFloat(m[3]),parseFloat(m[4]),parseFloat(m[5])).toTransformString();
1036 rtransform.push(transform_string); 1037 } 1038 } 1039 } 1040 1041 return rtransform.join(); 1042 } 1043 return ''; 1044 }, 1045 // GET ELEMENT'S STYLES (fill, strokes etc..) 1046 getElementStyles : function (elem){ 1047 if(!_browser.ie){ 1048 return elem.style; 1049 }else{ 1050 var styles = {}; 1051 styles.getPropertyValue = function(v){ 1052 return styles[v] || undefined; 1053 }; 1054 if($(elem).attr('style')){ 1055 var def_styles = $(elem).attr('style').split(';'); 1056 $.each(def_styles, function(i, val){ 1057 var p = val.split(':'); 1058 styles[p[0]] = p[1]; 1059 }); 1060 } 1061 return styles; 1062 } 1063 }, 1064 fileExists : function(url){ 1065 if(url.substr(0,4)=="data") 1066 return true; 1067 var http = new XMLHttpRequest(); 1068 http.open('HEAD', url, false); 1069 http.send(); 1070 return http.status!=404; 1071 }, 1072 // ADD REGION (PARSE SVG DATA) 1073 regionAdd : function (_item){ 1074 1075 var name = _item.name; 1076 1077 _item.disabled = _this.isRegionDisabled(name, _item.attr('fill')); 1078 _item.default_attr = {}; 1079 1080 _item.disabled && console.log(_data.options.colors.disabled); 1081 _item.default_attr['fill'] = _item.disabled && _data.options.colors.disabled ? _data.options.colors.disabled : (_item.attr('fill') || 'none'); 1082 1083 if(_item.default_attr['fill'] && _item.default_attr['fill'] != 'none' && _data.options.colors.base && !_item.disabled) 1084 _item.default_attr['fill'] = _data.options.colors.base; 1085 1086 if(_item.attr('stroke')) 1087 _item.default_attr['stroke'] = _item.attr('stroke'); 1088 1089 1090 if(_item.attr('stroke-width')) 1091 _item.default_attr['stroke-width'] = parseFloat(_item.attr('stroke-width')); 1092 1093 if(_item.default_attr['stroke'] && _item.default_attr['stroke'] != 'none' && _data.options.colors.stroke) 1094 _item.default_attr['stroke'] = _data.options.colors.stroke; 1095 1096 if(_item.default_attr['stroke-width'] && _data.options.strokeWidth) 1097 _item.default_attr['stroke-width'] = parseFloat(_data.options.strokeWidth); 1098 1099 _item.selected_attr = {}; 1100 _item.hover_attr = {}; 1101 1102 // Set cursor 1103 if(_item.disabled){ 1104 _item.default_attr.cursor = 'default'; 1105 $(_item.node).css({'pointer-events' :'none'}); 1106 }else{ 1107 _item.default_attr.cursor = _data.options.cursor; 1108 } 1109 1110 if(_data.options.regions[name]){ 1111 // Set attributes (colors, href, etc..) 1112 if(_data.options.regions[name].attr) 1113 _item.default_attr = $.extend(true, {}, _item.default_attr, _data.options.regions[name].attr); 1114 // Set tooltip 1115 if(_data.options.regions[name].tooltip) 1116 _item.tooltip = _data.options.regions[name].tooltip; 1117 // Set popover 1118 if(_data.options.regions[name].popover) 1119 _item.popover = _data.options.regions[name].popover; 1120 // Add custom data 1121 if(_data.options.regions[name].data){ 1122 if(typeof _data.options.regions[name].data == 'string'){ 1123 if(_data.options.regions[name].data.substr(0,1)=='[' || _data.options.regions[name].data.substr(0,1)=='{'){ 1124 try{ 1125 var tmp; 1126 eval('tmp = '+_data.options.regions[name].data); 1127 _item._data = tmp; 1128 }catch(err){ 1129 _item._data = _data.options.regions[name].data; 1130 } 1131 }else{ 1132 _item._data = _data.options.regions[name].data; 1133 } 1134 }else{ 1135 _item._data = _data.options.regions[name].data; 1136 } 1137 } 1138 } 1139 1140 if(_this.isNumber(_data.options.colors.selected)) 1141 _item.selected_attr['fill'] = _this.lighten(_item.default_attr.fill, parseFloat(_data.options.colors.selected)); 1142 else 1143 _item.selected_attr['fill'] = _data.options.colors.selected; 1144 1145 if(_this.isNumber(_data.options.colors.hover)) 1146 _item.hover_attr['fill'] = _this.lighten(_item.default_attr.fill, parseFloat(_data.options.colors.hover)); 1147 else 1148 _item.hover_attr['fill'] = _data.options.colors.hover; 1149 1150 // If stroke is dashed, convert it to simple: - - - - - 1151 var dash = _item.attr('stroke-dasharray'); 1152 if( dash && dash!='none') 1153 _item.default_attr['stroke-dasharray'] = '--'; 1154 1155 _item.attr(_item.default_attr); 1156 1157 // Make stroke-width always the same: 1158 if(!_browser.ie && !_browser.firefox) 1159 $(_item.node).css({'vector-effect' : 'non-scaling-stroke'}); 1160 1161 // Add region to Raphael.set() 1162 _data.RMap.push(_item); 1163 1164 // Should we select the region now? 1165 if(_data.options.regions[name] && _data.options.regions[name].selected) 1166 _this.selectRegion(name); 1167 }, 1168 1169 /** Lighten / Darken color 1170 * Taken from http://stackoverflow.com/questions/801406/c-create-a-lighter-darker-color-based-on-a-system-color/801463#801463 1171 */ 1172 1173 lighten2: function(hexColor, factor){ 1174 var h = (hexColor.charAt(0)=="#") ? hexColor.substring(1,7) : hexColor; 1175 var hsb = Raphael.rgb2hsb(parseInt(h.substring(0,2),16), parseInt(h.substring(2,4),16),parseInt(h.substring(4,6),16)); 1176 hsb.b += .1; 1177 return Raphael.hsb(hsb); 1178 }, 1179 lighten: function ( hexColor, delta ){ 1180 1181 if(!hexColor) return false; 1182 1183 delta = parseInt(delta)*0.008; 1184 1185 var rgb = Raphael.getRGB(hexColor); 1186 var hsb = Raphael.rgb2hsb(rgb.r, rgb.g, rgb.b); 1187 1188 var b = hsb.b + delta; 1189 1190 if(b >= 1){ 1191 b = 1; 1192 hsb.s = hsb.s - delta*1.5; 1193 }else if (b <= 0){ 1194 b = 0; 1195 } 1196 1197 var new_rgb = Raphael.hsb2rgb(hsb.h, hsb.s, b); 1198 1199 return new_rgb.hex; 1200 1201 }, 1202 setPan : function(on){ 1203 if(on){ 1204 _data.options.pan = true; 1205 _data.$map.on('mousedown', _this.panStart); 1206 }else{ 1207 if(_data.options.pan) 1208 _data.$map.off('mousedown', _this.panStart); 1209 _data.options.pan = false; 1210 } 1211 }, 1212 markAddClickHandler : function(e){
1213 // Don't add marker if marker was clicked 1214 if($(e.target).is('image')) return false; 1215 var x = e.offsetX == undefined ? e.layerX : e.offsetX; 1216 var y = e.offsetY == undefined ? e.layerY : e.offsetY; 1217 _this.markAdd({xy: [x, y]}, true); 1218 }, 1219 markEventHandlersSet : function(on, mark){ 1220 1221 on = _this.parseBoolean(on); 1222 1223 if(on){ 1224 if(_data.options.editMode === false) 1225 mark.unhover(); 1226 mark.drag(_this.markMove, _this.markMoveStart, _this.markMoveEnd); 1227 1228 }else{ 1229 if(_data.options.editMode) 1230 mark.undrag(); 1231 1232 mark.hover( 1233 function(){ 1234 if(this.data('tooltip')){ 1235 _data.mapTip.html( this.data('tooltip') ); 1236 _data.mapTip.show(); 1237 } 1238 }, 1239 function(){ 1240 if(this.data('tooltip')) 1241 _data.mapTip.hide(); 1242 }); 1243 1244 } 1245 }, 1246 setMarksEditMode : function(on, mark){ 1247 1248 on = _this.parseBoolean(on); 1249 1250 /* 1251 if(on){ 1252 _data.$map.on('click',_this.markAddClickHandler); 1253 }else{ 1254 _data.$map.off('click',_this.markAddClickHandler); 1255 } 1256 */ 1257 1258 _data.options.editMode = on; 1259 }, 1260 setZoom : function (on){ 1261 if(on){ 1262 _data.options.zoom = true; 1263 _data.$map.bind('mousewheel.mapsvg',function(event, delta, deltaX, deltaY) { 1264 var d = delta > 0 ? 1 : -1; 1265 _this.zoom(d); 1266 return false; 1267 }); 1268 1269 // Add zoom buttons 1270 if(_data.options.zoomButtons.show){ 1271 1272 var buttons = $('<div></div>'); 1273 1274 var cssBtn = {'border-radius': '3px', 'display': 'block', 'margin-bottom': '7px'}; 1275 1276 var btnZoomIn = $('<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABhElEQVR4nJWTT4rqQBDGf92pSEJWmYfgQpABb+EB1NU8DyBe5M1q5iKStTCDd/AWggElC3EQJAQxbb/NJDH+mccraEh31fdVfR8pBRBF0Uuapn+AX8CZn0MDuyAI3sfj8aeaTqcvWZZ9XFdZazmdTgC4rotS6oYpCILfkmXZ6yNwt9tFKcVyucRxnBuSNE1fNfB0TWCModlsMhwOGQwGdDod8jy/J+dJP9JsjKl9W2vvlZ3lcuyiS57ntY7FvZDgum6Zk0vN7XYbay3GGMIwLItarRbGGEQErTVxHON5XkVQAEaj0b0x6fV6tXsURRwOBxzHQd9F/CPO58o2ARARdrsds9ms9CIMQ/r9PgCLxYL1eo3rulhr2e/3dQkAnueRJElp2vF4LLskScJmsynNK8A1AqjcVUohUqVEBBGpuV+E/j63CV093/sLizIBvoDny1fHcdhut8znc5RSrFar2kQX8aV933+7ZldK0Wg0iOO4BD9YpjcF8L2R/7XOvu+/TyaTz79+UqnWsVHWHAAAAABJRU5ErkJggg==" id="btnZoomIn"/>').on('click', function(e){ 1277 e.stopPropagation(); 1278 _this.zoomIn(); 1279 }).css(cssBtn); 1280 1281 var btnZoomOut = $('<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA6klEQVR4nKWTPW6DQBBG3w4RaLXSFs4puAe9fQHEReLKPgYN4gLxQei5RNytFraANNEKKwk29uum+N78SKMA2rbdO+c+gHdgYh0Bvowx57IsL6ppmr33/vNO6E+MMQfx3h+fCQM4544C7J4VADvh/s5rTG/LKoTANK37RIQ0TWMdBSEE8jwnyzLmef437L2n7/soiQLnHEVRPDR313VRIA8lVogTWGup6/pmhSRJAFBKxcAwDFhrfwuSJCGEwDiOqx2VUlF8I1h23ILw2h1EgOsLgqtorU/LI23BGHNSAD8fuemdtdbnqqou39SbTK6RdYDsAAAAAElFTkSuQmCC" id="btnZoomOut"/>').on('click', function(e){ 1282 e.stopPropagation(); 1283 _this.zoomOut(); 1284 }).css(cssBtn); 1285 1286 buttons.append(btnZoomOut).append(btnZoomIn).css({position: 'absolute', top: '15px', width: '16px', cursor: 'pointer'}); 1287 1288 if(_data.options.zoomButtons.location == 'right') 1289 buttons.css({'right': '15px'}); 1290 else if(_data.options.zoomButtons.location == 'left') 1291 buttons.css({'left': '15px'}); 1292 1293 _data.zoomButtons = buttons; 1294 1295 _data.$map.append(_data.zoomButtons); 1296 } 1297 1298 }else{ 1299 if(_data.options.zoom) 1300 _data.$map.unbind('mousewheel.mapsvg'); 1301 if(_data.zoomButtons) 1302 _data.zoomButtons.hide(); 1303 _data.options.zoom = false; 1304 } 1305 }, 1306 setSize : function( width, height, responsive ){ 1307 1308 // Convert strings to numbers 1309 _data.options.width = parseInt(width); 1310 _data.options.height = parseInt(height); 1311 _data.options.responsive = _this.parseBoolean(responsive); 1312 1313 // Calculate width and height 1314 if ((!_data.options.width && !_data.options.height)){ 1315 _data.options.width = _data.svgDefault.width; 1316 _data.options.height = _data.svgDefault.height; 1317 }else if (!_data.options.width && _data.options.height){ 1318 _data.options.width = parseInt(_data.options.height * _data.svgDefault.width / _data.svgDefault.height); 1319 }else if (_data.options.width && !_data.options.height){ 1320 _data.options.height = parseInt(_data.options.width * _data.svgDefault.height/_data.svgDefault.width); 1321 } 1322 1323 if(_data.options.responsive){ 1324 var maxWidth = _data.options.width; 1325 var maxHeight = _data.options.height; 1326 _data.options.width = _data.svgDefault.width; 1327 _data.options.height = _data.svgDefault.height; 1328 } 1329 1330 _data.whRatio = _data.options.width / _data.options.height;
1331 _data.scale = _this.getScale(); 1332 1333 if(_data.options.responsive){ 1334 1335 _data.$map.css({ 1336 'max-width': maxWidth+'px', 1337 'max-height': maxHeight+'px', 1338 'width': 'auto', 1339 'height': 'auto', 1340 'position': 'relative' 1341 }).height(_data.$map.width() / _data.whRatio); 1342 1343 $(window).bind('resize.mapsvg', function(){ 1344 _data.$map.height(_data.$map.width() / _data.whRatio); 1345 }); 1346 }else{ 1347 _data.$map.css({ 1348 'width': _data.options.width+'px', 1349 'height': _data.options.height+'px', 1350 'max-width': 'none', 1351 'max-height': 'none', 1352 'position': 'relative' 1353 }); 1354 $(window).unbind('resize.mapsvg'); 1355 } 1356 1357 if(!_data.options.responsive && _data.R) 1358 _data.R.setSize(_data.options.width, _data.options.height); 1359 1360 return [_data.options.width, _data.options.height]; 1361 1362 1363 }, 1364 // Adding marks 1365 setMarks : function (marksArr){ 1366 if(marksArr){ 1367 $.each(marksArr, function(i, mark){ 1368 _this.markAdd(mark); 1369 }); 1370 } 1371 }, 1372 1373 // Show tooltip (this function will be defined later in setTooltip method) 1374 showTip : function(){}, 1375 showPopover : function(){}, 1376 // Hide tooltip 1377 hideTip : function (){ 1378 _data.mapTip.hide(); 1379 _data.mapTip.html(''); 1380 }, 1381 // Set tooltip behaviour 1382 setTooltip : function (mode){ 1383 1384 // Add tooltip container 1385 _data.mapTip = $('<div class="map_tooltip"></div>'); 1386 $("body").append(_data.mapTip); 1387 1388 _data.mapTip.css({ 1389 'font-weight': 'normal', 1390 'font-size' : '12px', 1391 'color': '#000000', 1392 'position': 'absolute', 1393 'border-radius' : '4px', 1394 '-moz-border-radius' : '4px', 1395 '-webkit-border-radius' : '4px', 1396 'top': '0', 1397 'left': '0', 1398 'z-index': '1000', 1399 'display': 'none', 1400 'background-color': 'white', 1401 'border': '1px solid #eee', 1402 'padding': '4px 7px', 1403 'max-width': '600px' 1404 }); 1405 1406 if(_data.options.tooltips.show == 'hover'){ 1407 _data.$map.mousemove(function(e) { 1408 _data.mapTip.css('left', e.clientX + $(window).scrollLeft()).css('top', e.clientY + $(window).scrollTop() + 30); 1409 }); 1410 } 1411 1412 _this.showTip = (_data.options.tooltipsMode == 'custom' ? 1413 function (name){ 1414 var obj = _data.R.getById(name); 1415 if(obj.tooltip){ 1416 _data.mapTip.html(obj.tooltip); 1417 _data.mapTip.show(); 1418 } 1419 }: _data.options.tooltipsMode == 'names' ? 1420 function (name){ 1421 var obj = _data.R.getById(name); 1422 if(obj.disabled) return false; 1423 _data.mapTip.html(name.replace(/_/g, ' ')); 1424 _data.mapTip.show(); 1425 }: _data.options.tooltipsMode == 'combined' ? 1426 function (name){ 1427 var obj = _data.R.getById(name); 1428 if(obj.tooltip){ 1429 _data.mapTip.html(obj.tooltip); 1430 _data.mapTip.show(); 1431 }else{ 1432 if(obj.disabled) return false; 1433 _data.mapTip.html(name.replace(/_/g, ' ')); 1434 _data.mapTip.show(); 1435 } 1436 }: function(name){null;} 1437 ); 1438 1439 }, 1440 // Set popover behaviour 1441 setPopover : function (on){ 1442 1443 if(!on) return false; 1444 1445 // Add tooltip container 1446 $("body").prepend('<div class="map_popover"><div class="map_popover_content"></div><div class="map_popover_close">x</div></div>'); 1447 1448 _data.mapPopover = $('.map_popover'); 1449 1450 var popoverClose = _data.mapPopover.find('.map_popover_close'); 1451 1452 1453 _data.mapPopover.css({ 1454 'font-weight': 'normal', 1455 'font-size' : '12px', 1456 'color': '#000000', 1457 'position': 'absolute', 1458 'border-radius' : '4px',
1459 '-moz-border-radius' : '4px', 1460 '-webkit-border-radius' : '4px', 1461 'top': '0', 1462 'left': '0', 1463 'z-index': '1000', 1464 'width': _data.options.popover.width+(_data.options.popover.width=='auto'? '': 'px'), 1465 'height': _data.options.popover.height+(_data.options.popover.height=='auto'? '': 'px'), 1466 'display': 'none', 1467 'background-color': 'white', 1468 'border': '1px solid #ccc', 1469 'padding': '12px', 1470 '-webkit-box-shadow': '5px 5px 5px 0px rgba(0, 0, 0, 0.2)', 1471 'box-shadow': '5px 5px 5px 0px rgba(0, 0, 0, 0.2)' 1472 1473 }); 1474 1475 popoverClose.css({ 1476 'position': 'absolute', 1477 'top': '0', 1478 'right' : '5px', 1479 'cursor': 'pointer', 1480 'color': '#aaa', 1481 'z-index' : '1200' 1482 1483 }); 1484 1485 _this.showPopover = function (e, content, pos){ 1486 1487 1488 if (!pos || pos.length != 2){ 1489 var m = mouseCoords(e); 1490 var pos = [m.x, m.y]; 1491 }else{ 1492 var scale = _this.getScale(); 1493 pos[0] = _data.$map.offset().left + pos[0]*scale; 1494 pos[1] = _data.$map.offset().top + pos[1]*scale; 1495 } 1496 1497 if(content){ 1498 _data.mapPopover.find('.map_popover_content').html(content); 1499 var nx = pos[0] - _data.mapPopover.outerWidth(false)/2; 1500 var ny = pos[1] - _data.mapPopover.outerHeight(false) - 7; 1501 if(nx<0) nx = 0; 1502 if(ny<0) ny = 0; 1503 1504 if(nx+_data.mapPopover.outerWidth(false) > $(window).scrollLeft() + $(window).width()) nx = ($(window).scrollLeft() + $(window).width()) - _data.mapPopover.outerWidth(false); 1505 if(ny+_data.mapPopover.outerHeight(false) > $(window).scrollTop() + $(window).height()) ny = ($(window).scrollTop() + $(window).height()) - _data.mapPopover.outerHeight(false); 1506 if(nx < $(window).scrollLeft()) nx = $(window).scrollLeft(); 1507 if(ny < $(window).scrollTop()) ny = $(window).scrollTop(); 1508 1509 _data.mapPopover.css('left', nx).css('top', ny); 1510 _data.mapPopover.show() 1511 }else{ 1512 _this.hidePopover(); 1513 } 1514 }; 1515 1516 _this.hidePopover = function(){ 1517 _data.mapPopover.find('.map_popover_content').html(''); 1518 _data.mapPopover.hide(0,function(){ 1519 $('body').off('mousedown', _this.popoverOffHandler); 1520 if(_data.options.onPopoverClose){ 1521 _data.options.onPopoverClose.call(_this); 1522 } 1523 1524 }); 1525 }; 1526 1527 popoverClose.on('click', _this.hidePopover); 1528 1529 }, 1530 popoverOffHandler : function(e){ 1531 1532 var id = $(e.target).attr('id'); 1533 1534 1535 // If clicked object was popover by itself, stop. 1536 // If region was clicked - stop, because pop-up will just move to another position, we don't have to hide it. 1537 if($(e.target).closest('.map_popover').length || (_data.options.regions[id] && !_data.options.regions[id].disabled )) 1538 return false; 1539 1540 _this.hidePopover(); 1541 }, 1542 isNumber : function (n) { 1543 return !isNaN(parseFloat(n)) && isFinite(n); 1544 }, 1545 parseBoolean : function (string) { 1546 switch (String(string).toLowerCase()) { 1547 case "true": 1548 case "1": 1549 case "yes": 1550 case "y": 1551 return true; 1552 case "false": 1553 case "0": 1554 case "no": 1555 case "n": 1556 return false; 1557 default: 1558 return undefined; 1559 } 1560 }, 1561 mouseOverHandler : function(){}, 1562 mouseOutHandler : function(){}, 1563 mouseDownHandler : function(){}, 1564 // INIT 1565 init : function(opts, elem) { 1566 1567 if(!opts.source) { 1568 alert('mapSVG Error: Please provide a map URL'); 1569 return false; 1570 } 1571 1572 // Cut protocol (http: || https:) - to avoid "cross-domain" error 1573 if(opts.source.indexOf('http://') == 0 || opts.source.indexOf('https://') == 0) 1574 opts.source = "//"+opts.source.split("://").pop(); 1575 1576 opts.pan = _this.parseBoolean(opts.pan); 1577 opts.zoom = _this.parseBoolean(opts.zoom); 1578 opts.responsive = _this.parseBoolean(opts.responsive); 1579 opts.disableAll = _this.parseBoolean(opts.disableAll); 1580 opts.multiSelect = _this.parseBoolean(opts.multiSelect); 1581 1582 // If veiwBox is set as string region's name (or country name) 1583 // then we'll calculate veiwBox parameters later 1584 if(opts.viewBox && typeof opts.viewBox == 'string'){ 1585 opts.viewBoxFind = opts.viewBox; 1586 delete opts.viewBox; 1587 } 1588 1589 /** Setting _data **/ 1590 _data = {}; 1591 1592 _data.options = $.extend(true, {}, defaults, opts); 1593 1594 _data.map = elem; 1595 _data.$map = $(elem); 1596 _data.whRatio = 0; 1597 _data.isPanning = false; 1598 1599 _data.markOptions = {}; 1600 _data.svgDefault = {}; 1601 _data.mouseDownHandler; 1602 1603 _data.refLength = 0; 1604 1605 _data.scale = 1; // absolute scale 1606 _data._scale = 1; // relative scale starting from current zoom level 1607 1608 _data.selected_id = _data.options.multiSelect ? [] : 0; 1609 _data.mapData = {}; 1610 1611 _data.marks = []; 1612 _data._viewBox = []; // initial viewBox 1613 _data.viewBox = []; // current viewBox 1614 _data.viewBoxZoom = []; 1615 _data.viewBoxFind = undefined; 1616 _data.zoomLevel = 0; 1617 _data.pan = {}; 1618 _data.zoom; 1619 _data.touchZoomStart; 1620 _data.touchZoomStartViewBox; 1621 _data.touchZoomEnd; 1622 /****/ 1623 1624 1625 // Set background 1626 _data.$map.css({ 1627 'background': _data.options.colors.background, 1628 'height': '100px', 1629 'position' : 'relative' 1630 }); 1631 1632 var loading = $('<div>'+_data.options.loadingText+'</div>').css({ 1633 position: 'absolute', 1634 top: '50%', 1635 left: '50%', 1636 'z-index': 1, 1637 padding: '7px 10px', 1638 'border-radius': '5px',
1639 '-webkit-border-radius': '5px', 1640 '-moz-border-radius': '5px', 1641 '-ms-border-radius': '5px', 1642 '-o-border-radius': '5px', 1643 'border': '1px solid #ccc', 1644 background: '#f5f5f2', 1645 color: '#999' 1646 }); 1647 1648 _data.$map.append(loading); 1649 1650 loading.css({ 1651 'margin-left': function () { 1652 return -($(this).outerWidth(false) / 2)+'px'; 1653 }, 1654 'margin-top': function () { 1655 return -($(this).outerHeight(false) / 2)+'px'; 1656 } 1657 }); 1658 1659 1660 // GET the map by ajax request 1661 $.ajax({ 1662 url: _data.options.source, 1663 contentType: "image/svg+xml; charset=utf-8", 1664 //dataType: (_browser.ie) ? 'text' : 'xml', // check if IE 1665 beforeSend: function(x) { 1666 if(x && x.overrideMimeType) { 1667 x.overrideMimeType("image/svg+xml; charset=utf-8"); 1668 } 1669 }, 1670 success: function(xmlData){ 1671 1672 $data = $(xmlData); 1673 1674 // Default width/height/viewBox from SVG 1675 var svgTag = $data.find('svg'); 1676 _data.svgDefault.width = parseFloat(svgTag.attr('width').replace(/px/g,'')); 1677 _data.svgDefault.height = parseFloat(svgTag.attr('height').replace(/px/g,'')); 1678 _data.svgDefault.viewBox = svgTag.attr('viewBox') ? svgTag.attr('viewBox').split(' ') : [0,0, _data.svgDefault.width, _data.svgDefault.height]; 1679 1680 $.each(_data.svgDefault.viewBox, function(i,v){ 1681 _data.svgDefault.viewBox[i] = parseInt(v); 1682 }); 1683 1684 _data._viewBox = (_data.options.viewBox.length==4) ? _data.options.viewBox : _data.svgDefault.viewBox; 1685 1686 $.each(_data._viewBox, function(i,v){ 1687 _data._viewBox[i] = parseInt(v); 1688 }); 1689 1690 1691 // Set size 1692 _this.setSize(_data.options.width, _data.options.height, _data.options.responsive); 1693 1694 // Attach Raphael to given jQuery element 1695 1696 // IE 7&8 doesn't support responsive size so we just set 1697 // width and height in pixels, and then resize it on window.resize event. 1698 // For all other cool browsers we just set width and height 1699 // to 100% to simply fit DIV container. 1700 1701 1702 if(_browser.ie && _browser.ie.old){ 1703 1704 _data.R = Raphael(_data.$map.attr('id'), _data.options.width, _data.options.height); 1705 _data.scale = _this.getScale(); 1706 1707 if(_data.options.responsive) 1708 $(window).on('resize', _this.fluidResize); 1709 1710 }else{ 1711 _data.R = Raphael(_data.$map.attr('id'), '100%', '100%'); 1712 1713 if(_data.options.responsive){ 1714 $(window).on('resize', function(e){ 1715 _data.scale = _this.getScale(); 1716 _this.marksAdjustPosition(); 1717 }); 1718 } 1719 } 1720 1721 // Adding moving sticky draggable image on background 1722 if(_data.options.panBackground) 1723 _data.background = _data.R.rect(_data.svgDefault.viewBox[0],_data.svgDefault.viewBox[1],_data.svgDefault.viewBox[2],_data.svgDefault.viewBox[3]).attr({fill: _data.options.colors.background}); 1724 1725 _data.RMap = _data.R.set(); 1726 _data.RMarks = _data.R.set(); 1727 1728 // Render each SVG element 1729 1730 var parse = function(_item, parentTransform, parentStyle){ 1731 var type = $(_item).get(0).tagName; 1732 1733 switch (type){ 1734 case 'path': 1735 _this.renderSVGPath(_item, parentTransform, parentStyle); 1736 break; 1737 case 'polygon': 1738 _this.renderSVGPolygon(_item, parentTransform, parentStyle); 1739 break; 1740 case 'polyline': 1741 _this.renderSVGPolyline(_item, parentTransform, parentStyle); 1742 break; 1743 case 'circle': 1744 _this.renderSVGCircle(_item, parentTransform, parentStyle); 1745 break; 1746 case 'ellipse': 1747 _this.renderSVGEllipse(_item, parentTransform, parentStyle); 1748 break; 1749 case 'rect': 1750 _this.renderSVGRect(_item, parentTransform, parentStyle); 1751 break; 1752 case 'image': 1753 _this.renderSVGImage(_item, parentTransform, parentStyle); 1754 break; 1755 case 'text': 1756 _this.renderSVGText(_item, parentTransform, parentStyle); 1757 break; 1758 default: 1759 null; 1760 break; 1761 } 1762 }; 1763 1764 var traverse = function (node, parentTransformString, parentStyle){ 1765 1766 var children = $(node).children();
1767 1768 if (children.length){// && !$(node).is('text')) { 1769 1770 var nodes = []; 1771 1772 parentTransformString = parentTransformString || ""; 1773 parentTransformString = _this.transformSVG2Raphael(node) + parentTransformString; 1774 parentStyle = parentStyle || {}; 1775 1776 $(node).children().each(function(i,n){ 1777 var _parentStyle = _this.styleSVG2Raphael(n, parentStyle); 1778 traverse($(n), parentTransformString, _parentStyle); 1779 }); 1780 1781 }// else{ 1782 parse($(node), parentTransformString, parentStyle); 1783 //} 1784 1785 }; 1786 1787 traverse($data.find('svg')); 1788 1789 // Set viewBox 1790 var v = _data.options.viewBoxFind || _data._viewBox; 1791 _this.setViewBox(v); 1792 1793 // If there are markers, put them to the map 1794 _this.setMarks(_data.options.marks); 1795 _this.setMarksEditMode(_data.options.editMode); 1796 1797 // Set panning 1798 _this.setPan(_data.options.pan); 1799 1800 // Set zooming by mouswheel 1801 _this.setZoom(_data.options.zoom); 1802 1803 // Set tooltips 1804 _this.setTooltip(_data.options.tooltips.mode); 1805 1806 // Set popovers 1807 _this.setPopover(_data.options.popover); 1808 1809 1810 if(_data.options.responsive && _browser.ie && _browser.ie.old) 1811 _this.fluidResize(); 1812 1813 1814 if((_browser.ie && !_browser.ie.old) || _browser.firefox) 1815 _this.mapAdjustStrokes(); 1816 1817 1818 //Create event handlers 1819 var funcStr = ''; 1820 1821 /* 1822 * Now let's add event handlers. 1823 * Please note that we don't need mouseOver / mouseOut on mobile devices (iPad etc..) 1824 */ 1825 if(!touchDevice){ 1826 // 1. MouseOver 1827 funcStr = 'methods.highlightRegion(this.name);'; 1828 if(_data.options.tooltips.show == 'hover') 1829 funcStr += 'methods.showTip(this.name);'; 1830 if(_data.options.mouseOver) 1831 funcStr += 'return options.mouseOver.call(this, e, methods);'; 1832 1833 _this.mouseOverHandler = new Function('e, methods, options', funcStr); 1834 1835 // 2. MouseOut 1836 funcStr = ''; 1837 funcStr += 'methods.unhighlightRegion(this.name);'; 1838 if(_data.options.tooltips.show == 'hover') 1839 funcStr += 'methods.hideTip();'; 1840 if(_data.options.mouseOut) 1841 funcStr += 'return options.mouseOut.call(this, e, methods);'; 1842 _this.mouseOutHandler = new Function('e, methods, options', funcStr); 1843 } 1844 1845 // 3. MouseDown 1846 funcStr = ''; 1847 funcStr = 'methods.regionClickHandler.call(mapObj, e, this);'; 1848 _this.mouseDownHandler = new Function('e, methods', funcStr); 1849 1850 1851 /* EVENTS */ 1852 if(!touchDevice){ 1853 _data.RMap 1854 .mouseover( function(e){_this.mouseOverHandler.call(this, e, _this, options);} ) 1855 .mouseout( function(e){_this.mouseOutHandler.call(this, e, _this, options);} ); 1856 } 1857 1858 if(!_data.options.pan){ 1859 1860 if(!touchDevice){ 1861 _data.RMap.mousedown( function(e){
1862 1863 //_this.mouseDownHandler.call(this, e, methods);} 1864 _this.regionClickHandler.call(_this, e, this); 1865 }); 1866 }else{ 1867 _data.RMap.touchstart( 1868 function(e){ 1869 1870 e.preventDefault(); 1871 _this.regionClickHandler.call(_this, e, this); 1872 } 1873 ); 1874 } 1875 }else{ 1876 if(!touchDevice){ 1877 _data.RMap.mousedown( function(e){ 1878 // While panning we just remember which region was clicked 1879 // by panRegionClickHandler method, and then trigger 1880 // regionClickHandler on that region when panning finishes 1881 e.preventDefault(); 1882 1883 _this.panRegionClickHandler.call(_this, e, this); 1884 }); 1885 }else{ 1886 _data.RMap.touchstart( 1887 function(e){ 1888 _this.panRegionClickHandler.call(_this, e, this); 1889 } 1890 ); 1891 _data.R.canvas.addEventListener('touchstart', function(e) { 1892 _this.touchStart(e); 1893 }, false); 1894 _data.R.canvas.addEventListener('touchmove', function(e) { 1895 _this.touchMove(e); 1896 }, false); 1897 _data.R.canvas.addEventListener('touchend', function(e) { 1898 _this.touchEnd(e); 1899 }, false); 1900 } 1901 } 1902 loading.hide(); 1903 1904 if(_data.options.onLoad) 1905 _data.options.onLoad.call(_this); 1906 1907 1908 1909 } // end of AJAX callback 1910 1911 1912 1913 });// end of AJAX 1914 1915 1916 1917 return _this; 1918 1919 } // end of init 1920 1921 }; // end of methods 1922 1923 var _this = this.methods; 1924 1925 }; // end of mapSVG class 1926 1927 1928 /** $.FN **/ 1929 $.fn.mapSvg = function( opts ) { 1930 1931 var id = $(this).attr('id'); 1932 1933 if(typeof opts == 'object' && instances[id] === undefined){ 1934 instances[id] = new mapSVG(this, opts); 1935 return instances[id].methods.init(opts, this); 1936 }else if(instances[id]){ 1937 return instances[id].methods; 1938 }else{ 1939 return $(this); 1940 } 1941 1942 }; // end of $.fn.mapSvg 1943 1944})( jQuery );
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.