MediaWiki:InteractiveMaps.js
Vai alla navigazione
Vai alla ricerca
Nota: dopo aver salvato, potrebbe essere necessario pulire la cache del proprio browser per vedere i cambiamenti.
- Firefox / Safari: tenere premuto il tasto delle maiuscole Shift e fare clic su Ricarica, oppure premere Ctrl-F5 o Ctrl-R (⌘-R su Mac)
- Google Chrome: premere Ctrl-Shift-R (⌘-Shift-R su un Mac)
- Internet Explorer: tenere premuto il tasto Ctrl e fare clic su Aggiorna, oppure premere Ctrl-F5
- Opera: Vai nel Menu → Impostazioni (Opera → Preferenze su un Mac) e poi in Privacy & sicurezza → Pulisci dati del browser → Immagini e file nella cache.
'use strict';
/*
* ZoomableMap v1.5
* Copyright (c) 2022 Jesús Martínez (User:Ciencia_Al_Poder)
*
* Allow zooming and scrolling of an image within a page.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*/
(function( $ ) {
var _sensibility = 2,
_init = function() {
$( '.zoomablemap' ).each( function() {
$( this ).data( 'zoomablemap', new ZoomableMap( this ) );
} );
},
_initZoomableMap = function() {
var $controls, $zoomin, $zoomout;
this.$mapCont = $( '<div class="mapcontent"></div>' ).append( $('<div class="mapinner"></div>').append( this.$el.contents() ) );
$controls = $( '<div class="mapcontrols"></div>' );
$zoomin = $( '<div class="control zoomin" tabindex="0" role="button"></div>' ).text( '+' ).on( 'click', _eventDelegate( this, _zoomIn ) );
$zoomout = $( '<div class="control zoomout" tabindex="0" role="button"></div>' ).text( '-' ).on( 'click', _eventDelegate( this, _zoomOut ) );
$controls.append( $zoomin, $zoomout );
this.$el.append( this.$mapCont, $controls );
this.$mapCont.on( {
pointerdown: _eventDelegate( this, _pointerDown ),
wheel: _eventDelegate( this, _wheel )
} );
_updateScale.call( this, -1 );
this.$el.addClass( 'loadcomplete' );
},
_eventDelegate = function( thisArg, fn ) {
return function( e ) {
return fn.call( thisArg, e );
};
},
_zoomIn = function() {
_updateScale.call( this, 0.1 );
return false;
},
_zoomOut = function() {
_updateScale.call( this, -0.1 );
return false;
},
_wheel = function( e ) {
_updateScale.call( this, e.originalEvent.deltaY > 0 ? -0.1 : 0.1 );
return false;
},
_updateScale = function( delta ) {
var rect, newScale, minScale, innerDimensions;
newScale = this.scale + delta;
if ( newScale < 0.1 ) {
newScale = 0.1;
}
innerDimensions = _getInnerDimensions.call( this );
// If the element is hidden (collapsible sections) this will be an empty array
rect = this.$mapCont[0].getClientRects();
if ( !rect || rect.length === 0 ) {
return;
}
// Lower limit is to fit the contents on the current width
minScale = Math.min( rect[0].width / innerDimensions.width, rect[0].height / innerDimensions.height );
if ( newScale < minScale ) {
newScale = minScale;
}
if ( newScale > 1 ) {
newScale = 1;
}
this.scale = newScale;
this.$mapCont.find( '> .mapinner' ).eq( 0 ).css( {
transform: 'scale(' + String( newScale ) + ')',
height: String( innerDimensions.height * newScale ) + 'px'
} );
},
_pointerDown = function( e ) {
var pos = _getEventCoordinates( e, this.$mapCont[0] );
e = e.originalEvent;
// Retarget all pointer events (until pointerup)
this.$mapCont[0].setPointerCapture( e.pointerId );
if ( e.isPrimary ) {
this.dragStartPoint = pos;
this.pointerCache = [];
this.initialPointerDistance = 0;
this.$mapCont.on( {
'pointermove': _eventDelegate( this, _dragMove ),
'pointerup': _eventDelegate( this, _dragEnd )
} );
this.$mapCont.addClass( 'pointerdown' );
}
// Allow max 2 pointers
if ( this.pointerCache !== null && this.pointerCache.length < 2 ) {
this.pointerCache.push( { id: e.pointerId, x: pos.x, y: pos.y } );
// On 2nd pointer, set initial zoom position
if ( !e.isPrimary ) {
this.initialPointerDistance = _getPointDistance.call( this );
this.initialPinchZoomScale = this.scale;
}
}
return false;
},
_dragMove = function( e ) {
var newPos, newProps, newDistance;
newPos = _getEventCoordinates( e, this.$mapCont[0] );
e = e.originalEvent;
// This should never happen
if ( this.pointerCache === null ) {
return;
}
// Update point cache
for ( var i = 0; i < this.pointerCache.length; i++ ) {
if ( this.pointerCache[ i ].id == e.pointerId ) {
this.pointerCache[ i ].x = newPos.x;
this.pointerCache[ i ].y = newPos.y;
break;
}
}
if ( e.isPrimary ) {
newProps = {
scrollLeft: this.dragStartPoint.scrollLeft - newPos.x + this.dragStartPoint.x,
scrollTop: this.dragStartPoint.scrollTop - newPos.y + this.dragStartPoint.y
};
this.$mapCont.prop( newProps );
}
if ( this.pointerCache.length == 2 && this.initialPointerDistance > 0 ) {
newDistance = _getPointDistance.call( this );
_updateScale.call( this, this.initialPinchZoomScale * newDistance / this.initialPointerDistance - this.scale );
}
if ( !this.dragging ) {
this.$mapCont.addClass( 'dragging' );
this.dragging = true;
}
},
_dragEnd = function( e ) {
var newPos, propagate = false;
e = e.originalEvent;
if ( !this.pointerCache ) {
return;
}
// Remove pointer from cache
for ( var i = 0; i < this.pointerCache.length; i++ ) {
if ( this.pointerCache[ i ].id == e.pointerId ) {
this.pointerCache.splice( i, 1 );
break;
}
}
if ( !e.isPrimary ) {
return;
}
newPos = _getEventCoordinates( e, this.$mapCont[0] );
// If it hasn't scrolled, propagate the event
if (
Math.abs( newPos.x - this.dragStartPoint.x ) <= _sensibility &&
Math.abs( newPos.y - this.dragStartPoint.y ) <= _sensibility
) {
propagate = true;
}
this.$mapCont.off( 'pointermove pointerup' ).removeClass( 'pointerdown' );
this.dragStartPoint = null;
this.dragging = false;
this.$mapCont.removeClass( 'dragging' );
this.pointerCache = null;
if ( propagate ) {
this.$el.trigger( $.Event( 'mapclick', { clientX: e.clientX, clientY: e.clientY } ) );
}
},
_getPointDistance = function() {
var xx, yy;
xx = this.pointerCache[ 0 ].x - this.pointerCache[ 1 ].x;
yy = this.pointerCache[ 0 ].y - this.pointerCache[ 1 ].y;
return Math.sqrt( xx * xx + yy * yy );
},
/* Given an event and element, returns pointer coordinates and scroll position of element */
_getEventCoordinates = function( event, el ) {
return {
x: event.clientX,
y: event.clientY,
scrollLeft: el.scrollLeft,
scrollTop: el.scrollTop
};
},
_getInnerDimensions = function() {
var innerEl;
if ( !this.innerDimensions ) {
innerEl = this.$mapCont.find( '> .mapinner' )[0];
if ( innerEl.scrollWidth === 0 || innerEl.scrollHeight === 0 ) {
return null;
}
this.innerDimensions = { width: innerEl.scrollWidth, height: innerEl.scrollHeight };
}
return this.innerDimensions;
};
// Class ZoomableMap
function ZoomableMap( el ) {
this.$el = $( el );
this.$mapCont = null;
this.dragStartPoint = null;
this.dragging = false;
this.scale = 1;
this.pointerCache = null;
this.innerDimensions = null;
this.initialPointerDistance = 0;
this.initialPinchZoomScale = 0;
_initZoomableMap.call( this );
}
$(_init);
})( $ );
/*******************************************************************************
* LPAInteractiveMaps
* Copyright (c) 2022 Pokémon Central
*
* Interactive maps for Leggende Pokémon: Arceus on Pokémon Central Wiki
*
* This program is heavily based on MapaLPAInteractivo v1.5
* (https://www.wikidex.net/wiki/MediaWiki:Gadget-MapaLPAInteractivo.js) by
* Jesús Martínez (User:Ciencia_Al_Poder). All due credits to the original
* author.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version
*/
(function( $ ) {
// WARNING: Doesn't support multiple maps in a page
var _buckets = {},
_mapData = {},
_svg = null,
_downCoords = null,
_sensibility = 5,
_pointRadius = 15,
_originalWidth = 2048,
_originalHeight = 2048,
_selectedPoint = null,
_useMapUpFallback = true,
_expandedPointTypes = {
s: 'm_estrella',
a: 'm_arbol',
c: 'm_caja',
r: 'm_roca',
w: 'm_distorsion'
},
_init = function() {
$( '#interactive-map-controller' ).each( _initializeTable );
},
_initializeTable = function() {
var $table = $( this ), origTablePosition, localPoints;
// This thing of detaching and reattaching the table is used to remove the
// table if anything goes wrong during the load
origTablePosition = _detachElement( $table );
try {
$table.find( '> tbody > tr[data-principal]' ).each( function() {
var $tr = $( this ), $td = $tr.find( '> td:eq(2)' );
if ( $tr.data( 'principal' ) === 1 ) {
$( '<label class="det"><input type="checkbox"/><span>Dettagli</span></label> ' ).prependTo( $td );
}
$( '<label class="map"><input type="checkbox"/><span>Mappa</span></label> ' ).prependTo( $td );
} ).filter( '[data-principal="0"]' ).each( function() {
// Hide secondary
var $tr = $( this ).hide(), $prev = $tr.prev();
localPoints = _parsePointData( $tr.data( 'pointdata' ) );
// Generate ids for coordinates
$tr.data( 'ids', $.map( localPoints, function( el ) {
return el.id;
} ).join( ',' ) );
} );
$table.on( 'change', _onChange );
_generateMap();
} catch( e ) {
console.log(e);
}
_reattachElement( $table, origTablePosition );
$( '#interactive-map .markupmap' ).eq( 0 ).on( {
mousedown: _mapDown,
mouseup: _mapUp
} ).closest( '.zoomablemap' ).on( {
mapclick: _zoomableMapClick
} );
},
/*
* Remove and element from the DOM without deleting it (ie. detach it), and
* returns its former position (either its previous sibiling, if any, or its
* parent)
*/
_detachElement = function( $el ) {
var $prev, $parent;
$prev = $el.prev();
$parent = $el.parent();
$el.detach();
if ( $prev.length > 0 ) {
return [ $prev, null ];
}
return [ null, $parent ];
},
/*
* Reattach an element detached with _detachElement
*/
_reattachElement = function( $el, origPosition ) {
if ( origPosition[0] ) {
$el.insertAfter( origPosition[0] );
} else {
$el.prependTo( origPosition[1] );
}
},
/*
* Handler for changed selected checkbox. It determines wheter it's a "detail"
* or "map" checkbox, and dispatches the right sub-handler (right below).
*/
_onChange = function( e ) {
var $target = $( e.target ), $label = $target.closest( 'label' ), checked = $target.is( ':checked' ), $tr;
$tr = $target.closest( 'tr' );
if ( $label.hasClass( 'det' ) ) {
_detailsChange( $tr, checked );
} else if ( $label.hasClass( 'map' ) ) {
_mapChange( $tr, $target, checked );
}
},
/*
* Handler for a change in the selected "details" checkbox
*/
_detailsChange = function( $tr, checked ) {
var pp, fn, $prev;
fn = checked ? 'show' : 'hide';
while ( 1 ) {
$tr = $tr.next();
pp = $tr.data( 'principal' );
if ( $tr.length === 0 || pp === 1 ) {
break;
}
if ( typeof( pp ) == 'undefined' ) {
continue;
}
$tr[fn]();
}
},
/*
* Handler for a change in the selected "map" checkbox
*/
_mapChange = function( $tr, $target, checked ) {
let recomputeList = false;
let $table = $tr.closest( 'table' );
// lch is the list of checked labels
let $lch = $table.find( 'label.map > input:checked' );
// If a point were selected, makes all the rows visible according to
// checkboxes again before applying the change
if ( _selectedPoint ) {
_reapplyTableRowVisibility( $table );
_selectedPoint = null;
}
// The user has unchecked the checkbox
if ( !checked ) {
if ( _selectedPoint || $tr.data( 'principal' ) === 1 ) {
// If there's a selected point, or it's the group heading, uncheck all
$lch.each( function() {
this.checked = false;
} );
$lch = $();
}
else {
// If it's the detail row, unckeck the group heading
let $tr2 = $tr;
while ( 1 ) {
$tr2 = $tr2.prev();
if ( $tr2.length === 0 ) {
break;
}
if ( $tr2.data( 'principal' ) === 1 ) {
let $input2 = $tr2.find( 'label.map > input' );
if ( $input2[0].checked ) {
$input2[0].checked = false;
recomputeList = true;
}
break;
}
}
}
}
// The user has checked the checkbox
else {
if ( $tr.data( 'principal' ) === 1 ) {
// If it's the group heading, mark all from the group, but first unmark everything
$lch.each( function() {
this.checked = false;
} );
let $tr2 = $tr;
while ( 1 ) {
$tr2 = $tr2.next();
if ( $tr2.length === 0 || $tr2.data( 'principal' ) === 1 ) {
break;
}
let $input2 = $tr2.find( 'label.map > input' );
$input2[0].checked = true;
recomputeList = true;
}
$target[0].checked = true;
} else {
// Not principal checkes
if ( $lch.length > 1 ) {
// Check a *different* row
let $tr2;
if ( $lch[0] === $target[0] ) {
$tr2 = $lch.eq( 1 ).closest( 'tr' );
} else {
$tr2 = $lch.eq( 0 ).closest( 'tr' );
}
while ( 1 ) {
if ( $tr2.length === 0 || $tr2.data( 'principal' ) === 1 ) {
break;
}
$tr2 = $tr2.prev();
}
// Check against our row
let $tr3 = $tr;
while ( 1 ) {
if ( $tr3.length === 0 || $tr3.data( 'principal' ) === 1 ) {
break;
}
$tr3 = $tr3.prev();
}
if ( $tr3.length === 0 || $tr2.length === 0 || $tr3[0] !== $tr2[0] ) {
// Different group. Unmark all
$lch.each( function() {
this.checked = false;
} );
$lch = $target.prop( 'checked', true );
}
}
}
}
if ( recomputeList ) {
$lch = $tr.closest( 'table' ).find( 'label.map > input:checked' );
}
let points = $lch.map( function() {
const ids = $( this ).closest( 'tr' ).data( 'ids' );
if ( ids ) {
return ids.split( ',' );
}
} ).get();
_generateMap( points );
},
/*
* Parse the field data-pointdata of a table row. Adds the elements to _mapData
*/
_parsePointData = function( str ) {
var coords = str.split( ',' ), ret;
ret = $.map( coords, function( coord ) {
var parts, x, y, id, el;
parts = coord.split( ':' );
x = parseFloat( parts[1] );
y = parseFloat( parts[2] );
id = _createIdForCoords( x, y );
el = { id: id, t: parts[0], x: x, y: y };
_mapData[ id ] = el;
return el;
} );
return ret;
},
_createIdForCoords = function( x, y ) {
var xx, yy, bkey, seq, id, point;
xx = String.fromCharCode( 65 + Math.trunc( x * 26 / _originalWidth ) );
yy = String( Math.trunc( y * 26 / _originalHeight ) + 1 );
bkey = xx + yy;
if ( ! ( bkey in _buckets ) ) {
_buckets[ bkey ] = [];
}
seq = _buckets[ bkey ].length;
for ( var i = 0; i < seq; i++ ) {
id = _buckets[ bkey ][ i ];
point = _mapData[ id ];
if ( point.x == x && point.y == y ) {
return id;
}
}
id = bkey + String.fromCharCode( 97 + seq );
_buckets[ bkey ].push( id );
return id;
},
/*
* Generate the overlay map with markers that is displayed over the "base" map
* image. If filterIds is an array, only shows markers corresponding to ids in
* filterIds.
*
* If I got it right, this thing creates an image and assign it a temporary
* URL, then loads it in the page as if it were a normal image.
*/
_generateMap = function( filterIds ) {
var svgData, blob;
svgData = '<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:w="https://schemas.wikidex.net/svg/generic" width="2048" height="2048" viewBox="0 0 2048 2048" version="1.1"><defs><filter id="invertColor" color-interpolation-filters="sRGB"><feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" /></filter><g id="m_estrella" transform="scale(0.6)"><path d="M -0.00164411,-27.941229 6.5673111,-9.0431814 26.570342,-8.63555 10.627149,3.4517155 16.420745,22.601693 -0.00164481,11.173986 -16.424036,22.601692 -10.630439,3.4517155 -26.573631,-8.6355515 -6.5706009,-9.0431814 Z" style="fill:#fcf7db;stroke:#000000;stroke-width:2" /></g><g id="m_distorsion" transform="scale(0.6)"><path d="m 10.898436,-19.664347 c -0.677587,-0.0649 -1.573603,0.42932 -2.251952,0.66016 -1.51606,0.5159 -3.107422,1.29207 -5.808594,1.26367 -2.25520899,-0.0237 -4.683473,-0.51286 -6.755859,0.37695 -2.257217,0.96917 -4.243107,2.86657 -5.367188,5.05078 -1.360569,2.64373 -1.032942,5.87122 -1.199219,8.83985 -0.02794,0.49879 -0.154571,1.08489 -0.294922,1.6875 -0.207206,-0.15406 -0.405503,-0.306 -0.564453,-0.45313 -0.85685,-1.14842 -0.646419,-2.92869 -1.261719,-4.29297 -0.69805,-1.54775 -2.319055,-3.10109 -4.546875,-4.41992 -0.65018,-0.38489 -1.650675,-1.01298 -2.208985,-0.5039 -0.70597,0.64374 0.07113,1.93537 0.378907,2.83984 0.5159,1.51606 1.290118,3.10741 1.261719,5.80859 -0.02371,2.2551999 -0.510904,4.68347 0.378906,6.75586 0.96917,2.25722 2.866571,4.2431 5.050781,5.36719 2.643731,1.36056 5.871215,1.03295 8.839845,1.19922 0.49827,0.0279 1.083594,0.15474 1.685547,0.29492 -0.153504,0.20634 -0.304551,0.40605 -0.451172,0.56445 -1.148414,0.85685 -2.928688,0.64642 -4.292969,1.26172 -1.547744,0.69805 -3.101094,2.31906 -4.419923,4.54688 -0.384895,0.65018 -1.014948,1.65067 -0.505859,2.20898 0.643733,0.70597 1.937333,-0.0711 2.841798,-0.3789 1.51606,-0.5159 3.107421,-1.29012 5.808593,-1.26172 2.25520901,0.0237 4.683474,0.5109 6.75586,-0.37891 2.257217,-0.96917 4.241153,-2.86657 5.365234,-5.05078 1.360567,-2.6437298 1.032941,-5.87121 1.199218,-8.83984 0.02791,-0.49827 0.15669,-1.0836 0.296875,-1.68555 0.20625,0.15345 0.404152,0.3046 0.5625,0.45117 0.85685,1.14842 0.648372,2.92869 1.263672,4.29297 0.69805,1.54775 2.317102,3.1010902 4.544922,4.41992 0.65018,0.38489 1.652627,1.01299 2.210937,0.50391 0.70597,-0.64374 -0.07113,-1.9353798 -0.378906,-2.83985 -0.5159,-1.51606 -1.292072,-3.10741 -1.263672,-5.80859 0.02371,-2.25520005 0.510904,-4.68347 -0.378906,-6.75586 -0.96917,-2.25722 -2.866572,-4.24114 -5.050781,-5.36523 -2.64373,-1.36056 -5.86926,-1.03491 -8.83789,-1.20118 -0.498789,-0.0279 -1.084888,-0.15457 -1.6875,-0.29492 0.153549,-0.20641 0.306462,-0.406 0.453125,-0.56445 1.148414,-0.85685 2.928688,-0.64642 4.292969,-1.26172 1.547744,-0.69805 3.101094,-2.31905 4.41992,-4.54687 0.384896,-0.65018 1.012996,-1.65068 0.503907,-2.20899 -0.160933,-0.17649 -0.362028,-0.25962 -0.587891,-0.28125 z M 0,-8.549107 A 8.5714283,8.5714283 0 0 1 8.570312,0.0212029 8.5714283,8.5714283 0 0 1 0,8.593463 8.5714283,8.5714283 0 0 1 -8.572266,0.0212029 8.5714283,8.5714283 0 0 1 0,-8.549107 Z" style="fill:#fcf7db;stroke:#000000;stroke-width:2" /></g><g id="m_arbol" transform="scale(0.6)"><path d="m 14.753887,-12.60332 c 2.321432,12.92478948 -20.7866602,27.5195 -35.289063,12.07030948 -0.11441,0.858 -0.175075,1.72232012 -0.18164,2.58789012 C -20.716942,13.52671 -11.417159,22.82649 0.05466773,22.82637 11.526496,22.82649 20.826279,13.52671 20.826153,2.0548796 c -0.0047,-5.49708 -2.188285,-10.76814 -6.072266,-14.6581996 z" style="fill:#fcf7db;stroke:#000000;stroke-width:2;" /><path d="m -0.19533227,-19.90606 c -0.99263503,0.0139 -2.00287793,0.10422 -3.01562493,0.26954 -0.463143,0.0783 -0.925867,0.17216 -1.386719,0.28125 -0.355533,2.09759 -2.33e-4,3.54672 0.643581,4.99609 l -1.294071,0.18821 c -1.723492,-2.38726 -2.139709,-5.31489 -2.147505,-8.18333 -2.7873118,-0.72381 -5.1244078,-0.40649 -6.9571998,1.04456 0.10172,4.35807 2.022044,7.58509 5.0637888,10.01114 l -0.9787828,1.0417 c -1.62928,-0.7875 -3.019008,-1.54784 -4.400123,-3.65889 -2.396701,2.42115 -3.717804,5.2353396 -3.720703,7.9257796 5.98e-4,6.17023988 6.795591,10.06483 15.1777338,8.69922 8.38303,-1.36564 15.1792642,-7.47543 15.1796882,-13.6464896 1.28e-4,-5.31558 -5.0869382,-9.06635 -12.16406327,-8.96875 z" style="fill:#fcf7db;stroke:#000000;stroke-width:2;" /></g><g id="m_caja" transform="scale(0.6)"><rect ry="2.5" y="1.0535715" x="-18.549109" height="12" width="37" style="fill:#fcf7db;stroke:#000000;stroke-width:2;" /><rect ry="2.5" y="-12.946428" x="-18.549109" height="20" width="37" style="fill:#fcf7db;stroke:#000000;stroke-width:2;" /><rect ry="1.2" y="6.0535722" x="-6.5491071" height="2.4000001" width="12" style="fill:#000000;stroke:#000000;stroke-width:2;" /><rect ry="1.8" y="-7.2464285" x="-23.099108" height="14.27" width="3.6500001" style="fill:#fcf7db;stroke:#000000;stroke-width:2;" /><rect style="fill:#fcf7db;stroke:#000000;stroke-width:2;" width="3.6500001" height="14.27" x="19.450891" y="-7.2464285" ry="1.8" /></g><g id="m_roca" transform="scale(0.6)"><path d="m -14.910709,22.571429 5.8035696,-5.71429 -11.2499996,-10.7142804 3.125,-8.83929 7.05357,2.49999996 6.4285691,12.14286044 1.25,-0.35714 -3.39285,-25.80358 6.24999987,-8.03571 H 4.0617301 l 8.3489909,8.30357 -4.9107209,25.53572 0.71429,0.53571 5.6250009,-6.5178604 6.42857,-1.42857 0.26786,6.5178604 -6.51786,6.25 4.53639,5.62503 z" style="fill:#fcf7db;stroke:#000000;stroke-width:2;" /></g></defs>';
for ( var id in _mapData ) {
if ( _mapData.hasOwnProperty( id ) ) {
if ( !filterIds || filterIds.length == 0 || filterIds.indexOf( id ) != -1 ) {
if ( id != _selectedPoint ) {
svgData += _pointToSvgEl( _mapData[ id ], false );
}
}
}
}
if ( _selectedPoint ) {
svgData += _pointToSvgEl( _mapData[ _selectedPoint ], true );
}
svgData += '</svg>';
blob = new Blob( [ svgData ], { type : 'image/svg+xml' } );
if ( _svg ) {
URL.revokeObjectURL( _svg );
}
_svg = URL.createObjectURL( blob );
$( '#interactive-map .markupmap' ).eq( 0 ).empty().append( $( '<img>' ).attr( {
src: _svg,
width: _originalWidth,
height: _originalHeight
} ) );
},
/*
* Given a point (things stored in _mapData) return the svg code to display it.
*/
_pointToSvgEl = function( point, selected ) {
var extra = '';
if ( selected ) {
extra = ' style="filter:url(#invertColor)"';
}
return '<use xlink:href="#' + _expandedPointTypes[ point.t ] + '" x="' + point.x + '" y="' + point.y + '" w:id="' + point.id + '"' + extra + '/>';
},
_mapDown = function( e ) {
_downCoords = [ e.clientX, e.clientY ];
},
_mapUp = function( e ) {
var upCoords;
upCoords = [ e.clientX, e.clientY ];
// Discard event if it's scrolling
for ( var i = 0; i < 2; i++ ) {
if ( Math.abs( upCoords[ i ] - _downCoords[ i ] ) > _sensibility ) {
return;
}
}
_downCoords = null;
_mapUpFiltered.call( this, e );
return false;
},
_zoomableMapClick = function( e ) {
if ( _useMapUpFallback ) {
$( '#interactive-map .markupmap' ).eq( 0 ).off( 'mousedown mouseup' );
_useMapUpFallback = false;
}
_mapUpFiltered.call( this, e );
},
_mapUpFiltered = function( e ) {
var upCoords, hit, points, idx, newSelection = null;
upCoords = [ e.clientX, e.clientY ];
hit = _translateToMap( upCoords );
points = _getPointsInHit( hit );
if ( points.length > 0 ) {
if ( _selectedPoint && points.indexOf( _selectedPoint ) != -1 ) {
// One of the target points is the one previously selected
// Force changing the selection, or unselect
if ( points.length > 1 ) {
idx = points.indexOf( _selectedPoint );
if ( idx == points.length - 1 ) {
idx = 0;
} else {
idx++;
}
newSelection = points[ idx ];
}
} else {
newSelection = points[ 0 ];
}
}
if ( !_selectedPoint && !newSelection ) {
return;
}
_selectedPoint = newSelection;
_generateMap();
_filterTableWithPoint();
},
_translateToMap = function( coords ) {
var rect = $( '#interactive-map .markupmap img' )[ 0 ].getClientRects()[ 0 ], factor = 1;
factor = ( rect.right - rect.left ) / _originalWidth;
return [ ( coords[ 0 ] - rect.left ) / factor, ( coords[ 1 ] - rect.top ) / factor, factor ];
},
_getPointsInHit = function( hit ) {
var sensibility = _sensibility / hit[ 2 ], points = [], c1, c2;
for ( var id in _mapData ) {
if ( _mapData.hasOwnProperty( id ) ) {
c1 = Math.abs( _mapData[ id ].x - hit[ 0 ] );
c2 = Math.abs( _mapData[ id ].y - hit[ 1 ] );
if ( Math.sqrt( c1 * c1 + c2 * c2 ) - _pointRadius <= sensibility ) {
points.push( id );
}
}
}
return points;
},
_filterTableWithPoint = function() {
let $table = $( '#interactive-map-controller' ).eq( 0 )
let origTablePosition = _detachElement( $table );
try {
// Uncheck all "map" checkboxes
$table.find( 'label.map > input:checked' ).each( function() {
this.checked = false;
} );
if ( _selectedPoint ) {
// If one point is selected
$table.find( '> tbody > tr[data-principal]' ).each( function( idx ) {
let $tr = $( this );
let ids = $tr.data( 'ids' );
if ( !ids || ids.split( ',' ).indexOf( _selectedPoint ) === -1 ) {
$tr.hide();
} else {
$tr.show();
$tr.find( 'label.map > input' )[ 0 ].checked = true;
}
} );
}
else {
// If no point is selected, show the whole table
_reapplyTableRowVisibility( $table );
}
} catch( e ) {
console.log(e);
}
_reattachElement( $table, origTablePosition );
},
/*
* Reapply the visibility of table cells detemined by checkboxes (this could
* not be the case if a point was selected on the map)
*/
_reapplyTableRowVisibility = function( $table ) {
$table.find( '> tbody > tr[data-principal="1"]' ).each( function() {
var $tr = $( this ).show(), $prev, op;
// $prev = $tr.prev();
// if ( $prev.hasClass( 'sep' ) ) {
// $prev.show();
// }
op = $tr.find( 'label.det > input' )[0].checked ? 'show' : 'hide';
// Hide secondary
while ( 1 ) {
$tr = $tr.next();
if ( $tr.length === 0 || $tr.data( 'principal' ) !== 0 ) {
break;
}
$tr[ op ]();
}
} );
};
$(_init);
})( $ );