1/** 2 * Mapplic - Custom Interactive Map Plugin by @sekler 3 * http://www.mapplic.com 4 */ 5 6(function($) { 7 8 var Mapplic = function() { 9 var self = this; 10 11 self.o = { 12 source: 'locations.json', 13 height: 420, 14 locations: true, 15 minimap: true, 16 sidebar: true, 17 deeplinking: true, 18 search: true, 19 clearbutton: true, 20 hovertip: true, 21 fullscreen: false, 22 developer: false, 23 animate: true, 24 maxscale: 4 25 }; 26 27 self.init = function(el, params) { 28 // Extend options 29 self.o = $.extend(self.o, params); 30 31 self.x = 0; 32 self.y = 0; 33 self.scale = 1; 34 35 self.el = el.addClass('mapplic-element mapplic-loading').height(self.o.height); 36 37 // Process JSON file 38 $.getJSON(self.o.source, function(data) { // Success 39 processData(data); 40 self.el.removeClass('mapplic-loading'); 41 42 // Controls 43 addControls(); 44 45 }).fail(function() { // Failure: couldn't load JSON file, or it is invalid. 46 console.error('Couldn\'t load map data. (Make sure you are running the script through a server and not just opening the html file with your browser)'); 47 alert('Data file missing or invalid!'); 48 }); 49 50 return self; 51 } 52 53 self.goToLocation = function(location,duration){ 54 showLocation(location, duration); 55 } 56 // Tooltip 57 function Tooltip() { 58 this.el = null; 59 this.shift = 6; 60 this.drop = 0; 61 62 this.init = function() { 63 var s = this; 64 65 // Construct 66 this.el = $('<div></div>').addClass('mapplic-tooltip'); 67 $('<a></a>').addClass('mapplic-tooltip-close').attr('href', '#').click(function(e) { 68 e.preventDefault(); 69 self.deeplinking.clear(); 70 s.hide(); 71 }).appendTo(this.el); 72 this.image = $('<img>').addClass('mapplic-tooltip-image').hide().appendTo(this.el); 73 this.title = $('<h4></h4>').addClass('mapplic-tooltip-title').appendTo(this.el); 74 this.content = $('<div></div>').addClass('mapplic-tooltip-content').appendTo(this.el); 75 this.desc = $('<div></div>').addClass('mapplic-tooltip-description').appendTo(this.content); 76 this.link = $('<a>More</a>').addClass('mapplic-tooltip-link').attr('href', '#').hide().appendTo(this.el); 77 $('<div></div>').addClass('mapplic-tooltip-triangle').prependTo(this.el); 78 79 // Append 80 self.map.append(this.el); 81 } 82 83 this.set = function(location) { 84 if (location) { 85 if (location.action == 'none') { 86 this.el.stop().fadeOut(300); 87 return; 88 } 89 90 var s = this; 91 92 if (location.image) this.image.attr('src', location.image).show(); 93 else this.image.hide(); 94 95 if (location.link) this.link.attr('href', location.link).show(); 96 else this.link.hide(); 97 98 this.title.text(location.title); 99 this.desc.html(location.description); 100 101 // Shift 102 var pinselect = $('.mapplic-pin[data-location="' + location.id + '"]'); 103 if (pinselect.length == 0) { 104 this.shift = 6; 105 } 106 else this.shift = pinselect.height() + 6; 107 108 // Loading & positioning 109 $('img', this.desc).load(function() { 110 s.position(location); 111 }); 112 113 this.position(location); 114 } 115 } 116 117 this.show = function(location) { 118 if (location) { 119 if (location.action == 'none') { 120 this.el.stop().fadeOut(300); 121 return; 122 } 123 124 var s = this; 125 126 if (location.image) this.image.attr('src', location.image).show(); 127 else this.image.hide(); 128 129 if (location.link) this.link.attr('href', location.link).show(); 130 else this.link.hide(); 131 132 this.title.text(location.title); 133 this.desc.html(location.description); 134 135 // Shift 136 var pinselect = $('.mapplic-pin[data-location="' + location.id + '"]'); 137 if (pinselect.length == 0) { 138 this.shift = 6; 139 } 140 else this.shift = pinselect.height() + 6; 141 142 // Loading & positioning 143 $('img', this.desc).load(function() { 144 s.position(location); 145 }); 146 147 this.position(location); 148 149 // Making it visible 150 this.el.stop().fadeIn(200).show(); 151 } 152 } 153 154 this.position = function(location) { 155 var x = location.x * 100; 156 y = location.y * 100; 157 mt = -this.el.outerHeight() - this.shift, 158 ml = -this.el.outerWidth() / 2; 159 this.el.css({ 160 left: x + '%', 161 top: y + '%', 162 marginTop: mt, 163 marginLeft: ml 164 }); 165 this.drop = this.el.outerHeight() + this.shift; 166 } 167 168 this.hide = function() { 169 var s = this; 170 171 this.el.stop().fadeOut(300, function() { 172 s.desc.empty(); 173 }); 174 } 175 } 176 177 // Deeplinking 178 function Deeplinking() { 179 this.init = function() { 180 // Check hash for location 181 var id = location.hash.slice(1); 182 if (id) { 183 var locationData = getLocationData(id); 184 185 self.tooltip.set(locationData); 186 showLocation(id, 0); 187 self.tooltip.show(locationData); 188 } 189 else zoomTo(0.5, 0.5, 1, 0); 190 191 // Hashchange 192 $(window).on('hashchange', function() { 193 var id = location.hash.slice(1); 194 195 if (id) { 196 var locationData = getLocationData(id); 197 198 self.tooltip.set(locationData); 199 showLocation(id, 800); 200 self.tooltip.show(locationData); 201 } 202 }); 203 } 204 205 this.clear = function() { 206 // if IE 6-8, else normal browsers 207 if (history.pushState) history.pushState('', document.title, window.location.pathname); 208 else window.location.hash = ''; 209 } 210 } 211 212 // HoverTooltip 213 function HoverTooltip() { 214 this.el = null; 215 this.shift = 6; 216 217 this.init = function() { 218 var s = this; 219 220 // Construct 221 this.el = $('<div></div>').addClass('mapplic-tooltip mapplic-hovertip'); 222 this.title = $('<h4></h4>').addClass('mapplic-tooltip-title').appendTo(this.el); 223 $('<div></div>').addClass('mapplic-tooltip-triangle').appendTo(this.el); 224 225 // Events 226 $(self.map).on('mouseover', '.mapplic-layer a', function() { 227 var data = ''; 228 if ($(this).hasClass('mapplic-pin')) { 229 data = $(this).data('location'); 230 s.shift = $(this).height() + 6; 231 } 232 else { 233 data = $(this).attr('xlink:href').slice(1); 234 s.shift = 6; 235 } 236 237 var location = getLocationData(data); 238 if (location) s.show(location); 239 }).on('mouseout', function() { 240 s.hide(); 241 }); 242 243 self.map.append(this.el); 244 } 245 246 this.show = function(location) { 247 this.title.text(location.title); 248 249 var x = location.x * 100, 250 y = location.y * 100, 251 mt = -this.el.outerHeight() - this.shift, 252 ml = -this.el.outerWidth() / 2; 253 this.el.css({ 254 left: x + '%', 255 top: y + '%', 256 marginTop: mt, 257 marginLeft: ml 258 }); 259 260 this.el.stop().fadeIn(100); 261 } 262 263 this.hide = function() { 264 this.el.stop().fadeOut(200); 265 } 266 } 267 268 // Minimap 269 function Minimap() { 270 this.el = null; 271 272 this.init = function() { 273 this.el = $('<div></div>').addClass('mapplic-minimap').appendTo(self.container); 274 this.el.css('height', this.el.width() * self.hw_ratio); 275 this.el.click(function(e) { 276 e.preventDefault(); 277 278 var x = (e.pageX - $(this).offset().left) / $(this).width(), 279 y = (e.pageY - $(this).offset().top) / $(this).height(); 280 281 zoomTo(x, y, self.scale / self.fitscale, 100); 282 }); 283 } 284 285 this.addLayer = function(data) {
286 var layer = $('<div></div>').addClass('mapplic-minimap-layer').addClass(data.id).appendTo(this.el); 287 $('<img>').attr('src', data.minimap).addClass('mapplic-minimap-background').appendTo(layer); 288 $('<div></div>').addClass('mapplic-minimap-overlay').appendTo(layer); 289 $('<img>').attr('src', data.minimap).addClass('mapplic-minimap-active').appendTo(layer); 290 } 291 292 this.show = function(target) { 293 $('.mapplic-minimap-layer:visible', this.el).hide(); 294 $('.mapplic-minimap-layer.' + target, this.el).show(); 295 } 296 297 this.update = function(x, y) { 298 var active = $('.mapplic-minimap-active', this.el); 299 300 if (x === undefined) x = self.x; 301 if (y === undefined) y = self.y; 302 303 var width = Math.round(self.container.width() / self.contentWidth / self.scale * this.el.width()), 304 height = Math.round(self.container.height() / self.contentHeight / self.scale * this.el.height()), 305 top = Math.round(-y / self.contentHeight / self.scale * this.el.height()), 306 left = Math.round(-x / self.contentWidth / self.scale * this.el.width()), 307 right = left + width, 308 bottom = top + height; 309 310 active.css('clip', 'rect(' + top + 'px, ' + right + 'px, ' + bottom + 'px, ' + left + 'px)'); 311 } 312 } 313 314 // Sidebar 315 function Sidebar() { 316 this.el = null; 317 this.list = null; 318 319 this.init = function() { 320 var s = this; 321 322 this.el = $('<div></div>').addClass('mapplic-sidebar').appendTo(self.el); 323 324 if (self.o.search) { 325 var form = $('<form></form>').addClass('mapplic-search-form').submit(function() { 326 return false; 327 }).appendTo(this.el); 328 self.clear = $('<button></button>').addClass('mapplic-search-clear').click(function() { 329 input.val('');
330 input.keyup(); 331 }).appendTo(form); 332 var input = $('<input>').attr({'type': 'text', 'spellcheck': 'false', 'placeholder': 'Search for location...'}).addClass('mapplic-search-input').keyup(function() { 333 var keyword = $(this).val(); 334 s.search(keyword); 335 }).prependTo(form); 336 } 337 338 var listContainer = $('<div></div>').addClass('mapplic-list-container').appendTo(this.el); 339 this.list = $('<ol></ol>').addClass('mapplic-list').appendTo(listContainer); 340 this.notfound = $('<p></p>').addClass('mapplic-not-found').text('Nothing found. Please try a different search.').appendTo(listContainer); 341 342 if (!self.o.search) listContainer.css('padding-top', '0'); 343 } 344 345 this.addCategories = function(categories) { 346 var list = this.list; 347 348 $.each(categories, function(index, category) { 349 var item = $('<li></li>').addClass('mapplic-list-category').addClass(category.id); 350 var ol = $('<ol></ol>').css('border-color', category.color).appendTo(item); 351 if (category.show == 'false') ol.hide(); 352 var link = $('<a></a>').attr('href', '#').attr('title', category.title).css('background-color', category.color).text(category.title).click(function(e) { 353 ol.slideToggle(200); 354 return false; 355 }).prependTo(item); 356 if (category.icon) $('<img>').attr('src', category.icon).addClass('mapplic-list-thumbnail').prependTo(link); 357 $('<span></span>').text('0').addClass('mapplic-list-count').prependTo(link); 358 list.append(item); 359 }); 360 } 361 362 this.addLocation = function(data) { 363 var item = $('<li></li>').addClass('mapplic-list-location').addClass('mapplic-list-shown'); 364 var link = $('<a></a>').attr('href', '#' + data.id).appendTo(item); 365 if (data.thumbnail) $('<img>').attr('src', data.thumbnail).addClass('mapplic-list-thumbnail').appendTo(link); 366 $('<h4></h4>').text(data.title).appendTo(link) 367 $('<span></span>').html(data.about).appendTo(link); 368 var category = $('.mapplic-list-category.' + data.category); 369 370 if (category.length) $('ol', category).append(item); 371 else this.list.append(item); 372 373 // Count 374 $('.mapplic-list-count', category).text($('.mapplic-list-shown', category).length); 375 } 376 377 this.search = function(keyword) { 378 if (keyword) self.clear.fadeIn(100); 379 else self.clear.fadeOut(100); 380 381 $('.mapplic-list li', self.el).each(function() { 382 if ($(this).text().search(new RegExp(keyword, "i")) < 0) { 383 $(this).removeClass('mapplic-list-shown'); 384 $(this).slideUp(200); 385 } else { 386 $(this).addClass('mapplic-list-shown'); 387 $(this).show(); 388 } 389 }); 390 391 $('.mapplic-list > li', self.el).each(function() { 392 var count = $('.mapplic-list-shown', this).length; 393 $('.mapplic-list-count', this).text(count); 394 }); 395 396 // Show not-found text 397 if ($('.mapplic-list > li.mapplic-list-shown').length > 0) this.notfound.fadeOut(200); 398 else this.notfound.fadeIn(200); 399 } 400 } 401 402 // Developer tools 403 function DevTools() { 404 this.el = null; 405 406 this.init = function() { 407 this.el = $('<div></div>').addClass('mapplic-coordinates').appendTo(self.container); 408 this.el.append('x: '); 409 $('<code></code>').addClass('mapplic-coordinates-x').appendTo(this.el); 410 this.el.append(' y: '); 411 $('<code></code>').addClass('mapplic-coordinates-y').appendTo(this.el); 412 413 $('.mapplic-layer', self.map).on('mousemove', function(e) { 414 var x = (e.pageX - self.map.offset().left) / self.map.width(), 415 y = (e.pageY - self.map.offset().top) / self.map.height(); 416 $('.mapplic-coordinates-x').text(parseFloat(x).toFixed(4)); 417 $('.mapplic-coordinates-y').text(parseFloat(y).toFixed(4)); 418 }); 419 } 420 } 421 422 // Clear Button 423 function ClearButton() { 424 this.el = null; 425 426 this.init = function() { 427 this.el = $('<a></a>').attr('href', '#').addClass('mapplic-clear-button').click(function(e) { 428 e.preventDefault(); 429 self.deeplinking.clear(); 430 self.tooltip.hide(); 431 zoomTo(0.5, 0.5, 1); 432 }).appendTo(self.container); 433 } 434 } 435 436 // Full Screen 437 function FullScreen() { 438 this.el = null; 439 440 this.init = function() { 441 var s = this; 442 this.element = self.el[0]; 443 444 $('<a></a>').attr('href', '#').attr('href', '#').addClass('mapplic-fullscreen-button').click(function(e) { 445 e.preventDefault(); 446 447 if (s.isFull()) s.exitFull(); 448 else s.goFull(); 449 450 }).appendTo(self.container); 451 } 452 453 this.goFull = function() { 454 if (this.element.requestFullscreen) this.element.requestFullscreen(); 455 else if(this.element.mozRequestFullScreen) this.element.mozRequestFullScreen(); 456 else if(this.element.webkitRequestFullscreen) this.element.webkitRequestFullscreen(); 457 else if(this.element.msRequestFullscreen) this.element.msRequestFullscreen(); 458 } 459 460 this.exitFull = function() { 461 if (document.exitFullscreen) document.exitFullscreen(); 462 else if(document.mozCancelFullScreen) document.mozCancelFullScreen(); 463 else if(document.webkitExitFullscreen) document.webkitExitFullscreen(); 464 } 465 466 this.isFull = function() { 467 if (window.innerHeight == screen.height) { 468 return true; 469 } else { 470 return false; 471 } 472 } 473 } 474 475 // Functions 476 var processData = function(data) { 477 self.data = data; 478 var nrlevels = 0; 479 var shownLevel; 480
481 self.container = $('<div></div>').addClass('mapplic-container').appendTo(self.el); 482 self.map = $('<div></div>').addClass('mapplic-map').appendTo(self.container); 483 484 self.levelselect = $('<select></select>').addClass('mapplic-levels-select'); 485 486 if (!self.o.sidebar) self.container.css('width', '100%'); 487 488 self.contentWidth = data.mapwidth; 489 self.contentHeight = data.mapheight; 490 491 self.hw_ratio = data.mapheight / data.mapwidth; 492 if (data.mapheight / self.container.height() > data.mapwidth / self.container.width()) { 493 self.min_width = self.container.width(); 494 self.min_height = self.container.width() * self.hw_ratio; 495 } 496 else { 497 self.min_height = self.container.height(); 498 self.min_width = self.container.height() / self.hw_ratio; 499 } 500 501 self.map.css({ 502 'width': data.mapwidth, 503 'height': data.mapheight 504 }); 505 506 // Create minimap 507 if (self.o.minimap) { 508 self.minimap = new Minimap(); 509 self.minimap.init(); 510 } 511 512 // Create sidebar 513 if (self.o.sidebar) { 514 self.sidebar = new Sidebar(); 515 self.sidebar.init(); 516 self.sidebar.addCategories(data.categories); 517 } 518 519 // Iterate through levels 520 if (data.levels) { 521 $.each(data.levels, function(index, value) { 522 var source = value.map; 523 var extension = source.substr((source.lastIndexOf('.') + 1)).toLowerCase(); 524 525 // Create new map layer
526 var layer = $('<div></div>').addClass('mapplic-layer').addClass(value.id).hide().appendTo(self.map); 527 switch (extension) { 528 529 // Image formats 530 case 'jpg': case 'jpeg': case 'png': case 'gif': 531 $('<img>').attr('src', source).addClass('mapplic-map-image').appendTo(layer); 532 break; 533 534 // Vector format 535 case 'svg': 536 $('<div></div>').addClass('mapplic-map-image').load(source).appendTo(layer); 537 break; 538 539 // Other 540 default: 541 alert('File type ' + extension + ' is not supported!'); 542 } 543 544 // Create new minimap layer 545 if (self.minimap) self.minimap.addLayer(value); 546 547 // Build layer control 548 self.levelselect.prepend($('<option></option>').attr('value', value.id).text(value.title)); 549 550 if (!shownLevel || value.show) { 551 shownLevel = value.id; 552 } 553 554 /* Iterate through locations */ 555 $.each(value.locations, function(index, value) { 556 var top = value.y * 100; 557 var left = value.x * 100; 558 559 if (value.pin != 'hidden') { 560 if (self.o.locations) { 561 var target = '#' + value.id; 562 if (value.action == 'redirect') target = value.link; 563 564 var pin = $('<a></a>').attr('href', target).addClass('mapplic-pin').css({'top': top + '%', 'left': left + '%'}).appendTo(layer); 565 pin.attr('data-location', value.id); 566 pin.addClass(value.pin); 567 } 568 } 569 570 if (self.sidebar) self.sidebar.addLocation(value); 571 }); 572 573 nrlevels++; 574 }); 575 } 576 577 // Pin animation 578 if (self.o.animate) { 579 $('.mapplic-pin').css('opacity', '0'); 580 window.setTimeout(animateNext, 200); 581 } 582 583 function animateNext() { 584 var select = $('.mapplic-pin:not(.mapplic-animate):visible'); 585 586 //console.log('enter'); 587 588 if (select.length > 0) { 589 select.first().addClass('mapplic-animate'); 590 window.setTimeout(animateNext, 200); 591 } 592 else { 593 $('.mapplic-animate').removeClass('mapplic-animate'); 594 $('.mapplic-pin').css('opacity', '1'); 595 } 596 } 597 598 // COMPONENTS 599 600 // Hover Tooltip 601 if (self.o.hovertip) self.hovertip = new HoverTooltip().init(); 602 603 // Tooltip 604 self.tooltip = new Tooltip(); 605 self.tooltip.init(); 606 607 // Developer tools 608 if (self.o.developer) self.devtools = new DevTools().init(); 609 610 // Clear button 611 if (self.o.clearbutton) self.clearbutton = new ClearButton().init(); 612 613 // Fullscreen 614 if (self.o.fullscreen) self.fullscreen = new FullScreen().init(); 615 616 // Levels 617 if (nrlevels > 1) { 618 self.levels = $('<div></div>').addClass('mapplic-levels'); 619 var up = $('<a href="#"></a>').addClass('mapplic-levels-up').appendTo(self.levels); 620 self.levelselect.appendTo(self.levels); 621 var down = $('<a href="#"></a>').addClass('mapplic-levels-down').appendTo(self.levels); 622 self.container.append(self.levels); 623 624 self.levelselect.change(function() { 625 var value = $(this).val(); 626 level(value); 627 }); 628 629 up.click(function(e) { 630 e.preventDefault(); 631 if (!$(this).hasClass('disabled')) level('+'); 632 }); 633 634 down.click(function(e) { 635 e.preventDefault(); 636 if (!$(this).hasClass('disabled')) level('-'); 637 }); 638 } 639 level(shownLevel); 640 641 // Browser resize 642 $(window).resize(function() { 643 var wr = self.container.width() / self.contentWidth, 644 hr = self.container.height() / self.contentHeight; 645 646 if (wr > hr) self.fitscale = wr; 647 else self.fitscale = hr; 648 649 self.scale = normalizeScale(self.scale); 650 self.x = normalizeX(self.x); 651 self.y = normalizeY(self.y); 652 653 moveTo(self.x, self.y, self.scale, 100); 654 }).resize(); 655 656 // Deeplinking 657 if (self.o.deeplinking) { 658 self.deeplinking = new Deeplinking(); 659 self.deeplinking.init(); 660 } 661 } 662 663 var addControls = function() { 664 var map = self.map, 665 mapbody = $('.mapplic-map-image', self.map); 666 667 document.ondragstart = function() { return false; } // IE drag fix 668 669 // Drag & drop 670 mapbody.on('mousedown', function(event) { 671 map.stop(); 672 673 map.data('mouseX', event.pageX); 674 map.data('mouseY', event.pageY); 675 map.data('lastX', self.x); 676 map.data('lastY', self.y); 677 678 map.addClass('mapplic-dragging'); 679 680 self.map.on('mousemove', function(event) { 681 var x = event.pageX - map.data('mouseX') + self.x; 682 y = event.pageY - map.data('mouseY') + self.y; 683 684 x = normalizeX(x); 685 y = normalizeY(y); 686 687 moveTo(x, y); 688 map.data('lastX', x); 689 map.data('lastY', y); 690 }); 691 692 $(document).on('mouseup', function(event) { 693 self.x = map.data('lastX'); 694 self.y = map.data('lastY'); 695 696 self.map.off('mousemove'); 697 $(document).off('mouseup'); 698 699 map.removeClass('mapplic-dragging'); 700 }); 701 }); 702 703 // Double click 704 $(document).on('dblclick', '.mapplic-map-image', function(event) { 705 var mapPos = self.map.offset(); 706 var x = (event.pageX - mapPos.left) / self.map.width(); 707 var y = (event.pageY - mapPos.top) / self.map.height(); 708 var z = self.map.width() / self.min_width * 2; 709 710 zoomTo(x, y, z, 600); 711 }); 712 713 // Mousewheel 714 $('.mapplic-layer', this.el).bind('mousewheel DOMMouseScroll', function(event, delta) { 715 event.preventDefault(); 716 717 var scale = self.scale; 718 self.scale = normalizeScale(scale + scale * delta/5); 719 720 self.x = normalizeX(self.x - (event.pageX - self.container.offset().left - self.x) * (self.scale/scale - 1)); 721 self.y = normalizeY(self.y - (event.pageY - self.container.offset().top - self.y) * (self.scale/scale - 1)); 722 723 moveTo(self.x, self.y, self.scale, 100); 724 }); 725 726 // Touch support 727 if (!('ontouchstart' in window || 'onmsgesturechange' in window)) return true; 728 729 mapbody.on('touchstart', function(e) { 730 var orig = e.originalEvent, 731 pos = map.position(); 732 733 map.data('touchY', orig.changedTouches[0].pageY - pos.top); 734 map.data('touchX', orig.changedTouches[0].pageX - pos.left); 735 736 mapbody.on('touchmove', function(e) { 737 e.preventDefault(); 738 var orig = e.originalEvent; 739 var touches = orig.touches.length; 740 741 if (touches == 1) { 742 self.x = normalizeX(orig.changedTouches[0].pageX - map.data('touchX')); 743 self.y = normalizeY(orig.changedTouches[0].pageY - map.data('touchY')); 744 745 moveTo(self.x, self.y, self.scale, 100); 746 } 747 else { 748 mapbody.off('touchmove'); 749 } 750 }); 751 752 mapbody.on('touchend', function(e) { 753 mapbody.off('touchmove touchend'); 754 }); 755 }); 756 757 // Pinch zoom 758 var mapPinch = Hammer(self.map[0], { 759 transform_always_block: true, 760 drag_block_horizontal: true, 761 drag_block_vertical: true 762 }); 763 764 var scale=1, last_scale; 765 766 mapPinch.on('touch transform', function(ev) { 767 switch(ev.type) { 768 case 'touch': 769 last_scale = scale; 770 break; 771 772 case 'transform': 773 var center = ev.gesture.center; 774 scale = Math.max(1, Math.min(last_scale * ev.gesture.scale, 10)); 775 776 var oldscale = self.scale; 777 self.scale = normalizeScale(scale * self.fitscale); 778 779 self.x = normalizeX(self.x - (center.pageX - self.container.offset().left - self.x) * (self.scale/oldscale - 1)); 780 self.y = normalizeY(self.y - (center.pageY - self.container.offset().top - self.y) * (self.scale/oldscale - 1)); 781 782 moveTo(self.x, self.y, self.scale, 200);
783 784 break; 785 } 786 }); 787 } 788 789 var level = function(target) { 790 switch (target) { 791 case '+': 792 target = $('option:selected', self.levelselect).removeAttr('selected').prev().prop('selected', 'selected').val(); 793 break; 794 case '-': 795 target = $('option:selected', self.levelselect).removeAttr('selected').next().prop('selected', 'selected').val(); 796 break; 797 default: 798 $('option[value="' + target + '"]', self.levelselect).prop('selected', 'selected'); 799 } 800 801 var layer = $('.mapplic-layer.' + target, self.map); 802 803 // Target layer is active 804 if (layer.is(':visible')) return; 805 806 // Hide Tooltip 807 self.tooltip.hide(); 808 809 // Show target layer 810 $('.mapplic-layer:visible', self.map).hide(); 811 layer.show(); 812 813 // Show target minimap layer 814 if (self.minimap) self.minimap.show(target); 815 816 // Update control 817 var index = self.levelselect.get(0).selectedIndex, 818 up = $('.mapplic-levels-up', self.levels), 819 down = $('.mapplic-levels-down', self.levels); 820 821 up.removeClass('disabled'); 822 down.removeClass('disabled'); 823 if (index == 0) { 824 up.addClass('disabled'); 825 } 826 else if (index == self.levelselect.get(0).length - 1) { 827 down.addClass('disabled'); 828 } 829 } 830 831 var getLocationData = function(id) { 832 var data = null; 833 $.each(self.data.levels, function(index, layer) { 834 $.each(layer.locations, function(index, value) { 835 if (value.id == id) { 836 data = value; 837 } 838 }); 839 }); 840 return data; 841 } 842 843 var showLocation = function(id, duration) { 844 $.each(self.data.levels, function(index, layer) { 845 $.each(layer.locations, function(index, value) { 846 if (value.id == id) { 847 var zoom = typeof value.zoom !== 'undefined' ? value.zoom : 4, 848 drop = self.tooltip.drop / self.contentHeight / zoom; 849 850 level(layer.id); 851 852 zoomTo(value.x, parseFloat(value.y) - drop, zoom, duration, 'easeInOutCubic'); 853 } 854 }); 855 }); 856 }; 857 858 var normalizeX = function(x) { 859 var minX = self.container.width() - self.contentWidth * self.scale; 860 861 if (x > 0) x = 0; 862 else if (x < minX) x = minX; 863 864 return x; 865 } 866 867 var normalizeY = function(y) { 868 var minY = self.container.height() - self.contentHeight * self.scale; 869 870 if (y >= 0) y = 0; 871 else if (y < minY) y = minY; 872 873 return y; 874 } 875 876 var normalizeScale = function(scale) { 877 if (scale < self.fitscale) scale = self.fitscale; 878 else if (scale > self.o.maxscale) scale = self.o.maxscale; 879 880 return scale; 881 } 882 883 var zoomTo = function(x, y, s, duration, easing) { 884 duration = typeof duration !== 'undefined' ? duration : 400; 885 886 self.scale = normalizeScale(self.fitscale * s); 887 var scale = self.contentWidth * self.scale; 888 889 self.x = normalizeX(self.container.width() * 0.5 - self.scale * self.contentWidth * x); 890 self.y = normalizeY(self.container.height() * 0.5 - self.scale * self.contentHeight * y); 891 892 moveTo(self.x, self.y, self.scale, duration, easing); 893 } 894 895 var moveTo = function(x, y, scale, d, easing) { 896 if (scale !== undefined) { 897 self.map.stop().animate({ 898 'left': x, 899 'top': y, 900 'width': self.contentWidth * scale, 901 'height': self.contentHeight * scale 902 }, d, easing); 903 } 904 else { 905 self.map.css({ 906 'left': x, 907 'top': y 908 }); 909 } 910 if (self.minimap) self.minimap.update(x, y); 911 } 912 }; 913 914 // Create a jQuery plugin 915 $.fn.mapplic = function(params) { 916 var len = this.length; 917 918 return this.each(function(index) { 919 var me = $(this), 920 key = 'mapplic' + (len > 1 ? '-' + ++index : ''), 921 instance = (new Mapplic).init(me, params); 922 923 me.data(key, instance).data('key', key); 924 }); 925 }; 926})(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.