2020-07-24 03:01:32 +00:00
/ * *
* jVectorMap version 2.0 . 1
*
* Copyright 2011 - 2014 , Kirill Lebedev
*
* /
( function ( $ ) {
var apiParams = {
set : {
colors : 1 ,
values : 1 ,
backgroundColor : 1 ,
scaleColors : 1 ,
normalizeFunction : 1 ,
focus : 1
} ,
get : {
selectedRegions : 1 ,
selectedMarkers : 1 ,
mapObject : 1 ,
regionName : 1
}
} ;
$ . fn . vectorMap = function ( options ) {
var map ,
methodName ,
map = this . children ( '.jvectormap-container' ) . data ( 'mapObject' ) ;
if ( options === 'addMap' ) {
jvm . Map . maps [ arguments [ 1 ] ] = arguments [ 2 ] ;
} else if ( ( options === 'set' || options === 'get' ) && apiParams [ options ] [ arguments [ 1 ] ] ) {
methodName = arguments [ 1 ] . charAt ( 0 ) . toUpperCase ( ) + arguments [ 1 ] . substr ( 1 ) ;
return map [ options + methodName ] . apply ( map , Array . prototype . slice . call ( arguments , 2 ) ) ;
} else {
options = options || { } ;
options . container = this ;
map = new jvm . Map ( options ) ;
}
return this ;
} ;
} ) ( jQuery ) ;
/*! Copyright (c) 2013 Brandon Aaron (http:/ / brandon . aaron . sh )
* Licensed under the MIT License ( LICENSE . txt ) .
*
* Version : 3.1 . 9
*
* Requires : jQuery 1.2 . 2 +
* /
( function ( factory ) {
if ( typeof define === 'function' && define . amd ) {
// AMD. Register as an anonymous module.
define ( [ 'jquery' ] , factory ) ;
} else if ( typeof exports === 'object' ) {
// Node/CommonJS style for Browserify
module . exports = factory ;
} else {
// Browser globals
factory ( jQuery ) ;
}
} ( function ( $ ) {
var toFix = [ 'wheel' , 'mousewheel' , 'DOMMouseScroll' , 'MozMousePixelScroll' ] ,
toBind = ( 'onwheel' in document || document . documentMode >= 9 ) ?
[ 'wheel' ] : [ 'mousewheel' , 'DomMouseScroll' , 'MozMousePixelScroll' ] ,
slice = Array . prototype . slice ,
nullLowestDeltaTimeout , lowestDelta ;
if ( $ . event . fixHooks ) {
for ( var i = toFix . length ; i ; ) {
$ . event . fixHooks [ toFix [ -- i ] ] = $ . event . mouseHooks ;
}
}
var special = $ . event . special . mousewheel = {
version : '3.1.9' ,
setup : function ( ) {
if ( this . addEventListener ) {
for ( var i = toBind . length ; i ; ) {
this . addEventListener ( toBind [ -- i ] , handler , false ) ;
}
} else {
this . onmousewheel = handler ;
}
// Store the line height and page height for this particular element
$ . data ( this , 'mousewheel-line-height' , special . getLineHeight ( this ) ) ;
$ . data ( this , 'mousewheel-page-height' , special . getPageHeight ( this ) ) ;
} ,
teardown : function ( ) {
if ( this . removeEventListener ) {
for ( var i = toBind . length ; i ; ) {
this . removeEventListener ( toBind [ -- i ] , handler , false ) ;
}
} else {
this . onmousewheel = null ;
}
} ,
getLineHeight : function ( elem ) {
return parseInt ( $ ( elem ) [ 'offsetParent' in $ . fn ? 'offsetParent' : 'parent' ] ( ) . css ( 'fontSize' ) , 10 ) ;
} ,
getPageHeight : function ( elem ) {
return $ ( elem ) . height ( ) ;
} ,
settings : {
adjustOldDeltas : true
}
} ;
$ . fn . extend ( {
mousewheel : function ( fn ) {
return fn ? this . bind ( 'mousewheel' , fn ) : this . trigger ( 'mousewheel' ) ;
} ,
unmousewheel : function ( fn ) {
return this . unbind ( 'mousewheel' , fn ) ;
}
} ) ;
function handler ( event ) {
var orgEvent = event || window . event ,
args = slice . call ( arguments , 1 ) ,
delta = 0 ,
deltaX = 0 ,
deltaY = 0 ,
absDelta = 0 ;
event = $ . event . fix ( orgEvent ) ;
event . type = 'mousewheel' ;
// Old school scrollwheel delta
if ( 'detail' in orgEvent ) { deltaY = orgEvent . detail * - 1 ; }
if ( 'wheelDelta' in orgEvent ) { deltaY = orgEvent . wheelDelta ; }
if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent . wheelDeltaY ; }
if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent . wheelDeltaX * - 1 ; }
// Firefox < 17 horizontal scrolling related to DOMMouseScroll event
if ( 'axis' in orgEvent && orgEvent . axis === orgEvent . HORIZONTAL _AXIS ) {
deltaX = deltaY * - 1 ;
deltaY = 0 ;
}
// Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
delta = deltaY === 0 ? deltaX : deltaY ;
// New school wheel delta (wheel event)
if ( 'deltaY' in orgEvent ) {
deltaY = orgEvent . deltaY * - 1 ;
delta = deltaY ;
}
if ( 'deltaX' in orgEvent ) {
deltaX = orgEvent . deltaX ;
if ( deltaY === 0 ) { delta = deltaX * - 1 ; }
}
// No change actually happened, no reason to go any further
if ( deltaY === 0 && deltaX === 0 ) { return ; }
// Need to convert lines and pages to pixels if we aren't already in pixels
// There are three delta modes:
// * deltaMode 0 is by pixels, nothing to do
// * deltaMode 1 is by lines
// * deltaMode 2 is by pages
if ( orgEvent . deltaMode === 1 ) {
var lineHeight = $ . data ( this , 'mousewheel-line-height' ) ;
delta *= lineHeight ;
deltaY *= lineHeight ;
deltaX *= lineHeight ;
} else if ( orgEvent . deltaMode === 2 ) {
var pageHeight = $ . data ( this , 'mousewheel-page-height' ) ;
delta *= pageHeight ;
deltaY *= pageHeight ;
deltaX *= pageHeight ;
}
// Store lowest absolute delta to normalize the delta values
absDelta = Math . max ( Math . abs ( deltaY ) , Math . abs ( deltaX ) ) ;
if ( ! lowestDelta || absDelta < lowestDelta ) {
lowestDelta = absDelta ;
// Adjust older deltas if necessary
if ( shouldAdjustOldDeltas ( orgEvent , absDelta ) ) {
lowestDelta /= 40 ;
}
}
// Adjust older deltas if necessary
if ( shouldAdjustOldDeltas ( orgEvent , absDelta ) ) {
// Divide all the things by 40!
delta /= 40 ;
deltaX /= 40 ;
deltaY /= 40 ;
}
// Get a whole, normalized value for the deltas
delta = Math [ delta >= 1 ? 'floor' : 'ceil' ] ( delta / lowestDelta ) ;
deltaX = Math [ deltaX >= 1 ? 'floor' : 'ceil' ] ( deltaX / lowestDelta ) ;
deltaY = Math [ deltaY >= 1 ? 'floor' : 'ceil' ] ( deltaY / lowestDelta ) ;
// Add information to the event object
event . deltaX = deltaX ;
event . deltaY = deltaY ;
event . deltaFactor = lowestDelta ;
// Go ahead and set deltaMode to 0 since we converted to pixels
// Although this is a little odd since we overwrite the deltaX/Y
// properties with normalized deltas.
event . deltaMode = 0 ;
// Add event and delta to the front of the arguments
args . unshift ( event , delta , deltaX , deltaY ) ;
// Clearout lowestDelta after sometime to better
// handle multiple device types that give different
// a different lowestDelta
// Ex: trackpad = 3 and mouse wheel = 120
if ( nullLowestDeltaTimeout ) { clearTimeout ( nullLowestDeltaTimeout ) ; }
nullLowestDeltaTimeout = setTimeout ( nullLowestDelta , 200 ) ;
return ( $ . event . dispatch || $ . event . handle ) . apply ( this , args ) ;
}
function nullLowestDelta ( ) {
lowestDelta = null ;
}
function shouldAdjustOldDeltas ( orgEvent , absDelta ) {
// If this is an older event and the delta is divisable by 120,
// then we are assuming that the browser is treating this as an
// older mouse wheel event and that we should divide the deltas
// by 40 to try and get a more usable deltaFactor.
// Side note, this actually impacts the reported scroll distance
// in older browsers and can cause scrolling to be slower than native.
// Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
return special . settings . adjustOldDeltas && orgEvent . type === 'mousewheel' && absDelta % 120 === 0 ;
}
} ) ) ; / * *
* @ namespace jvm Holds core methods and classes used by jVectorMap .
* /
var jvm = {
/ * *
* Inherits child 's prototype from the parent' s one .
* @ param { Function } child
* @ param { Function } parent
* /
inherits : function ( child , parent ) {
function temp ( ) { }
temp . prototype = parent . prototype ;
child . prototype = new temp ( ) ;
child . prototype . constructor = child ;
child . parentClass = parent ;
} ,
/ * *
* Mixes in methods from the source constructor to the target one .
* @ param { Function } target
* @ param { Function } source
* /
mixin : function ( target , source ) {
var prop ;
for ( prop in source . prototype ) {
if ( source . prototype . hasOwnProperty ( prop ) ) {
target . prototype [ prop ] = source . prototype [ prop ] ;
}
}
} ,
min : function ( values ) {
var min = Number . MAX _VALUE ,
i ;
if ( values instanceof Array ) {
for ( i = 0 ; i < values . length ; i ++ ) {
if ( values [ i ] < min ) {
min = values [ i ] ;
}
}
} else {
for ( i in values ) {
if ( values [ i ] < min ) {
min = values [ i ] ;
}
}
}
return min ;
} ,
max : function ( values ) {
var max = Number . MIN _VALUE ,
i ;
if ( values instanceof Array ) {
for ( i = 0 ; i < values . length ; i ++ ) {
if ( values [ i ] > max ) {
max = values [ i ] ;
}
}
} else {
for ( i in values ) {
if ( values [ i ] > max ) {
max = values [ i ] ;
}
}
}
return max ;
} ,
keys : function ( object ) {
var keys = [ ] ,
key ;
for ( key in object ) {
keys . push ( key ) ;
}
return keys ;
} ,
values : function ( object ) {
var values = [ ] ,
key ,
i ;
for ( i = 0 ; i < arguments . length ; i ++ ) {
object = arguments [ i ] ;
for ( key in object ) {
values . push ( object [ key ] ) ;
}
}
return values ;
} ,
whenImageLoaded : function ( url ) {
var deferred = new jvm . $ . Deferred ( ) ,
img = jvm . $ ( '<img/>' ) ;
img . error ( function ( ) {
deferred . reject ( ) ;
} ) . load ( function ( ) {
deferred . resolve ( img ) ;
} ) ;
img . attr ( 'src' , url ) ;
return deferred ;
} ,
isImageUrl : function ( s ) {
return /\.\w{3,4}$/ . test ( s ) ;
}
} ;
jvm . $ = jQuery ;
/ * *
* indexOf polyfill for IE < 9
* https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
* /
if ( ! Array . prototype . indexOf ) {
Array . prototype . indexOf = function ( searchElement , fromIndex ) {
var k ;
// 1. Let O be the result of calling ToObject passing
// the this value as the argument.
if ( this == null ) {
throw new TypeError ( '"this" is null or not defined' ) ;
}
var O = Object ( this ) ;
// 2. Let lenValue be the result of calling the Get
// internal method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O . length >>> 0 ;
// 4. If len is 0, return -1.
if ( len === 0 ) {
return - 1 ;
}
// 5. If argument fromIndex was passed let n be
// ToInteger(fromIndex); else let n be 0.
var n = + fromIndex || 0 ;
if ( Math . abs ( n ) === Infinity ) {
n = 0 ;
}
// 6. If n >= len, return -1.
if ( n >= len ) {
return - 1 ;
}
// 7. If n >= 0, then Let k be n.
// 8. Else, n<0, Let k be len - abs(n).
// If k is less than 0, then let k be 0.
k = Math . max ( n >= 0 ? n : len - Math . abs ( n ) , 0 ) ;
// 9. Repeat, while k < len
while ( k < len ) {
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the
// HasProperty internal method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
// i. Let elementK be the result of calling the Get
// internal method of O with the argument ToString(k).
// ii. Let same be the result of applying the
// Strict Equality Comparison Algorithm to
// searchElement and elementK.
// iii. If same is true, return k.
if ( k in O && O [ k ] === searchElement ) {
return k ;
}
k ++ ;
}
return - 1 ;
} ;
} / * *
* Basic wrapper for DOM element .
* @ constructor
* @ param { String } name Tag name of the element
* @ param { Object } config Set of parameters to initialize element with
* /
jvm . AbstractElement = function ( name , config ) {
/ * *
* Underlying DOM element
* @ type { DOMElement }
* @ private
* /
this . node = this . createElement ( name ) ;
/ * *
* Name of underlying element
* @ type { String }
* @ private
* /
this . name = name ;
/ * *
* Internal store of attributes
* @ type { Object }
* @ private
* /
this . properties = { } ;
if ( config ) {
this . set ( config ) ;
}
} ;
/ * *
* Set attribute of the underlying DOM element .
* @ param { String } name Name of attribute
* @ param { Number | String } config Set of parameters to initialize element with
* /
jvm . AbstractElement . prototype . set = function ( property , value ) {
var key ;
if ( typeof property === 'object' ) {
for ( key in property ) {
this . properties [ key ] = property [ key ] ;
this . applyAttr ( key , property [ key ] ) ;
}
} else {
this . properties [ property ] = value ;
this . applyAttr ( property , value ) ;
}
} ;
/ * *
* Returns value of attribute .
* @ param { String } name Name of attribute
* /
jvm . AbstractElement . prototype . get = function ( property ) {
return this . properties [ property ] ;
} ;
/ * *
* Applies attribute value to the underlying DOM element .
* @ param { String } name Name of attribute
* @ param { Number | String } config Value of attribute to apply
* @ private
* /
jvm . AbstractElement . prototype . applyAttr = function ( property , value ) {
this . node . setAttribute ( property , value ) ;
} ;
jvm . AbstractElement . prototype . remove = function ( ) {
jvm . $ ( this . node ) . remove ( ) ;
} ; / * *
* Implements abstract vector canvas .
* @ constructor
* @ param { HTMLElement } container Container to put element to .
* @ param { Number } width Width of canvas .
* @ param { Number } height Height of canvas .
* /
jvm . AbstractCanvasElement = function ( container , width , height ) {
this . container = container ;
this . setSize ( width , height ) ;
this . rootElement = new jvm [ this . classPrefix + 'GroupElement' ] ( ) ;
this . node . appendChild ( this . rootElement . node ) ;
this . container . appendChild ( this . node ) ;
}
/ * *
* Add element to the certain group inside of the canvas .
* @ param { HTMLElement } element Element to add to canvas .
* @ param { HTMLElement } group Group to add element into or into root group if not provided .
* /
jvm . AbstractCanvasElement . prototype . add = function ( element , group ) {
group = group || this . rootElement ;
group . add ( element ) ;
element . canvas = this ;
}
/ * *
* Create path and add it to the canvas .
* @ param { Object } config Parameters of path to create .
* @ param { Object } style Styles of the path to create .
* @ param { HTMLElement } group Group to add path into .
* /
jvm . AbstractCanvasElement . prototype . addPath = function ( config , style , group ) {
var el = new jvm [ this . classPrefix + 'PathElement' ] ( config , style ) ;
this . add ( el , group ) ;
return el ;
} ;
/ * *
* Create circle and add it to the canvas .
* @ param { Object } config Parameters of path to create .
* @ param { Object } style Styles of the path to create .
* @ param { HTMLElement } group Group to add circle into .
* /
jvm . AbstractCanvasElement . prototype . addCircle = function ( config , style , group ) {
var el = new jvm [ this . classPrefix + 'CircleElement' ] ( config , style ) ;
this . add ( el , group ) ;
return el ;
} ;
/ * *
* Create circle and add it to the canvas .
* @ param { Object } config Parameters of path to create .
* @ param { Object } style Styles of the path to create .
* @ param { HTMLElement } group Group to add circle into .
* /
jvm . AbstractCanvasElement . prototype . addImage = function ( config , style , group ) {
var el = new jvm [ this . classPrefix + 'ImageElement' ] ( config , style ) ;
this . add ( el , group ) ;
return el ;
} ;
/ * *
* Create text and add it to the canvas .
* @ param { Object } config Parameters of path to create .
* @ param { Object } style Styles of the path to create .
* @ param { HTMLElement } group Group to add circle into .
* /
jvm . AbstractCanvasElement . prototype . addText = function ( config , style , group ) {
var el = new jvm [ this . classPrefix + 'TextElement' ] ( config , style ) ;
this . add ( el , group ) ;
return el ;
} ;
/ * *
* Add group to the another group inside of the canvas .
* @ param { HTMLElement } group Group to add circle into or root group if not provided .
* /
jvm . AbstractCanvasElement . prototype . addGroup = function ( parentGroup ) {
var el = new jvm [ this . classPrefix + 'GroupElement' ] ( ) ;
if ( parentGroup ) {
parentGroup . node . appendChild ( el . node ) ;
} else {
this . node . appendChild ( el . node ) ;
}
el . canvas = this ;
return el ;
} ; / * *
* Abstract shape element . Shape element represents some visual vector or raster object .
* @ constructor
* @ param { String } name Tag name of the element .
* @ param { Object } config Set of parameters to initialize element with .
* @ param { Object } style Object with styles to set on element initialization .
* /
jvm . AbstractShapeElement = function ( name , config , style ) {
this . style = style || { } ;
this . style . current = this . style . current || { } ;
this . isHovered = false ;
this . isSelected = false ;
this . updateStyle ( ) ;
} ;
/ * *
* Set element ' s style .
* @ param { Object | String } property Could be string to set only one property or object to set several style properties at once .
* @ param { String } value Value to set in case only one property should be set .
* /
jvm . AbstractShapeElement . prototype . setStyle = function ( property , value ) {
var styles = { } ;
if ( typeof property === 'object' ) {
styles = property ;
} else {
styles [ property ] = value ;
}
jvm . $ . extend ( this . style . current , styles ) ;
this . updateStyle ( ) ;
} ;
jvm . AbstractShapeElement . prototype . updateStyle = function ( ) {
var attrs = { } ;
jvm . AbstractShapeElement . mergeStyles ( attrs , this . style . initial ) ;
jvm . AbstractShapeElement . mergeStyles ( attrs , this . style . current ) ;
if ( this . isHovered ) {
jvm . AbstractShapeElement . mergeStyles ( attrs , this . style . hover ) ;
}
if ( this . isSelected ) {
jvm . AbstractShapeElement . mergeStyles ( attrs , this . style . selected ) ;
if ( this . isHovered ) {
jvm . AbstractShapeElement . mergeStyles ( attrs , this . style . selectedHover ) ;
}
}
this . set ( attrs ) ;
} ;
jvm . AbstractShapeElement . mergeStyles = function ( styles , newStyles ) {
var key ;
newStyles = newStyles || { } ;
for ( key in newStyles ) {
if ( newStyles [ key ] === null ) {
delete styles [ key ] ;
} else {
styles [ key ] = newStyles [ key ] ;
}
}
} / * *
* Wrapper for SVG element .
* @ constructor
* @ extends jvm . AbstractElement
* @ param { String } name Tag name of the element
* @ param { Object } config Set of parameters to initialize element with
* /
jvm . SVGElement = function ( name , config ) {
jvm . SVGElement . parentClass . apply ( this , arguments ) ;
}
jvm . inherits ( jvm . SVGElement , jvm . AbstractElement ) ;
jvm . SVGElement . svgns = "http://www.w3.org/2000/svg" ;
/ * *
* Creates DOM element .
* @ param { String } tagName Name of element
* @ private
* @ returns DOMElement
* /
jvm . SVGElement . prototype . createElement = function ( tagName ) {
return document . createElementNS ( jvm . SVGElement . svgns , tagName ) ;
} ;
/ * *
* Adds CSS class for underlying DOM element .
* @ param { String } className Name of CSS class name
* /
jvm . SVGElement . prototype . addClass = function ( className ) {
this . node . setAttribute ( 'class' , className ) ;
} ;
/ * *
* Returns constructor for element by name prefixed with 'VML' .
* @ param { String } ctr Name of basic constructor to return
* proper implementation for .
* @ returns Function
* @ private
* /
jvm . SVGElement . prototype . getElementCtr = function ( ctr ) {
return jvm [ 'SVG' + ctr ] ;
} ;
jvm . SVGElement . prototype . getBBox = function ( ) {
return this . node . getBBox ( ) ;
} ; jvm . SVGGroupElement = function ( ) {
jvm . SVGGroupElement . parentClass . call ( this , 'g' ) ;
}
jvm . inherits ( jvm . SVGGroupElement , jvm . SVGElement ) ;
jvm . SVGGroupElement . prototype . add = function ( element ) {
this . node . appendChild ( element . node ) ;
} ; jvm . SVGCanvasElement = function ( container , width , height ) {
this . classPrefix = 'SVG' ;
jvm . SVGCanvasElement . parentClass . call ( this , 'svg' ) ;
this . defsElement = new jvm . SVGElement ( 'defs' ) ;
this . node . appendChild ( this . defsElement . node ) ;
jvm . AbstractCanvasElement . apply ( this , arguments ) ;
}
jvm . inherits ( jvm . SVGCanvasElement , jvm . SVGElement ) ;
jvm . mixin ( jvm . SVGCanvasElement , jvm . AbstractCanvasElement ) ;
jvm . SVGCanvasElement . prototype . setSize = function ( width , height ) {
this . width = width ;
this . height = height ;
this . node . setAttribute ( 'width' , width ) ;
this . node . setAttribute ( 'height' , height ) ;
} ;
jvm . SVGCanvasElement . prototype . applyTransformParams = function ( scale , transX , transY ) {
this . scale = scale ;
this . transX = transX ;
this . transY = transY ;
this . rootElement . node . setAttribute ( 'transform' , 'scale(' + scale + ') translate(' + transX + ', ' + transY + ')' ) ;
} ; jvm . SVGShapeElement = function ( name , config , style ) {
jvm . SVGShapeElement . parentClass . call ( this , name , config ) ;
jvm . AbstractShapeElement . apply ( this , arguments ) ;
} ;
jvm . inherits ( jvm . SVGShapeElement , jvm . SVGElement ) ;
jvm . mixin ( jvm . SVGShapeElement , jvm . AbstractShapeElement ) ;
jvm . SVGShapeElement . prototype . applyAttr = function ( attr , value ) {
var patternEl ,
imageEl ,
that = this ;
if ( attr === 'fill' && jvm . isImageUrl ( value ) ) {
if ( ! jvm . SVGShapeElement . images [ value ] ) {
jvm . whenImageLoaded ( value ) . then ( function ( img ) {
imageEl = new jvm . SVGElement ( 'image' ) ;
imageEl . node . setAttributeNS ( 'http://www.w3.org/1999/xlink' , 'href' , value ) ;
imageEl . applyAttr ( 'x' , '0' ) ;
imageEl . applyAttr ( 'y' , '0' ) ;
imageEl . applyAttr ( 'width' , img [ 0 ] . width ) ;
imageEl . applyAttr ( 'height' , img [ 0 ] . height ) ;
patternEl = new jvm . SVGElement ( 'pattern' ) ;
patternEl . applyAttr ( 'id' , 'image' + jvm . SVGShapeElement . imageCounter ) ;
patternEl . applyAttr ( 'x' , 0 ) ;
patternEl . applyAttr ( 'y' , 0 ) ;
patternEl . applyAttr ( 'width' , img [ 0 ] . width / 2 ) ;
patternEl . applyAttr ( 'height' , img [ 0 ] . height / 2 ) ;
patternEl . applyAttr ( 'viewBox' , '0 0 ' + img [ 0 ] . width + ' ' + img [ 0 ] . height ) ;
patternEl . applyAttr ( 'patternUnits' , 'userSpaceOnUse' ) ;
patternEl . node . appendChild ( imageEl . node ) ;
that . canvas . defsElement . node . appendChild ( patternEl . node ) ;
jvm . SVGShapeElement . images [ value ] = jvm . SVGShapeElement . imageCounter ++ ;
that . applyAttr ( 'fill' , 'url(#image' + jvm . SVGShapeElement . images [ value ] + ')' ) ;
} ) ;
} else {
this . applyAttr ( 'fill' , 'url(#image' + jvm . SVGShapeElement . images [ value ] + ')' ) ;
}
} else {
jvm . SVGShapeElement . parentClass . prototype . applyAttr . apply ( this , arguments ) ;
}
} ;
jvm . SVGShapeElement . imageCounter = 1 ;
jvm . SVGShapeElement . images = { } ; jvm . SVGPathElement = function ( config , style ) {
jvm . SVGPathElement . parentClass . call ( this , 'path' , config , style ) ;
this . node . setAttribute ( 'fill-rule' , 'evenodd' ) ;
}
jvm . inherits ( jvm . SVGPathElement , jvm . SVGShapeElement ) ; jvm . SVGCircleElement = function ( config , style ) {
jvm . SVGCircleElement . parentClass . call ( this , 'circle' , config , style ) ;
} ;
jvm . inherits ( jvm . SVGCircleElement , jvm . SVGShapeElement ) ; jvm . SVGImageElement = function ( config , style ) {
jvm . SVGImageElement . parentClass . call ( this , 'image' , config , style ) ;
} ;
jvm . inherits ( jvm . SVGImageElement , jvm . SVGShapeElement ) ;
jvm . SVGImageElement . prototype . applyAttr = function ( attr , value ) {
var that = this ;
if ( attr == 'image' ) {
jvm . whenImageLoaded ( value ) . then ( function ( img ) {
that . node . setAttributeNS ( 'http://www.w3.org/1999/xlink' , 'href' , value ) ;
that . width = img [ 0 ] . width ;
that . height = img [ 0 ] . height ;
that . applyAttr ( 'width' , that . width ) ;
that . applyAttr ( 'height' , that . height ) ;
that . applyAttr ( 'x' , that . cx - that . width / 2 ) ;
that . applyAttr ( 'y' , that . cy - that . height / 2 ) ;
jvm . $ ( that . node ) . trigger ( 'imageloaded' , [ img ] ) ;
} ) ;
} else if ( attr == 'cx' ) {
this . cx = value ;
if ( this . width ) {
this . applyAttr ( 'x' , value - this . width / 2 ) ;
}
} else if ( attr == 'cy' ) {
this . cy = value ;
if ( this . height ) {
this . applyAttr ( 'y' , value - this . height / 2 ) ;
}
} else {
jvm . SVGImageElement . parentClass . prototype . applyAttr . apply ( this , arguments ) ;
}
} ; jvm . SVGTextElement = function ( config , style ) {
jvm . SVGTextElement . parentClass . call ( this , 'text' , config , style ) ;
}
jvm . inherits ( jvm . SVGTextElement , jvm . SVGShapeElement ) ;
jvm . SVGTextElement . prototype . applyAttr = function ( attr , value ) {
if ( attr === 'text' ) {
this . node . textContent = value ;
} else {
jvm . SVGTextElement . parentClass . prototype . applyAttr . apply ( this , arguments ) ;
}
} ; / * *
* Wrapper for VML element .
* @ constructor
* @ extends jvm . AbstractElement
* @ param { String } name Tag name of the element
* @ param { Object } config Set of parameters to initialize element with
* /
jvm . VMLElement = function ( name , config ) {
if ( ! jvm . VMLElement . VMLInitialized ) {
jvm . VMLElement . initializeVML ( ) ;
}
jvm . VMLElement . parentClass . apply ( this , arguments ) ;
} ;
jvm . inherits ( jvm . VMLElement , jvm . AbstractElement ) ;
/ * *
* Shows if VML was already initialized for the current document or not .
* @ static
* @ private
* @ type { Boolean }
* /
jvm . VMLElement . VMLInitialized = false ;
/ * *
* Initializes VML handling before creating the first element
* ( adds CSS class and creates namespace ) . Adds one of two forms
* of createElement method depending of support by browser .
* @ static
* @ private
* /
// The following method of VML handling is borrowed from the
// Raphael library by Dmitry Baranovsky.
jvm . VMLElement . initializeVML = function ( ) {
try {
if ( ! document . namespaces . rvml ) {
document . namespaces . add ( "rvml" , "urn:schemas-microsoft-com:vml" ) ;
}
/ * *
* Creates DOM element .
* @ param { String } tagName Name of element
* @ private
* @ returns DOMElement
* /
jvm . VMLElement . prototype . createElement = function ( tagName ) {
return document . createElement ( '<rvml:' + tagName + ' class="rvml">' ) ;
} ;
} catch ( e ) {
/ * *
* @ private
* /
jvm . VMLElement . prototype . createElement = function ( tagName ) {
return document . createElement ( '<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">' ) ;
} ;
}
document . createStyleSheet ( ) . addRule ( ".rvml" , "behavior:url(#default#VML)" ) ;
jvm . VMLElement . VMLInitialized = true ;
} ;
/ * *
* Returns constructor for element by name prefixed with 'VML' .
* @ param { String } ctr Name of basic constructor to return
* proper implementation for .
* @ returns Function
* @ private
* /
jvm . VMLElement . prototype . getElementCtr = function ( ctr ) {
return jvm [ 'VML' + ctr ] ;
} ;
/ * *
* Adds CSS class for underlying DOM element .
* @ param { String } className Name of CSS class name
* /
jvm . VMLElement . prototype . addClass = function ( className ) {
jvm . $ ( this . node ) . addClass ( className ) ;
} ;
/ * *
* Applies attribute value to the underlying DOM element .
* @ param { String } name Name of attribute
* @ param { Number | String } config Value of attribute to apply
* @ private
* /
jvm . VMLElement . prototype . applyAttr = function ( attr , value ) {
this . node [ attr ] = value ;
} ;
/ * *
* Returns boundary box for the element .
* @ returns { Object } Boundary box with numeric fields : x , y , width , height
* @ override
* /
jvm . VMLElement . prototype . getBBox = function ( ) {
var node = jvm . $ ( this . node ) ;
return {
x : node . position ( ) . left / this . canvas . scale ,
y : node . position ( ) . top / this . canvas . scale ,
width : node . width ( ) / this . canvas . scale ,
height : node . height ( ) / this . canvas . scale
} ;
} ; jvm . VMLGroupElement = function ( ) {
jvm . VMLGroupElement . parentClass . call ( this , 'group' ) ;
this . node . style . left = '0px' ;
this . node . style . top = '0px' ;
this . node . coordorigin = "0 0" ;
} ;
jvm . inherits ( jvm . VMLGroupElement , jvm . VMLElement ) ;
jvm . VMLGroupElement . prototype . add = function ( element ) {
this . node . appendChild ( element . node ) ;
} ; jvm . VMLCanvasElement = function ( container , width , height ) {
this . classPrefix = 'VML' ;
jvm . VMLCanvasElement . parentClass . call ( this , 'group' ) ;
jvm . AbstractCanvasElement . apply ( this , arguments ) ;
this . node . style . position = 'absolute' ;
} ;
jvm . inherits ( jvm . VMLCanvasElement , jvm . VMLElement ) ;
jvm . mixin ( jvm . VMLCanvasElement , jvm . AbstractCanvasElement ) ;
jvm . VMLCanvasElement . prototype . setSize = function ( width , height ) {
var paths ,
groups ,
i ,
l ;
this . width = width ;
this . height = height ;
this . node . style . width = width + "px" ;
this . node . style . height = height + "px" ;
this . node . coordsize = width + ' ' + height ;
this . node . coordorigin = "0 0" ;
if ( this . rootElement ) {
paths = this . rootElement . node . getElementsByTagName ( 'shape' ) ;
for ( i = 0 , l = paths . length ; i < l ; i ++ ) {
paths [ i ] . coordsize = width + ' ' + height ;
paths [ i ] . style . width = width + 'px' ;
paths [ i ] . style . height = height + 'px' ;
}
groups = this . node . getElementsByTagName ( 'group' ) ;
for ( i = 0 , l = groups . length ; i < l ; i ++ ) {
groups [ i ] . coordsize = width + ' ' + height ;
groups [ i ] . style . width = width + 'px' ;
groups [ i ] . style . height = height + 'px' ;
}
}
} ;
jvm . VMLCanvasElement . prototype . applyTransformParams = function ( scale , transX , transY ) {
this . scale = scale ;
this . transX = transX ;
this . transY = transY ;
this . rootElement . node . coordorigin = ( this . width - transX - this . width / 100 ) + ',' + ( this . height - transY - this . height / 100 ) ;
this . rootElement . node . coordsize = this . width / scale + ',' + this . height / scale ;
} ; jvm . VMLShapeElement = function ( name , config ) {
jvm . VMLShapeElement . parentClass . call ( this , name , config ) ;
this . fillElement = new jvm . VMLElement ( 'fill' ) ;
this . strokeElement = new jvm . VMLElement ( 'stroke' ) ;
this . node . appendChild ( this . fillElement . node ) ;
this . node . appendChild ( this . strokeElement . node ) ;
this . node . stroked = false ;
jvm . AbstractShapeElement . apply ( this , arguments ) ;
} ;
jvm . inherits ( jvm . VMLShapeElement , jvm . VMLElement ) ;
jvm . mixin ( jvm . VMLShapeElement , jvm . AbstractShapeElement ) ;
jvm . VMLShapeElement . prototype . applyAttr = function ( attr , value ) {
switch ( attr ) {
case 'fill' :
this . node . fillcolor = value ;
break ;
case 'fill-opacity' :
this . fillElement . node . opacity = Math . round ( value * 100 ) + '%' ;
break ;
case 'stroke' :
if ( value === 'none' ) {
this . node . stroked = false ;
} else {
this . node . stroked = true ;
}
this . node . strokecolor = value ;
break ;
case 'stroke-opacity' :
this . strokeElement . node . opacity = Math . round ( value * 100 ) + '%' ;
break ;
case 'stroke-width' :
if ( parseInt ( value , 10 ) === 0 ) {
this . node . stroked = false ;
} else {
this . node . stroked = true ;
}
this . node . strokeweight = value ;
break ;
case 'd' :
this . node . path = jvm . VMLPathElement . pathSvgToVml ( value ) ;
break ;
default :
jvm . VMLShapeElement . parentClass . prototype . applyAttr . apply ( this , arguments ) ;
}
} ; jvm . VMLPathElement = function ( config , style ) {
var scale = new jvm . VMLElement ( 'skew' ) ;
jvm . VMLPathElement . parentClass . call ( this , 'shape' , config , style ) ;
this . node . coordorigin = "0 0" ;
scale . node . on = true ;
scale . node . matrix = '0.01,0,0,0.01,0,0' ;
scale . node . offset = '0,0' ;
this . node . appendChild ( scale . node ) ;
} ;
jvm . inherits ( jvm . VMLPathElement , jvm . VMLShapeElement ) ;
jvm . VMLPathElement . prototype . applyAttr = function ( attr , value ) {
if ( attr === 'd' ) {
this . node . path = jvm . VMLPathElement . pathSvgToVml ( value ) ;
} else {
jvm . VMLShapeElement . prototype . applyAttr . call ( this , attr , value ) ;
}
} ;
jvm . VMLPathElement . pathSvgToVml = function ( path ) {
var cx = 0 , cy = 0 , ctrlx , ctrly ;
path = path . replace ( /(-?\d+)e(-?\d+)/g , '0' ) ;
return path . replace ( /([MmLlHhVvCcSs])\s*((?:-?\d*(?:\.\d+)?\s*,?\s*)+)/g , function ( segment , letter , coords , index ) {
coords = coords . replace ( /(\d)-/g , '$1,-' )
. replace ( /^\s+/g , '' )
. replace ( /\s+$/g , '' )
. replace ( /\s+/g , ',' ) . split ( ',' ) ;
if ( ! coords [ 0 ] ) coords . shift ( ) ;
for ( var i = 0 , l = coords . length ; i < l ; i ++ ) {
coords [ i ] = Math . round ( 100 * coords [ i ] ) ;
}
switch ( letter ) {
case 'm' :
cx += coords [ 0 ] ;
cy += coords [ 1 ] ;
return 't' + coords . join ( ',' ) ;
case 'M' :
cx = coords [ 0 ] ;
cy = coords [ 1 ] ;
return 'm' + coords . join ( ',' ) ;
case 'l' :
cx += coords [ 0 ] ;
cy += coords [ 1 ] ;
return 'r' + coords . join ( ',' ) ;
case 'L' :
cx = coords [ 0 ] ;
cy = coords [ 1 ] ;
return 'l' + coords . join ( ',' ) ;
case 'h' :
cx += coords [ 0 ] ;
return 'r' + coords [ 0 ] + ',0' ;
case 'H' :
cx = coords [ 0 ] ;
return 'l' + cx + ',' + cy ;
case 'v' :
cy += coords [ 0 ] ;
return 'r0,' + coords [ 0 ] ;
case 'V' :
cy = coords [ 0 ] ;
return 'l' + cx + ',' + cy ;
case 'c' :
ctrlx = cx + coords [ coords . length - 4 ] ;
ctrly = cy + coords [ coords . length - 3 ] ;
cx += coords [ coords . length - 2 ] ;
cy += coords [ coords . length - 1 ] ;
return 'v' + coords . join ( ',' ) ;
case 'C' :
ctrlx = coords [ coords . length - 4 ] ;
ctrly = coords [ coords . length - 3 ] ;
cx = coords [ coords . length - 2 ] ;
cy = coords [ coords . length - 1 ] ;
return 'c' + coords . join ( ',' ) ;
case 's' :
coords . unshift ( cy - ctrly ) ;
coords . unshift ( cx - ctrlx ) ;
ctrlx = cx + coords [ coords . length - 4 ] ;
ctrly = cy + coords [ coords . length - 3 ] ;
cx += coords [ coords . length - 2 ] ;
cy += coords [ coords . length - 1 ] ;
return 'v' + coords . join ( ',' ) ;
case 'S' :
coords . unshift ( cy + cy - ctrly ) ;
coords . unshift ( cx + cx - ctrlx ) ;
ctrlx = coords [ coords . length - 4 ] ;
ctrly = coords [ coords . length - 3 ] ;
cx = coords [ coords . length - 2 ] ;
cy = coords [ coords . length - 1 ] ;
return 'c' + coords . join ( ',' ) ;
}
return '' ;
} ) . replace ( /z/g , 'e' ) ;
} ; jvm . VMLCircleElement = function ( config , style ) {
jvm . VMLCircleElement . parentClass . call ( this , 'oval' , config , style ) ;
} ;
jvm . inherits ( jvm . VMLCircleElement , jvm . VMLShapeElement ) ;
jvm . VMLCircleElement . prototype . applyAttr = function ( attr , value ) {
switch ( attr ) {
case 'r' :
this . node . style . width = value * 2 + 'px' ;
this . node . style . height = value * 2 + 'px' ;
this . applyAttr ( 'cx' , this . get ( 'cx' ) || 0 ) ;
this . applyAttr ( 'cy' , this . get ( 'cy' ) || 0 ) ;
break ;
case 'cx' :
if ( ! value ) return ;
this . node . style . left = value - ( this . get ( 'r' ) || 0 ) + 'px' ;
break ;
case 'cy' :
if ( ! value ) return ;
this . node . style . top = value - ( this . get ( 'r' ) || 0 ) + 'px' ;
break ;
default :
jvm . VMLCircleElement . parentClass . prototype . applyAttr . call ( this , attr , value ) ;
}
} ; / * *
* Class for vector images manipulations .
* @ constructor
* @ param { DOMElement } container to place canvas to
* @ param { Number } width
* @ param { Number } height
* /
jvm . VectorCanvas = function ( container , width , height ) {
this . mode = window . SVGAngle ? 'svg' : 'vml' ;
if ( this . mode == 'svg' ) {
this . impl = new jvm . SVGCanvasElement ( container , width , height ) ;
} else {
this . impl = new jvm . VMLCanvasElement ( container , width , height ) ;
}
this . impl . mode = this . mode ;
return this . impl ;
} ; jvm . SimpleScale = function ( scale ) {
this . scale = scale ;
} ;
jvm . SimpleScale . prototype . getValue = function ( value ) {
return value ;
} ; jvm . OrdinalScale = function ( scale ) {
this . scale = scale ;
} ;
jvm . OrdinalScale . prototype . getValue = function ( value ) {
return this . scale [ value ] ;
} ;
jvm . OrdinalScale . prototype . getTicks = function ( ) {
var ticks = [ ] ,
key ;
for ( key in this . scale ) {
ticks . push ( {
label : key ,
value : this . scale [ key ]
} ) ;
}
return ticks ;
} ; jvm . NumericScale = function ( scale , normalizeFunction , minValue , maxValue ) {
this . scale = [ ] ;
normalizeFunction = normalizeFunction || 'linear' ;
if ( scale ) this . setScale ( scale ) ;
if ( normalizeFunction ) this . setNormalizeFunction ( normalizeFunction ) ;
if ( typeof minValue !== 'undefined' ) this . setMin ( minValue ) ;
if ( typeof maxValue !== 'undefined' ) this . setMin ( maxValue ) ;
} ;
jvm . NumericScale . prototype = {
setMin : function ( min ) {
this . clearMinValue = min ;
if ( typeof this . normalize === 'function' ) {
this . minValue = this . normalize ( min ) ;
} else {
this . minValue = min ;
}
} ,
setMax : function ( max ) {
this . clearMaxValue = max ;
if ( typeof this . normalize === 'function' ) {
this . maxValue = this . normalize ( max ) ;
} else {
this . maxValue = max ;
}
} ,
setScale : function ( scale ) {
var i ;
this . scale = [ ] ;
for ( i = 0 ; i < scale . length ; i ++ ) {
this . scale [ i ] = [ scale [ i ] ] ;
}
} ,
setNormalizeFunction : function ( f ) {
if ( f === 'polynomial' ) {
this . normalize = function ( value ) {
return Math . pow ( value , 0.2 ) ;
}
} else if ( f === 'linear' ) {
delete this . normalize ;
} else {
this . normalize = f ;
}
this . setMin ( this . clearMinValue ) ;
this . setMax ( this . clearMaxValue ) ;
} ,
getValue : function ( value ) {
var lengthes = [ ] ,
fullLength = 0 ,
l ,
i = 0 ,
c ;
if ( typeof this . normalize === 'function' ) {
value = this . normalize ( value ) ;
}
for ( i = 0 ; i < this . scale . length - 1 ; i ++ ) {
l = this . vectorLength ( this . vectorSubtract ( this . scale [ i + 1 ] , this . scale [ i ] ) ) ;
lengthes . push ( l ) ;
fullLength += l ;
}
c = ( this . maxValue - this . minValue ) / fullLength ;
for ( i = 0 ; i < lengthes . length ; i ++ ) {
lengthes [ i ] *= c ;
}
i = 0 ;
value -= this . minValue ;
while ( value - lengthes [ i ] >= 0 ) {
value -= lengthes [ i ] ;
i ++ ;
}
if ( i == this . scale . length - 1 ) {
value = this . vectorToNum ( this . scale [ i ] )
} else {
value = (
this . vectorToNum (
this . vectorAdd ( this . scale [ i ] ,
this . vectorMult (
this . vectorSubtract ( this . scale [ i + 1 ] , this . scale [ i ] ) ,
( value ) / ( lengthes [ i ] )
)
)
)
) ;
}
return value ;
} ,
vectorToNum : function ( vector ) {
var num = 0 ,
i ;
for ( i = 0 ; i < vector . length ; i ++ ) {
num += Math . round ( vector [ i ] ) * Math . pow ( 256 , vector . length - i - 1 ) ;
}
return num ;
} ,
vectorSubtract : function ( vector1 , vector2 ) {
var vector = [ ] ,
i ;
for ( i = 0 ; i < vector1 . length ; i ++ ) {
vector [ i ] = vector1 [ i ] - vector2 [ i ] ;
}
return vector ;
} ,
vectorAdd : function ( vector1 , vector2 ) {
var vector = [ ] ,
i ;
for ( i = 0 ; i < vector1 . length ; i ++ ) {
vector [ i ] = vector1 [ i ] + vector2 [ i ] ;
}
return vector ;
} ,
vectorMult : function ( vector , num ) {
var result = [ ] ,
i ;
for ( i = 0 ; i < vector . length ; i ++ ) {
result [ i ] = vector [ i ] * num ;
}
return result ;
} ,
vectorLength : function ( vector ) {
var result = 0 ,
i ;
for ( i = 0 ; i < vector . length ; i ++ ) {
result += vector [ i ] * vector [ i ] ;
}
return Math . sqrt ( result ) ;
} ,
/* Derived from d3 implementation https://github.com/mbostock/d3/blob/master/src/scale/linear.js#L94 */
getTicks : function ( ) {
var m = 5 ,
extent = [ this . clearMinValue , this . clearMaxValue ] ,
span = extent [ 1 ] - extent [ 0 ] ,
step = Math . pow ( 10 , Math . floor ( Math . log ( span / m ) / Math . LN10 ) ) ,
err = m / span * step ,
ticks = [ ] ,
tick ,
v ;
if ( err <= . 15 ) step *= 10 ;
else if ( err <= . 35 ) step *= 5 ;
else if ( err <= . 75 ) step *= 2 ;
extent [ 0 ] = Math . floor ( extent [ 0 ] / step ) * step ;
extent [ 1 ] = Math . ceil ( extent [ 1 ] / step ) * step ;
tick = extent [ 0 ] ;
while ( tick <= extent [ 1 ] ) {
if ( tick == extent [ 0 ] ) {
v = this . clearMinValue ;
} else if ( tick == extent [ 1 ] ) {
v = this . clearMaxValue ;
} else {
v = tick ;
}
ticks . push ( {
label : tick ,
value : this . getValue ( v )
} ) ;
tick += step ;
}
return ticks ;
}
} ;
jvm . ColorScale = function ( colors , normalizeFunction , minValue , maxValue ) {
jvm . ColorScale . parentClass . apply ( this , arguments ) ;
}
jvm . inherits ( jvm . ColorScale , jvm . NumericScale ) ;
jvm . ColorScale . prototype . setScale = function ( scale ) {
var i ;
for ( i = 0 ; i < scale . length ; i ++ ) {
this . scale [ i ] = jvm . ColorScale . rgbToArray ( scale [ i ] ) ;
}
} ;
jvm . ColorScale . prototype . getValue = function ( value ) {
return jvm . ColorScale . numToRgb ( jvm . ColorScale . parentClass . prototype . getValue . call ( this , value ) ) ;
} ;
jvm . ColorScale . arrayToRgb = function ( ar ) {
var rgb = '#' ,
d ,
i ;
for ( i = 0 ; i < ar . length ; i ++ ) {
d = ar [ i ] . toString ( 16 ) ;
rgb += d . length == 1 ? '0' + d : d ;
}
return rgb ;
} ;
jvm . ColorScale . numToRgb = function ( num ) {
num = num . toString ( 16 ) ;
while ( num . length < 6 ) {
num = '0' + num ;
}
return '#' + num ;
} ;
jvm . ColorScale . rgbToArray = function ( rgb ) {
rgb = rgb . substr ( 1 ) ;
return [ parseInt ( rgb . substr ( 0 , 2 ) , 16 ) , parseInt ( rgb . substr ( 2 , 2 ) , 16 ) , parseInt ( rgb . substr ( 4 , 2 ) , 16 ) ] ;
} ; / * *
* Represents map legend .
* @ constructor
* @ param { Object } params Configuration parameters .
* @ param { String } params . cssClass Additional CSS class to apply to legend element .
* @ param { Boolean } params . vertical If < code > true < / c o d e > l e g e n d w i l l b e r e n d e r e d a s v e r t i c a l .
* @ param { String } params . title Legend title .
* @ param { Function } params . labelRender Method to convert series values to legend labels .
* /
jvm . Legend = function ( params ) {
this . params = params || { } ;
this . map = this . params . map ;
this . series = this . params . series ;
this . body = jvm . $ ( '<div/>' ) ;
this . body . addClass ( 'jvectormap-legend' ) ;
if ( this . params . cssClass ) {
this . body . addClass ( this . params . cssClass ) ;
}
if ( params . vertical ) {
this . map . legendCntVertical . append ( this . body ) ;
} else {
this . map . legendCntHorizontal . append ( this . body ) ;
}
this . render ( ) ;
}
jvm . Legend . prototype . render = function ( ) {
var ticks = this . series . scale . getTicks ( ) ,
i ,
inner = jvm . $ ( '<div/>' ) . addClass ( 'jvectormap-legend-inner' ) ,
tick ,
sample ,
label ;
this . body . html ( '' ) ;
if ( this . params . title ) {
this . body . append (
jvm . $ ( '<div/>' ) . addClass ( 'jvectormap-legend-title' ) . html ( this . params . title )
) ;
}
this . body . append ( inner ) ;
for ( i = 0 ; i < ticks . length ; i ++ ) {
tick = jvm . $ ( '<div/>' ) . addClass ( 'jvectormap-legend-tick' ) ;
sample = jvm . $ ( '<div/>' ) . addClass ( 'jvectormap-legend-tick-sample' ) ;
switch ( this . series . params . attribute ) {
case 'fill' :
if ( jvm . isImageUrl ( ticks [ i ] . value ) ) {
sample . css ( 'background' , 'url(' + ticks [ i ] . value + ')' ) ;
} else {
sample . css ( 'background' , ticks [ i ] . value ) ;
}
break ;
case 'stroke' :
sample . css ( 'background' , ticks [ i ] . value ) ;
break ;
case 'image' :
sample . css ( 'background' , 'url(' + ticks [ i ] . value + ') no-repeat center center' ) ;
break ;
case 'r' :
jvm . $ ( '<div/>' ) . css ( {
'border-radius' : ticks [ i ] . value ,
border : this . map . params . markerStyle . initial [ 'stroke-width' ] + 'px ' +
this . map . params . markerStyle . initial [ 'stroke' ] + ' solid' ,
width : ticks [ i ] . value * 2 + 'px' ,
height : ticks [ i ] . value * 2 + 'px' ,
background : this . map . params . markerStyle . initial [ 'fill' ]
} ) . appendTo ( sample ) ;
break ;
}
tick . append ( sample ) ;
label = ticks [ i ] . label ;
if ( this . params . labelRender ) {
label = this . params . labelRender ( label ) ;
}
tick . append ( jvm . $ ( '<div>' + label + ' </div>' ) . addClass ( 'jvectormap-legend-tick-text' ) ) ;
inner . append ( tick ) ;
}
inner . append ( jvm . $ ( '<div/>' ) . css ( 'clear' , 'both' ) ) ;
} / * *
* Creates data series .
* @ constructor
* @ param { Object } params Parameters to initialize series with .
* @ param { Array } params . values The data set to visualize .
* @ param { String } params . attribute Numberic or color attribute to use for data visualization . This could be : < code > fill < / c o d e > , < c o d e > s t r o k e < / c o d e > , < c o d e > f i l l - o p a c i t y < / c o d e > , < c o d e > s t r o k e - o p a c i t y < / c o d e > f o r m a r k e r s a n d r e g i o n s a n d < c o d e > r < / c o d e > ( r a d i u s ) f o r m a r k e r s o n l y .
* @ param { Array } params . scale Values used to map a dimension of data to a visual representation . The first value sets visualization for minimum value from the data set and the last value sets visualization for the maximum value . There also could be intermidiate values . Default value is < code > [ '#C8EEFF' , '#0071A4' ] < / c o d e >
* @ param { Function | String } params . normalizeFunction The function used to map input values to the provided scale . This parameter could be provided as function or one of the strings : < code > 'linear' < / c o d e > o r < c o d e > ' p o l y n o m i a l ' < / c o d e > , w h i l e < c o d e > ' l i n e a r ' < / c o d e > i s u s e d b y d e f a u l t . T h e f u n c t i o n p r o v i d e d t a k e s v a l u e f r o m t h e d a t a s e t a s a n i n p u t a n d r e t u r n s c o r r e s p o n d i n g v a l u e f r o m t h e s c a l e .
* @ param { Number } params . min Minimum value of the data set . Could be calculated automatically if not provided .
* @ param { Number } params . min Maximum value of the data set . Could be calculated automatically if not provided .
* /
jvm . DataSeries = function ( params , elements , map ) {
var scaleConstructor ;
params = params || { } ;
params . attribute = params . attribute || 'fill' ;
this . elements = elements ;
this . params = params ;
this . map = map ;
if ( params . attributes ) {
this . setAttributes ( params . attributes ) ;
}
if ( jvm . $ . isArray ( params . scale ) ) {
scaleConstructor = ( params . attribute === 'fill' || params . attribute === 'stroke' ) ? jvm . ColorScale : jvm . NumericScale ;
this . scale = new scaleConstructor ( params . scale , params . normalizeFunction , params . min , params . max ) ;
} else if ( params . scale ) {
this . scale = new jvm . OrdinalScale ( params . scale ) ;
} else {
this . scale = new jvm . SimpleScale ( params . scale ) ;
}
this . values = params . values || { } ;
this . setValues ( this . values ) ;
if ( this . params . legend ) {
this . legend = new jvm . Legend ( $ . extend ( {
map : this . map ,
series : this
} , this . params . legend ) )
}
} ;
jvm . DataSeries . prototype = {
setAttributes : function ( key , attr ) {
var attrs = key ,
code ;
if ( typeof key == 'string' ) {
if ( this . elements [ key ] ) {
this . elements [ key ] . setStyle ( this . params . attribute , attr ) ;
}
} else {
for ( code in attrs ) {
if ( this . elements [ code ] ) {
this . elements [ code ] . element . setStyle ( this . params . attribute , attrs [ code ] ) ;
}
}
}
} ,
/ * *
* Set values for the data set .
* @ param { Object } values Object which maps codes of regions or markers to values .
* /
setValues : function ( values ) {
var max = - Number . MAX _VALUE ,
min = Number . MAX _VALUE ,
val ,
cc ,
attrs = { } ;
if ( ! ( this . scale instanceof jvm . OrdinalScale ) && ! ( this . scale instanceof jvm . SimpleScale ) ) {
// we have a color scale as an array
if ( typeof this . params . min === 'undefined' || typeof this . params . max === 'undefined' ) {
// min and/or max are not defined, so calculate them
for ( cc in values ) {
val = parseFloat ( values [ cc ] ) ;
if ( val > max ) max = val ;
if ( val < min ) min = val ;
}
}
if ( typeof this . params . min === 'undefined' ) {
this . scale . setMin ( min ) ;
this . params . min = min ;
} else {
this . scale . setMin ( this . params . min ) ;
}
if ( typeof this . params . max === 'undefined' ) {
this . scale . setMax ( max ) ;
this . params . max = max ;
} else {
this . scale . setMax ( this . params . max ) ;
}
for ( cc in values ) {
if ( cc != 'indexOf' ) {
val = parseFloat ( values [ cc ] ) ;
if ( ! isNaN ( val ) ) {
attrs [ cc ] = this . scale . getValue ( val ) ;
} else {
attrs [ cc ] = this . elements [ cc ] . element . style . initial [ this . params . attribute ] ;
}
}
}
} else {
for ( cc in values ) {
if ( values [ cc ] ) {
attrs [ cc ] = this . scale . getValue ( values [ cc ] ) ;
} else {
attrs [ cc ] = this . elements [ cc ] . element . style . initial [ this . params . attribute ] ;
}
}
}
this . setAttributes ( attrs ) ;
jvm . $ . extend ( this . values , values ) ;
} ,
clear : function ( ) {
var key ,
attrs = { } ;
for ( key in this . values ) {
if ( this . elements [ key ] ) {
attrs [ key ] = this . elements [ key ] . element . shape . style . initial [ this . params . attribute ] ;
}
}
this . setAttributes ( attrs ) ;
this . values = { } ;
} ,
/ * *
* Set scale of the data series .
* @ param { Array } scale Values representing scale .
* /
setScale : function ( scale ) {
this . scale . setScale ( scale ) ;
if ( this . values ) {
this . setValues ( this . values ) ;
}
} ,
/ * *
* Set normalize function of the data series .
* @ param { Function | String } normilizeFunction .
* /
setNormalizeFunction : function ( f ) {
this . scale . setNormalizeFunction ( f ) ;
if ( this . values ) {
this . setValues ( this . values ) ;
}
}
} ;
/ * *
* Contains methods for transforming point on sphere to
* Cartesian coordinates using various projections .
* @ class
* /
jvm . Proj = {
degRad : 180 / Math . PI ,
radDeg : Math . PI / 180 ,
radius : 6381372 ,
sgn : function ( n ) {
if ( n > 0 ) {
return 1 ;
} else if ( n < 0 ) {
return - 1 ;
} else {
return n ;
}
} ,
/ * *
* Converts point on sphere to the Cartesian coordinates using Miller projection
* @ param { Number } lat Latitude in degrees
* @ param { Number } lng Longitude in degrees
* @ param { Number } c Central meridian in degrees
* /
mill : function ( lat , lng , c ) {
return {
x : this . radius * ( lng - c ) * this . radDeg ,
y : - this . radius * Math . log ( Math . tan ( ( 45 + 0.4 * lat ) * this . radDeg ) ) / 0.8
} ;
} ,
/ * *
* Inverse function of mill ( )
* Converts Cartesian coordinates to point on sphere using Miller projection
* @ param { Number } x X of point in Cartesian system as integer
* @ param { Number } y Y of point in Cartesian system as integer
* @ param { Number } c Central meridian in degrees
* /
mill _inv : function ( x , y , c ) {
return {
lat : ( 2.5 * Math . atan ( Math . exp ( 0.8 * y / this . radius ) ) - 5 * Math . PI / 8 ) * this . degRad ,
lng : ( c * this . radDeg + x / this . radius ) * this . degRad
} ;
} ,
/ * *
* Converts point on sphere to the Cartesian coordinates using Mercator projection
* @ param { Number } lat Latitude in degrees
* @ param { Number } lng Longitude in degrees
* @ param { Number } c Central meridian in degrees
* /
merc : function ( lat , lng , c ) {
return {
x : this . radius * ( lng - c ) * this . radDeg ,
y : - this . radius * Math . log ( Math . tan ( Math . PI / 4 + lat * Math . PI / 360 ) )
} ;
} ,
/ * *
* Inverse function of merc ( )
* Converts Cartesian coordinates to point on sphere using Mercator projection
* @ param { Number } x X of point in Cartesian system as integer
* @ param { Number } y Y of point in Cartesian system as integer
* @ param { Number } c Central meridian in degrees
* /
merc _inv : function ( x , y , c ) {
return {
lat : ( 2 * Math . atan ( Math . exp ( y / this . radius ) ) - Math . PI / 2 ) * this . degRad ,
lng : ( c * this . radDeg + x / this . radius ) * this . degRad
} ;
} ,
/ * *
* Converts point on sphere to the Cartesian coordinates using Albers Equal - Area Conic
* projection
* @ see < a href = "http://mathworld.wolfram.com/AlbersEqual-AreaConicProjection.html" > Albers Equal - Area Conic projection < / a >
* @ param { Number } lat Latitude in degrees
* @ param { Number } lng Longitude in degrees
* @ param { Number } c Central meridian in degrees
* /
aea : function ( lat , lng , c ) {
var fi0 = 0 ,
lambda0 = c * this . radDeg ,
fi1 = 29.5 * this . radDeg ,
fi2 = 45.5 * this . radDeg ,
fi = lat * this . radDeg ,
lambda = lng * this . radDeg ,
n = ( Math . sin ( fi1 ) + Math . sin ( fi2 ) ) / 2 ,
C = Math . cos ( fi1 ) * Math . cos ( fi1 ) + 2 * n * Math . sin ( fi1 ) ,
theta = n * ( lambda - lambda0 ) ,
ro = Math . sqrt ( C - 2 * n * Math . sin ( fi ) ) / n ,
ro0 = Math . sqrt ( C - 2 * n * Math . sin ( fi0 ) ) / n ;
return {
x : ro * Math . sin ( theta ) * this . radius ,
y : - ( ro0 - ro * Math . cos ( theta ) ) * this . radius
} ;
} ,
/ * *
* Converts Cartesian coordinates to the point on sphere using Albers Equal - Area Conic
* projection
* @ see < a href = "http://mathworld.wolfram.com/AlbersEqual-AreaConicProjection.html" > Albers Equal - Area Conic projection < / a >
* @ param { Number } x X of point in Cartesian system as integer
* @ param { Number } y Y of point in Cartesian system as integer
* @ param { Number } c Central meridian in degrees
* /
aea _inv : function ( xCoord , yCoord , c ) {
var x = xCoord / this . radius ,
y = yCoord / this . radius ,
fi0 = 0 ,
lambda0 = c * this . radDeg ,
fi1 = 29.5 * this . radDeg ,
fi2 = 45.5 * this . radDeg ,
n = ( Math . sin ( fi1 ) + Math . sin ( fi2 ) ) / 2 ,
C = Math . cos ( fi1 ) * Math . cos ( fi1 ) + 2 * n * Math . sin ( fi1 ) ,
ro0 = Math . sqrt ( C - 2 * n * Math . sin ( fi0 ) ) / n ,
ro = Math . sqrt ( x * x + ( ro0 - y ) * ( ro0 - y ) ) ,
theta = Math . atan ( x / ( ro0 - y ) ) ;
return {
lat : ( Math . asin ( ( C - ro * ro * n * n ) / ( 2 * n ) ) ) * this . degRad ,
lng : ( lambda0 + theta / n ) * this . degRad
} ;
} ,
/ * *
* Converts point on sphere to the Cartesian coordinates using Lambert conformal
* conic projection
* @ see < a href = "http://mathworld.wolfram.com/LambertConformalConicProjection.html" > Lambert Conformal Conic Projection < / a >
* @ param { Number } lat Latitude in degrees
* @ param { Number } lng Longitude in degrees
* @ param { Number } c Central meridian in degrees
* /
lcc : function ( lat , lng , c ) {
var fi0 = 0 ,
lambda0 = c * this . radDeg ,
lambda = lng * this . radDeg ,
fi1 = 33 * this . radDeg ,
fi2 = 45 * this . radDeg ,
fi = lat * this . radDeg ,
n = Math . log ( Math . cos ( fi1 ) * ( 1 / Math . cos ( fi2 ) ) ) / Math . log ( Math . tan ( Math . PI / 4 + fi2 / 2 ) * ( 1 / Math . tan ( Math . PI / 4 + fi1 / 2 ) ) ) ,
F = ( Math . cos ( fi1 ) * Math . pow ( Math . tan ( Math . PI / 4 + fi1 / 2 ) , n ) ) / n ,
ro = F * Math . pow ( 1 / Math . tan ( Math . PI / 4 + fi / 2 ) , n ) ,
ro0 = F * Math . pow ( 1 / Math . tan ( Math . PI / 4 + fi0 / 2 ) , n ) ;
return {
x : ro * Math . sin ( n * ( lambda - lambda0 ) ) * this . radius ,
y : - ( ro0 - ro * Math . cos ( n * ( lambda - lambda0 ) ) ) * this . radius
} ;
} ,
/ * *
* Converts Cartesian coordinates to the point on sphere using Lambert conformal conic
* projection
* @ see < a href = "http://mathworld.wolfram.com/LambertConformalConicProjection.html" > Lambert Conformal Conic Projection < / a >
* @ param { Number } x X of point in Cartesian system as integer
* @ param { Number } y Y of point in Cartesian system as integer
* @ param { Number } c Central meridian in degrees
* /
lcc _inv : function ( xCoord , yCoord , c ) {
var x = xCoord / this . radius ,
y = yCoord / this . radius ,
fi0 = 0 ,
lambda0 = c * this . radDeg ,
fi1 = 33 * this . radDeg ,
fi2 = 45 * this . radDeg ,
n = Math . log ( Math . cos ( fi1 ) * ( 1 / Math . cos ( fi2 ) ) ) / Math . log ( Math . tan ( Math . PI / 4 + fi2 / 2 ) * ( 1 / Math . tan ( Math . PI / 4 + fi1 / 2 ) ) ) ,
F = ( Math . cos ( fi1 ) * Math . pow ( Math . tan ( Math . PI / 4 + fi1 / 2 ) , n ) ) / n ,
ro0 = F * Math . pow ( 1 / Math . tan ( Math . PI / 4 + fi0 / 2 ) , n ) ,
ro = this . sgn ( n ) * Math . sqrt ( x * x + ( ro0 - y ) * ( ro0 - y ) ) ,
theta = Math . atan ( x / ( ro0 - y ) ) ;
return {
lat : ( 2 * Math . atan ( Math . pow ( F / ro , 1 / n ) ) - Math . PI / 2 ) * this . degRad ,
lng : ( lambda0 + theta / n ) * this . degRad
} ;
}
} ; jvm . MapObject = function ( config ) { } ;
jvm . MapObject . prototype . getLabelText = function ( key ) {
var text ;
if ( this . config . label ) {
if ( typeof this . config . label . render === 'function' ) {
text = this . config . label . render ( key ) ;
} else {
text = key ;
}
} else {
text = null ;
}
return text ;
}
jvm . MapObject . prototype . getLabelOffsets = function ( key ) {
var offsets ;
if ( this . config . label ) {
if ( typeof this . config . label . offsets === 'function' ) {
offsets = this . config . label . offsets ( key ) ;
} else if ( typeof this . config . label . offsets === 'object' ) {
offsets = this . config . label . offsets [ key ] ;
}
}
return offsets || [ 0 , 0 ] ;
}
/ * *
* Set hovered state to the element . Hovered state means mouse cursor is over element . Styles will be updates respectively .
* @ param { Boolean } isHovered < code > true < / c o d e > t o m a k e e l e m e n t h o v e r e d , < c o d e > f a l s e < / c o d e > o t h e r w i s e .
* /
jvm . MapObject . prototype . setHovered = function ( isHovered ) {
if ( this . isHovered !== isHovered ) {
this . isHovered = isHovered ;
this . shape . isHovered = isHovered ;
this . shape . updateStyle ( ) ;
if ( this . label ) {
this . label . isHovered = isHovered ;
this . label . updateStyle ( ) ;
}
}
} ;
/ * *
* Set selected state to the element . Styles will be updates respectively .
* @ param { Boolean } isSelected < code > true < / c o d e > t o m a k e e l e m e n t s e l e c t e d , < c o d e > f a l s e < / c o d e > o t h e r w i s e .
* /
jvm . MapObject . prototype . setSelected = function ( isSelected ) {
if ( this . isSelected !== isSelected ) {
this . isSelected = isSelected ;
this . shape . isSelected = isSelected ;
this . shape . updateStyle ( ) ;
if ( this . label ) {
this . label . isSelected = isSelected ;
this . label . updateStyle ( ) ;
}
jvm . $ ( this . shape ) . trigger ( 'selected' , [ isSelected ] ) ;
}
} ;
jvm . MapObject . prototype . setStyle = function ( ) {
this . shape . setStyle . apply ( this . shape , arguments ) ;
} ;
jvm . MapObject . prototype . remove = function ( ) {
this . shape . remove ( ) ;
if ( this . label ) {
this . label . remove ( ) ;
}
} ; jvm . Region = function ( config ) {
var bbox ,
text ,
offsets ,
labelDx ,
labelDy ;
this . config = config ;
this . map = this . config . map ;
this . shape = config . canvas . addPath ( {
d : config . path ,
'data-code' : config . code
} , config . style , config . canvas . rootElement ) ;
this . shape . addClass ( 'jvectormap-region jvectormap-element' ) ;
bbox = this . shape . getBBox ( ) ;
text = this . getLabelText ( config . code ) ;
if ( this . config . label && text ) {
offsets = this . getLabelOffsets ( config . code ) ;
this . labelX = bbox . x + bbox . width / 2 + offsets [ 0 ] ;
this . labelY = bbox . y + bbox . height / 2 + offsets [ 1 ] ;
this . label = config . canvas . addText ( {
text : text ,
'text-anchor' : 'middle' ,
'alignment-baseline' : 'central' ,
x : this . labelX ,
y : this . labelY ,
'data-code' : config . code
} , config . labelStyle , config . labelsGroup ) ;
this . label . addClass ( 'jvectormap-region jvectormap-element' ) ;
}
} ;
jvm . inherits ( jvm . Region , jvm . MapObject ) ;
jvm . Region . prototype . updateLabelPosition = function ( ) {
if ( this . label ) {
this . label . set ( {
x : this . labelX * this . map . scale + this . map . transX * this . map . scale ,
y : this . labelY * this . map . scale + this . map . transY * this . map . scale
} ) ;
}
} ; jvm . Marker = function ( config ) {
var text ,
offsets ;
this . config = config ;
this . map = this . config . map ;
this . isImage = ! ! this . config . style . initial . image ;
this . createShape ( ) ;
2020-09-17 08:10:13 +00:00
text = this . getLabelText ( config . data ) ;
2020-07-24 03:01:32 +00:00
if ( this . config . label && text ) {
2020-09-17 08:10:13 +00:00
this . offsets = this . getLabelOffsets ( config . data ) ;
2020-07-24 03:01:32 +00:00
this . labelX = config . cx / this . map . scale - this . map . transX ;
this . labelY = config . cy / this . map . scale - this . map . transY ;
this . label = config . canvas . addText ( {
text : text ,
2020-09-17 08:10:13 +00:00
'data-index' : config . data ,
2020-07-24 03:01:32 +00:00
dy : "0.6ex" ,
x : this . labelX ,
y : this . labelY
} , config . labelStyle , config . labelsGroup ) ;
this . label . addClass ( 'jvectormap-marker jvectormap-element' ) ;
}
} ;
jvm . inherits ( jvm . Marker , jvm . MapObject ) ;
jvm . Marker . prototype . createShape = function ( ) {
var that = this ;
if ( this . shape ) {
this . shape . remove ( ) ;
}
this . shape = this . config . canvas [ this . isImage ? 'addImage' : 'addCircle' ] ( {
2020-09-17 08:10:13 +00:00
"data-index" : this . config . data ,
2020-07-24 03:01:32 +00:00
cx : this . config . cx ,
cy : this . config . cy
} , this . config . style , this . config . group ) ;
this . shape . addClass ( 'jvectormap-marker jvectormap-element' ) ;
if ( this . isImage ) {
jvm . $ ( this . shape . node ) . on ( 'imageloaded' , function ( ) {
that . updateLabelPosition ( ) ;
} ) ;
}
} ;
jvm . Marker . prototype . updateLabelPosition = function ( ) {
if ( this . label ) {
this . label . set ( {
x : this . labelX * this . map . scale + this . offsets [ 0 ] +
this . map . transX * this . map . scale + 5 + ( this . isImage ? ( this . shape . width || 0 ) / 2 : this . shape . properties . r ) ,
y : this . labelY * this . map . scale + this . map . transY * this . map . scale + this . offsets [ 1 ]
} ) ;
}
} ;
jvm . Marker . prototype . setStyle = function ( property , value ) {
var isImage ;
jvm . Marker . parentClass . prototype . setStyle . apply ( this , arguments ) ;
if ( property === 'r' ) {
this . updateLabelPosition ( ) ;
}
isImage = ! ! this . shape . get ( 'image' ) ;
if ( isImage != this . isImage ) {
this . isImage = isImage ;
this . config . style = jvm . $ . extend ( true , { } , this . shape . style ) ;
this . createShape ( ) ;
}
} ; / * *
* Creates map , draws paths , binds events .
* @ constructor
* @ param { Object } params Parameters to initialize map with .
* @ param { String } params . map Name of the map in the format < code > territory _proj _lang < / c o d e > w h e r e < c o d e > t e r r i t o r y < / c o d e > i s a u n i q u e c o d e o r n a m e o f t h e t e r r i t o r y w h i c h t h e m a p r e p r e s e n t s ( I S O 3 1 6 6 s t a n d a r d i s u s e d w h e r e p o s s i b l e ) , < c o d e > p r o j < / c o d e > i s a n a m e o f p r o j e c t i o n u s e d t o g e n e r a t e r e p r e s e n t a t i o n o f t h e m a p o n t h e p l a n e ( p r o j e c t i o n s a r e n a m e d a c c o r d i n g t o t h e c o n v e n t i o n s o f p r o j 4 u t i l i t y ) a n d < c o d e > l a n g < / c o d e > i s a c o d e o f t h e l a n g u a g e , u s e d f o r t h e n a m e s o f r e g i o n s .
* @ param { String } params . backgroundColor Background color of the map in CSS format .
* @ param { Boolean } params . zoomOnScroll When set to true map could be zoomed using mouse scroll . Default value is < code > true < / c o d e > .
* @ param { Boolean } params . panOnDrag When set to true , the map pans when being dragged . Default value is < code > true < / c o d e > .
* @ param { Number } params . zoomMax Indicates the maximum zoom ratio which could be reached zooming the map . Default value is < code > 8 < / c o d e > .
* @ param { Number } params . zoomMin Indicates the minimum zoom ratio which could be reached zooming the map . Default value is < code > 1 < / c o d e > .
* @ param { Number } params . zoomStep Indicates the multiplier used to zoom map with + / - b u t t o n s . D e f a u l t v a l u e i s < c o d e > 1 . 6 < / c o d e > .
* @ param { Boolean } params . zoomAnimate Indicates whether or not to animate changing of map zoom with zoom buttons .
* @ param { Boolean } params . regionsSelectable When set to true regions of the map could be selected . Default value is < code > false < / c o d e > .
* @ param { Boolean } params . regionsSelectableOne Allow only one region to be selected at the moment . Default value is < code > false < / c o d e > .
* @ param { Boolean } params . markersSelectable When set to true markers on the map could be selected . Default value is < code > false < / c o d e > .
* @ param { Boolean } params . markersSelectableOne Allow only one marker to be selected at the moment . Default value is < code > false < / c o d e > .
* @ param { Object } params . regionStyle Set the styles for the map 's regions. Each region or marker has four states: <code>initial</code> (default state), <code>hover</code> (when the mouse cursor is over the region or marker), <code>selected</code> (when region or marker is selected), <code>selectedHover</code> (when the mouse cursor is over the region or marker and it' s selected simultaneously ) . Styles could be set for each of this states . Default value for that parameter is :
< pre > {
initial : {
fill : 'white' ,
"fill-opacity" : 1 ,
stroke : 'none' ,
"stroke-width" : 0 ,
"stroke-opacity" : 1
} ,
hover : {
"fill-opacity" : 0.8 ,
cursor : 'pointer'
} ,
selected : {
fill : 'yellow'
} ,
selectedHover : {
}
} < / p r e >
* @ param { Object } params . regionLabelStyle Set the styles for the regions ' labels. Each region or marker has four states: <code>initial</code> (default state), <code>hover</code> (when the mouse cursor is over the region or marker), <code>selected</code> (when region or marker is selected), <code>selectedHover</code> (when the mouse cursor is over the region or marker and it' s selected simultaneously ) . Styles could be set for each of this states . Default value for that parameter is :
< pre > {
initial : {
'font-family' : 'Verdana' ,
'font-size' : '12' ,
'font-weight' : 'bold' ,
cursor : 'default' ,
fill : 'black'
} ,
hover : {
cursor : 'pointer'
}
} < / p r e >
* @ param { Object } params . markerStyle Set the styles for the map 's markers. Any parameter suitable for <code>regionStyle</code> could be used as well as numeric parameter <code>r</code> to set the marker' s radius . Default value for that parameter is :
< pre > {
initial : {
fill : 'grey' ,
stroke : '#505050' ,
"fill-opacity" : 1 ,
"stroke-width" : 1 ,
"stroke-opacity" : 1 ,
r : 5
} ,
hover : {
stroke : 'black' ,
"stroke-width" : 2 ,
cursor : 'pointer'
} ,
selected : {
fill : 'blue'
} ,
selectedHover : {
}
} < / p r e >
* @ param { Object } params . markerLabelStyle Set the styles for the markers ' labels . Default value for that parameter is :
< pre > {
initial : {
'font-family' : 'Verdana' ,
'font-size' : '12' ,
'font-weight' : 'bold' ,
cursor : 'default' ,
fill : 'black'
} ,
hover : {
cursor : 'pointer'
}
} < / p r e >
* @ param { Object | Array } params . markers Set of markers to add to the map during initialization . In case of array is provided , codes of markers will be set as string representations of array indexes . Each marker is represented by < code > latLng < / c o d e > ( a r r a y o f t w o n u m e r i c v a l u e s ) , < c o d e > n a m e < / c o d e > ( s t r i n g w h i c h w i l l b e s h o w o n m a r k e r ' s t i p ) a n d a n y m a r k e r s t y l e s .
* @ param { Object } params . series Object with two keys : < code > markers < / c o d e > a n d < c o d e > r e g i o n s < / c o d e > . E a c h o f w h i c h i s a n a r r a y o f s e r i e s c o n f i g s t o b e a p p l i e d t o t h e r e s p e c t i v e m a p e l e m e n t s . S e e < a h r e f = " j v m . D a t a S e r i e s . h t m l " > D a t a S e r i e s < / a > d e s c r i p t i o n f o r a l i s t o f p a r a m e t e r s a v a i l a b l e .
* @ param { Object | String } params . focusOn This parameter sets the initial position and scale of the map viewport . See < code > setFocus < / c o d e > d o c u e m n t a t i o n f o r p o s s i b l e p a r a m e t e r s .
* @ param { Object } params . labels Defines parameters for rendering static labels . Object could contain two keys : < code > regions < / c o d e > a n d < c o d e > m a r k e r s < / c o d e > . E a c h k e y v a l u e d e f i n e s c o n f i g u r a t i o n o b j e c t w i t h t h e f o l l o w i n g p o s s i b l e o p t i o n s :
< ul >
< li > < code > render { Function } < / c o d e > - d e f i n e s m e t h o d f o r c o n v e r t i n g r e g i o n c o d e o r m a r k e r i n d e x t o a c t u a l l a b e l v a l u e . < / l i >
< li > < code > offsets { Object | Function } < / c o d e > - p r o v i d e s m e t h o d o r o b j e c t w h i c h c o u l d b e u s e d t o d e f i n e l a b e l o f f s e t b y r e g i o n c o d e o r m a r k e r i n d e x . < / l i >
< / u l >
< b > Plase note : static labels feature is not supported in Internet Explorer 8 and below . < / b >
* @ param { Array | Object | String } params . selectedRegions Set initially selected regions .
* @ param { Array | Object | String } params . selectedMarkers Set initially selected markers .
* @ param { Function } params . onRegionTipShow < code > ( Event e , Object tip , String code ) < / c o d e > W i l l b e c a l l e d r i g h t b e f o r e t h e r e g i o n t i p i s g o i n g t o b e s h o w n .
* @ param { Function } params . onRegionOver < code > ( Event e , String code ) < / c o d e > W i l l b e c a l l e d o n r e g i o n m o u s e o v e r e v e n t .
* @ param { Function } params . onRegionOut < code > ( Event e , String code ) < / c o d e > W i l l b e c a l l e d o n r e g i o n m o u s e o u t e v e n t .
* @ param { Function } params . onRegionClick < code > ( Event e , String code ) < / c o d e > W i l l b e c a l l e d o n r e g i o n c l i c k e v e n t .
* @ param { Function } params . onRegionSelected < code > ( Event e , String code , Boolean isSelected , Array selectedRegions ) < / c o d e > W i l l b e c a l l e d w h e n r e g i o n i s ( d e ) s e l e c t e d . < c o d e > i s S e l e c t e d < / c o d e > p a r a m e t e r o f t h e c a l l b a c k i n d i c a t e s w h e t h e r r e g i o n i s s e l e c t e d o r n o t . < c o d e > s e l e c t e d R e g i o n s < / c o d e > c o n t a i n s c o d e s o f a l l c u r r e n t l y s e l e c t e d r e g i o n s .
* @ param { Function } params . onMarkerTipShow < code > ( Event e , Object tip , String code ) < / c o d e > W i l l b e c a l l e d r i g h t b e f o r e t h e m a r k e r t i p i s g o i n g t o b e s h o w n .
* @ param { Function } params . onMarkerOver < code > ( Event e , String code ) < / c o d e > W i l l b e c a l l e d o n m a r k e r m o u s e o v e r e v e n t .
* @ param { Function } params . onMarkerOut < code > ( Event e , String code ) < / c o d e > W i l l b e c a l l e d o n m a r k e r m o u s e o u t e v e n t .
* @ param { Function } params . onMarkerClick < code > ( Event e , String code ) < / c o d e > W i l l b e c a l l e d o n m a r k e r c l i c k e v e n t .
* @ param { Function } params . onMarkerSelected < code > ( Event e , String code , Boolean isSelected , Array selectedMarkers ) < / c o d e > W i l l b e c a l l e d w h e n m a r k e r i s ( d e ) s e l e c t e d . < c o d e > i s S e l e c t e d < / c o d e > p a r a m e t e r o f t h e c a l l b a c k i n d i c a t e s w h e t h e r m a r k e r i s s e l e c t e d o r n o t . < c o d e > s e l e c t e d M a r k e r s < / c o d e > c o n t a i n s c o d e s o f a l l c u r r e n t l y s e l e c t e d m a r k e r s .
* @ param { Function } params . onViewportChange < code > ( Event e , Number scale ) < / c o d e > T r i g g e r e d w h e n t h e m a p ' s v i e w p o r t i s c h a n g e d ( m a p w a s p a n n e d o r z o o m e d ) .
* /
jvm . Map = function ( params ) {
var map = this ,
e ;
this . params = jvm . $ . extend ( true , { } , jvm . Map . defaultParams , params ) ;
if ( ! jvm . Map . maps [ this . params . map ] ) {
throw new Error ( 'Attempt to use map which was not loaded: ' + this . params . map ) ;
}
this . mapData = jvm . Map . maps [ this . params . map ] ;
this . markers = { } ;
this . regions = { } ;
this . regionsColors = { } ;
this . regionsData = { } ;
this . container = jvm . $ ( '<div>' ) . addClass ( 'jvectormap-container' ) ;
if ( this . params . container ) {
this . params . container . append ( this . container ) ;
}
this . container . data ( 'mapObject' , this ) ;
this . defaultWidth = this . mapData . width ;
this . defaultHeight = this . mapData . height ;
this . setBackgroundColor ( this . params . backgroundColor ) ;
this . onResize = function ( ) {
map . updateSize ( ) ;
}
jvm . $ ( window ) . resize ( this . onResize ) ;
for ( e in jvm . Map . apiEvents ) {
if ( this . params [ e ] ) {
this . container . bind ( jvm . Map . apiEvents [ e ] + '.jvectormap' , this . params [ e ] ) ;
}
}
this . canvas = new jvm . VectorCanvas ( this . container [ 0 ] , this . width , this . height ) ;
if ( ( 'ontouchstart' in window ) || ( window . DocumentTouch && document instanceof DocumentTouch ) ) {
if ( this . params . bindTouchEvents ) {
this . bindContainerTouchEvents ( ) ;
}
}
this . bindContainerEvents ( ) ;
this . bindElementEvents ( ) ;
this . createTip ( ) ;
if ( this . params . zoomButtons ) {
this . bindZoomButtons ( ) ;
}
this . createRegions ( ) ;
this . createMarkers ( this . params . markers || { } ) ;
this . updateSize ( ) ;
if ( this . params . focusOn ) {
if ( typeof this . params . focusOn === 'string' ) {
this . params . focusOn = { region : this . params . focusOn } ;
} else if ( jvm . $ . isArray ( this . params . focusOn ) ) {
this . params . focusOn = { regions : this . params . focusOn } ;
}
this . setFocus ( this . params . focusOn ) ;
}
if ( this . params . selectedRegions ) {
this . setSelectedRegions ( this . params . selectedRegions ) ;
}
if ( this . params . selectedMarkers ) {
this . setSelectedMarkers ( this . params . selectedMarkers ) ;
}
this . legendCntHorizontal = jvm . $ ( '<div/>' ) . addClass ( 'jvectormap-legend-cnt jvectormap-legend-cnt-h' ) ;
this . legendCntVertical = jvm . $ ( '<div/>' ) . addClass ( 'jvectormap-legend-cnt jvectormap-legend-cnt-v' ) ;
this . container . append ( this . legendCntHorizontal ) ;
this . container . append ( this . legendCntVertical ) ;
if ( this . params . series ) {
this . createSeries ( ) ;
}
} ;
jvm . Map . prototype = {
transX : 0 ,
transY : 0 ,
scale : 1 ,
baseTransX : 0 ,
baseTransY : 0 ,
baseScale : 1 ,
width : 0 ,
height : 0 ,
/ * *
* Set background color of the map .
* @ param { String } backgroundColor Background color in CSS format .
* /
setBackgroundColor : function ( backgroundColor ) {
this . container . css ( 'background-color' , backgroundColor ) ;
} ,
resize : function ( ) {
var curBaseScale = this . baseScale ;
if ( this . width / this . height > this . defaultWidth / this . defaultHeight ) {
this . baseScale = this . height / this . defaultHeight ;
this . baseTransX = Math . abs ( this . width - this . defaultWidth * this . baseScale ) / ( 2 * this . baseScale ) ;
} else {
this . baseScale = this . width / this . defaultWidth ;
this . baseTransY = Math . abs ( this . height - this . defaultHeight * this . baseScale ) / ( 2 * this . baseScale ) ;
}
this . scale *= this . baseScale / curBaseScale ;
this . transX *= this . baseScale / curBaseScale ;
this . transY *= this . baseScale / curBaseScale ;
} ,
/ * *
* Synchronize the size of the map with the size of the container . Suitable in situations where the size of the container is changed programmatically or container is shown after it became visible .
* /
updateSize : function ( ) {
this . width = this . container . width ( ) ;
this . height = this . container . height ( ) ;
this . resize ( ) ;
this . canvas . setSize ( this . width , this . height ) ;
this . applyTransform ( ) ;
} ,
/ * *
* Reset all the series and show the map with the initial zoom .
* /
reset : function ( ) {
var key ,
i ;
for ( key in this . series ) {
for ( i = 0 ; i < this . series [ key ] . length ; i ++ ) {
this . series [ key ] [ i ] . clear ( ) ;
}
}
this . scale = this . baseScale ;
this . transX = this . baseTransX ;
this . transY = this . baseTransY ;
this . applyTransform ( ) ;
} ,
applyTransform : function ( ) {
var maxTransX ,
maxTransY ,
minTransX ,
minTransY ;
if ( this . defaultWidth * this . scale <= this . width ) {
maxTransX = ( this . width - this . defaultWidth * this . scale ) / ( 2 * this . scale ) ;
minTransX = ( this . width - this . defaultWidth * this . scale ) / ( 2 * this . scale ) ;
} else {
maxTransX = 0 ;
minTransX = ( this . width - this . defaultWidth * this . scale ) / this . scale ;
}
if ( this . defaultHeight * this . scale <= this . height ) {
maxTransY = ( this . height - this . defaultHeight * this . scale ) / ( 2 * this . scale ) ;
minTransY = ( this . height - this . defaultHeight * this . scale ) / ( 2 * this . scale ) ;
} else {
maxTransY = 0 ;
minTransY = ( this . height - this . defaultHeight * this . scale ) / this . scale ;
}
if ( this . transY > maxTransY ) {
this . transY = maxTransY ;
} else if ( this . transY < minTransY ) {
this . transY = minTransY ;
}
if ( this . transX > maxTransX ) {
this . transX = maxTransX ;
} else if ( this . transX < minTransX ) {
this . transX = minTransX ;
}
this . canvas . applyTransformParams ( this . scale , this . transX , this . transY ) ;
if ( this . markers ) {
this . repositionMarkers ( ) ;
}
this . repositionLabels ( ) ;
this . container . trigger ( 'viewportChange' , [ this . scale / this . baseScale , this . transX , this . transY ] ) ;
} ,
bindContainerEvents : function ( ) {
var mouseDown = false ,
oldPageX ,
oldPageY ,
map = this ;
if ( this . params . panOnDrag ) {
this . container . mousemove ( function ( e ) {
if ( mouseDown ) {
map . transX -= ( oldPageX - e . pageX ) / map . scale ;
map . transY -= ( oldPageY - e . pageY ) / map . scale ;
map . applyTransform ( ) ;
oldPageX = e . pageX ;
oldPageY = e . pageY ;
}
return false ;
} ) . mousedown ( function ( e ) {
mouseDown = true ;
oldPageX = e . pageX ;
oldPageY = e . pageY ;
return false ;
} ) ;
this . onContainerMouseUp = function ( ) {
mouseDown = false ;
} ;
jvm . $ ( 'body' ) . mouseup ( this . onContainerMouseUp ) ;
}
if ( this . params . zoomOnScroll ) {
this . container . mousewheel ( function ( event , delta , deltaX , deltaY ) {
var offset = jvm . $ ( map . container ) . offset ( ) ,
centerX = event . pageX - offset . left ,
centerY = event . pageY - offset . top ,
zoomStep = Math . pow ( 1.003 , event . deltaY ) ;
map . tip . hide ( ) ;
map . setScale ( map . scale * zoomStep , centerX , centerY ) ;
event . preventDefault ( ) ;
} ) ;
}
} ,
bindContainerTouchEvents : function ( ) {
var touchStartScale ,
touchStartDistance ,
map = this ,
touchX ,
touchY ,
centerTouchX ,
centerTouchY ,
lastTouchesLength ,
handleTouchEvent = function ( e ) {
var touches = e . originalEvent . touches ,
offset ,
scale ,
transXOld ,
transYOld ;
if ( e . type == 'touchstart' ) {
lastTouchesLength = 0 ;
}
if ( touches . length == 1 ) {
if ( lastTouchesLength == 1 ) {
transXOld = map . transX ;
transYOld = map . transY ;
map . transX -= ( touchX - touches [ 0 ] . pageX ) / map . scale ;
map . transY -= ( touchY - touches [ 0 ] . pageY ) / map . scale ;
map . applyTransform ( ) ;
map . tip . hide ( ) ;
if ( transXOld != map . transX || transYOld != map . transY ) {
e . preventDefault ( ) ;
}
}
touchX = touches [ 0 ] . pageX ;
touchY = touches [ 0 ] . pageY ;
} else if ( touches . length == 2 ) {
if ( lastTouchesLength == 2 ) {
scale = Math . sqrt (
Math . pow ( touches [ 0 ] . pageX - touches [ 1 ] . pageX , 2 ) +
Math . pow ( touches [ 0 ] . pageY - touches [ 1 ] . pageY , 2 )
) / touchStartDistance ;
map . setScale (
touchStartScale * scale ,
centerTouchX ,
centerTouchY
)
map . tip . hide ( ) ;
e . preventDefault ( ) ;
} else {
offset = jvm . $ ( map . container ) . offset ( ) ;
if ( touches [ 0 ] . pageX > touches [ 1 ] . pageX ) {
centerTouchX = touches [ 1 ] . pageX + ( touches [ 0 ] . pageX - touches [ 1 ] . pageX ) / 2 ;
} else {
centerTouchX = touches [ 0 ] . pageX + ( touches [ 1 ] . pageX - touches [ 0 ] . pageX ) / 2 ;
}
if ( touches [ 0 ] . pageY > touches [ 1 ] . pageY ) {
centerTouchY = touches [ 1 ] . pageY + ( touches [ 0 ] . pageY - touches [ 1 ] . pageY ) / 2 ;
} else {
centerTouchY = touches [ 0 ] . pageY + ( touches [ 1 ] . pageY - touches [ 0 ] . pageY ) / 2 ;
}
centerTouchX -= offset . left ;
centerTouchY -= offset . top ;
touchStartScale = map . scale ;
touchStartDistance = Math . sqrt (
Math . pow ( touches [ 0 ] . pageX - touches [ 1 ] . pageX , 2 ) +
Math . pow ( touches [ 0 ] . pageY - touches [ 1 ] . pageY , 2 )
) ;
}
}
lastTouchesLength = touches . length ;
} ;
jvm . $ ( this . container ) . bind ( 'touchstart' , handleTouchEvent ) ;
jvm . $ ( this . container ) . bind ( 'touchmove' , handleTouchEvent ) ;
} ,
bindElementEvents : function ( ) {
var map = this ,
mouseMoved ;
this . container . mousemove ( function ( ) {
mouseMoved = true ;
} ) ;
/ * C a n n o t u s e c o m m o n c l a s s s e l e c t o r s h e r e b e c a u s e o f t h e b u g i n j Q u e r y
SVG handling , use with caution . * /
this . container . delegate ( "[class~='jvectormap-element']" , 'mouseover mouseout' , function ( e ) {
var baseVal = jvm . $ ( this ) . attr ( 'class' ) . baseVal || jvm . $ ( this ) . attr ( 'class' ) ,
type = baseVal . indexOf ( 'jvectormap-region' ) === - 1 ? 'marker' : 'region' ,
code = type == 'region' ? jvm . $ ( this ) . attr ( 'data-code' ) : jvm . $ ( this ) . attr ( 'data-index' ) ,
element = type == 'region' ? map . regions [ code ] . element : map . markers [ code ] . element ,
tipText = type == 'region' ? map . mapData . paths [ code ] . name : ( map . markers [ code ] . config . name || '' ) ,
tipShowEvent = jvm . $ . Event ( type + 'TipShow.jvectormap' ) ,
overEvent = jvm . $ . Event ( type + 'Over.jvectormap' ) ;
if ( e . type == 'mouseover' ) {
map . container . trigger ( overEvent , [ code ] ) ;
if ( ! overEvent . isDefaultPrevented ( ) ) {
element . setHovered ( true ) ;
}
map . tip . text ( tipText ) ;
map . container . trigger ( tipShowEvent , [ map . tip , code ] ) ;
if ( ! tipShowEvent . isDefaultPrevented ( ) ) {
map . tip . show ( ) ;
map . tipWidth = map . tip . width ( ) ;
map . tipHeight = map . tip . height ( ) ;
}
} else {
element . setHovered ( false ) ;
map . tip . hide ( ) ;
map . container . trigger ( type + 'Out.jvectormap' , [ code ] ) ;
}
} ) ;
/ * C a n n o t u s e c o m m o n c l a s s s e l e c t o r s h e r e b e c a u s e o f t h e b u g i n j Q u e r y
SVG handling , use with caution . * /
this . container . delegate ( "[class~='jvectormap-element']" , 'mousedown' , function ( ) {
mouseMoved = false ;
} ) ;
/ * C a n n o t u s e c o m m o n c l a s s s e l e c t o r s h e r e b e c a u s e o f t h e b u g i n j Q u e r y
SVG handling , use with caution . * /
this . container . delegate ( "[class~='jvectormap-element']" , 'mouseup' , function ( ) {
var baseVal = jvm . $ ( this ) . attr ( 'class' ) . baseVal ? jvm . $ ( this ) . attr ( 'class' ) . baseVal : jvm . $ ( this ) . attr ( 'class' ) ,
type = baseVal . indexOf ( 'jvectormap-region' ) === - 1 ? 'marker' : 'region' ,
code = type == 'region' ? jvm . $ ( this ) . attr ( 'data-code' ) : jvm . $ ( this ) . attr ( 'data-index' ) ,
clickEvent = jvm . $ . Event ( type + 'Click.jvectormap' ) ,
element = type == 'region' ? map . regions [ code ] . element : map . markers [ code ] . element ;
if ( ! mouseMoved ) {
map . container . trigger ( clickEvent , [ code ] ) ;
if ( ( type === 'region' && map . params . regionsSelectable ) || ( type === 'marker' && map . params . markersSelectable ) ) {
if ( ! clickEvent . isDefaultPrevented ( ) ) {
if ( map . params [ type + 'sSelectableOne' ] ) {
map . clearSelected ( type + 's' ) ;
}
element . setSelected ( ! element . isSelected ) ;
}
}
}
} ) ;
} ,
bindZoomButtons : function ( ) {
var map = this ;
jvm . $ ( '<div/>' ) . addClass ( 'jvectormap-zoomin' ) . text ( '+' ) . appendTo ( this . container ) ;
jvm . $ ( '<div/>' ) . addClass ( 'jvectormap-zoomout' ) . html ( '−' ) . appendTo ( this . container ) ;
this . container . find ( '.jvectormap-zoomin' ) . click ( function ( ) {
map . setScale ( map . scale * map . params . zoomStep , map . width / 2 , map . height / 2 , false , map . params . zoomAnimate ) ;
} ) ;
this . container . find ( '.jvectormap-zoomout' ) . click ( function ( ) {
map . setScale ( map . scale / map . params . zoomStep , map . width / 2 , map . height / 2 , false , map . params . zoomAnimate ) ;
} ) ;
} ,
createTip : function ( ) {
var map = this ;
this . tip = jvm . $ ( '<div/>' ) . addClass ( 'jvectormap-tip' ) . appendTo ( jvm . $ ( 'body' ) ) ;
this . container . mousemove ( function ( e ) {
var left = e . pageX - 15 - map . tipWidth ,
top = e . pageY - 15 - map . tipHeight ;
if ( left < 5 ) {
left = e . pageX + 15 ;
}
if ( top < 5 ) {
top = e . pageY + 15 ;
}
if ( map . tip . is ( ':visible' ) ) {
map . tip . css ( {
left : left ,
top : top
} )
}
} ) ;
} ,
setScale : function ( scale , anchorX , anchorY , isCentered , animate ) {
var viewportChangeEvent = jvm . $ . Event ( 'zoom.jvectormap' ) ,
interval ,
that = this ,
i = 0 ,
count = Math . abs ( Math . round ( ( scale - this . scale ) * 60 / Math . max ( scale , this . scale ) ) ) ,
scaleStart ,
scaleDiff ,
transXStart ,
transXDiff ,
transYStart ,
transYDiff ,
transX ,
transY ,
deferred = new jvm . $ . Deferred ( ) ;
if ( scale > this . params . zoomMax * this . baseScale ) {
scale = this . params . zoomMax * this . baseScale ;
} else if ( scale < this . params . zoomMin * this . baseScale ) {
scale = this . params . zoomMin * this . baseScale ;
}
if ( typeof anchorX != 'undefined' && typeof anchorY != 'undefined' ) {
zoomStep = scale / this . scale ;
if ( isCentered ) {
transX = anchorX + this . defaultWidth * ( this . width / ( this . defaultWidth * scale ) ) / 2 ;
transY = anchorY + this . defaultHeight * ( this . height / ( this . defaultHeight * scale ) ) / 2 ;
} else {
transX = this . transX - ( zoomStep - 1 ) / scale * anchorX ;
transY = this . transY - ( zoomStep - 1 ) / scale * anchorY ;
}
}
if ( animate && count > 0 ) {
scaleStart = this . scale ;
scaleDiff = ( scale - scaleStart ) / count ;
transXStart = this . transX * this . scale ;
transYStart = this . transY * this . scale ;
transXDiff = ( transX * scale - transXStart ) / count ;
transYDiff = ( transY * scale - transYStart ) / count ;
interval = setInterval ( function ( ) {
i += 1 ;
that . scale = scaleStart + scaleDiff * i ;
that . transX = ( transXStart + transXDiff * i ) / that . scale ;
that . transY = ( transYStart + transYDiff * i ) / that . scale ;
that . applyTransform ( ) ;
if ( i == count ) {
clearInterval ( interval ) ;
that . container . trigger ( viewportChangeEvent , [ scale / that . baseScale ] ) ;
deferred . resolve ( ) ;
}
} , 10 ) ;
} else {
this . transX = transX ;
this . transY = transY ;
this . scale = scale ;
this . applyTransform ( ) ;
this . container . trigger ( viewportChangeEvent , [ scale / this . baseScale ] ) ;
deferred . resolve ( ) ;
}
return deferred ;
} ,
/ * *
* Set the map ' s viewport to the specific point and set zoom of the map to the specific level . Point and zoom level could be defined in two ways : using the code of some region to focus on or a central point and zoom level as numbers .
* @ param This method takes a configuration object as the single argument . The options passed to it are the following :
* @ param { Array } params . regions Array of region codes to zoom to .
* @ param { String } params . region Region code to zoom to .
* @ param { Number } params . scale Map scale to set .
* @ param { Number } params . lat Latitude to set viewport to .
* @ param { Number } params . lng Longitude to set viewport to .
* @ param { Number } params . x Number from 0 to 1 specifying the horizontal coordinate of the central point of the viewport .
* @ param { Number } params . y Number from 0 to 1 specifying the vertical coordinate of the central point of the viewport .
* @ param { Boolean } params . animate Indicates whether or not to animate the scale change and transition .
* /
setFocus : function ( config ) {
var bbox ,
itemBbox ,
newBbox ,
codes ,
i ,
point ;
config = config || { } ;
if ( config . region ) {
codes = [ config . region ] ;
} else if ( config . regions ) {
codes = config . regions ;
}
if ( codes ) {
for ( i = 0 ; i < codes . length ; i ++ ) {
if ( this . regions [ codes [ i ] ] ) {
itemBbox = this . regions [ codes [ i ] ] . element . shape . getBBox ( ) ;
if ( itemBbox ) {
if ( typeof bbox == 'undefined' ) {
bbox = itemBbox ;
} else {
newBbox = {
x : Math . min ( bbox . x , itemBbox . x ) ,
y : Math . min ( bbox . y , itemBbox . y ) ,
width : Math . max ( bbox . x + bbox . width , itemBbox . x + itemBbox . width ) - Math . min ( bbox . x , itemBbox . x ) ,
height : Math . max ( bbox . y + bbox . height , itemBbox . y + itemBbox . height ) - Math . min ( bbox . y , itemBbox . y )
}
bbox = newBbox ;
}
}
}
}
return this . setScale (
Math . min ( this . width / bbox . width , this . height / bbox . height ) ,
- ( bbox . x + bbox . width / 2 ) ,
- ( bbox . y + bbox . height / 2 ) ,
true ,
config . animate
) ;
} else {
if ( config . lat && config . lng ) {
point = this . latLngToPoint ( config . lat , config . lng ) ;
config . x = this . transX - point . x / this . scale ;
config . y = this . transY - point . y / this . scale ;
} else if ( config . x && config . y ) {
config . x *= - this . defaultWidth ;
config . y *= - this . defaultHeight ;
}
return this . setScale ( config . scale * this . baseScale , config . x , config . y , true , config . animate ) ;
}
} ,
getSelected : function ( type ) {
var key ,
selected = [ ] ;
for ( key in this [ type ] ) {
if ( this [ type ] [ key ] . element . isSelected ) {
selected . push ( key ) ;
}
}
return selected ;
} ,
/ * *
* Return the codes of currently selected regions .
* @ returns { Array }
* /
getSelectedRegions : function ( ) {
return this . getSelected ( 'regions' ) ;
} ,
/ * *
* Return the codes of currently selected markers .
* @ returns { Array }
* /
getSelectedMarkers : function ( ) {
return this . getSelected ( 'markers' ) ;
} ,
setSelected : function ( type , keys ) {
var i ;
if ( typeof keys != 'object' ) {
keys = [ keys ] ;
}
if ( jvm . $ . isArray ( keys ) ) {
for ( i = 0 ; i < keys . length ; i ++ ) {
this [ type ] [ keys [ i ] ] . element . setSelected ( true ) ;
}
} else {
for ( i in keys ) {
this [ type ] [ i ] . element . setSelected ( ! ! keys [ i ] ) ;
}
}
} ,
/ * *
* Set or remove selected state for the regions .
* @ param { String | Array | Object } keys If < code > String < / c o d e > o r < c o d e > A r r a y < / c o d e > t h e r e g i o n ( s ) w i t h t h e c o r r e s p o n d i n g c o d e ( s ) w i l l b e s e l e c t e d . I f < c o d e > O b j e c t < / c o d e > w a s p r o v i d e d i t s k e y s a r e c o d e s o f r e g i o n s , s t a t e o f w h i c h s h o u l d b e c h a n g e d . S e l e c t e d s t a t e w i l l b e s e t i f v a l u e i s t r u e , r e m o v e d o t h e r w i s e .
* /
setSelectedRegions : function ( keys ) {
this . setSelected ( 'regions' , keys ) ;
} ,
/ * *
* Set or remove selected state for the markers .
* @ param { String | Array | Object } keys If < code > String < / c o d e > o r < c o d e > A r r a y < / c o d e > t h e m a r k e r ( s ) w i t h t h e c o r r e s p o n d i n g c o d e ( s ) w i l l b e s e l e c t e d . I f < c o d e > O b j e c t < / c o d e > w a s p r o v i d e d i t s k e y s a r e c o d e s o f m a r k e r s , s t a t e o f w h i c h s h o u l d b e c h a n g e d . S e l e c t e d s t a t e w i l l b e s e t i f v a l u e i s t r u e , r e m o v e d o t h e r w i s e .
* /
setSelectedMarkers : function ( keys ) {
this . setSelected ( 'markers' , keys ) ;
} ,
clearSelected : function ( type ) {
var select = { } ,
selected = this . getSelected ( type ) ,
i ;
for ( i = 0 ; i < selected . length ; i ++ ) {
select [ selected [ i ] ] = false ;
} ;
this . setSelected ( type , select ) ;
} ,
/ * *
* Remove the selected state from all the currently selected regions .
* /
clearSelectedRegions : function ( ) {
this . clearSelected ( 'regions' ) ;
} ,
/ * *
* Remove the selected state from all the currently selected markers .
* /
clearSelectedMarkers : function ( ) {
this . clearSelected ( 'markers' ) ;
} ,
/ * *
* Return the instance of Map . Useful when instantiated as a jQuery plug - in .
* @ returns { Map }
* /
getMapObject : function ( ) {
return this ;
} ,
/ * *
* Return the name of the region by region code .
* @ returns { String }
* /
getRegionName : function ( code ) {
return this . mapData . paths [ code ] . name ;
} ,
createRegions : function ( ) {
var key ,
region ,
map = this ;
this . regionLabelsGroup = this . regionLabelsGroup || this . canvas . addGroup ( ) ;
for ( key in this . mapData . paths ) {
region = new jvm . Region ( {
map : this ,
path : this . mapData . paths [ key ] . path ,
code : key ,
style : jvm . $ . extend ( true , { } , this . params . regionStyle ) ,
labelStyle : jvm . $ . extend ( true , { } , this . params . regionLabelStyle ) ,
canvas : this . canvas ,
labelsGroup : this . regionLabelsGroup ,
label : this . canvas . mode != 'vml' ? ( this . params . labels && this . params . labels . regions ) : null
} ) ;
jvm . $ ( region . shape ) . bind ( 'selected' , function ( e , isSelected ) {
map . container . trigger ( 'regionSelected.jvectormap' , [ jvm . $ ( this . node ) . attr ( 'data-code' ) , isSelected , map . getSelectedRegions ( ) ] ) ;
} ) ;
this . regions [ key ] = {
element : region ,
config : this . mapData . paths [ key ]
} ;
}
} ,
createMarkers : function ( markers ) {
var i ,
marker ,
point ,
markerConfig ,
markersArray ,
map = this ;
this . markersGroup = this . markersGroup || this . canvas . addGroup ( ) ;
this . markerLabelsGroup = this . markerLabelsGroup || this . canvas . addGroup ( ) ;
if ( jvm . $ . isArray ( markers ) ) {
markersArray = markers . slice ( ) ;
markers = { } ;
for ( i = 0 ; i < markersArray . length ; i ++ ) {
markers [ i ] = markersArray [ i ] ;
}
}
for ( i in markers ) {
markerConfig = markers [ i ] instanceof Array ? { latLng : markers [ i ] } : markers [ i ] ;
point = this . getMarkerPosition ( markerConfig ) ;
if ( point !== false ) {
marker = new jvm . Marker ( {
map : this ,
style : jvm . $ . extend ( true , { } , this . params . markerStyle , { initial : markerConfig . style || { } } ) ,
labelStyle : jvm . $ . extend ( true , { } , this . params . markerLabelStyle ) ,
index : i ,
cx : point . x ,
cy : point . y ,
group : this . markersGroup ,
canvas : this . canvas ,
labelsGroup : this . markerLabelsGroup ,
label : this . canvas . mode != 'vml' ? ( this . params . labels && this . params . labels . markers ) : null
} ) ;
jvm . $ ( marker . shape ) . bind ( 'selected' , function ( e , isSelected ) {
map . container . trigger ( 'markerSelected.jvectormap' , [ jvm . $ ( this . node ) . attr ( 'data-index' ) , isSelected , map . getSelectedMarkers ( ) ] ) ;
} ) ;
if ( this . markers [ i ] ) {
this . removeMarkers ( [ i ] ) ;
}
this . markers [ i ] = { element : marker , config : markerConfig } ;
}
}
} ,
repositionMarkers : function ( ) {
var i ,
point ;
for ( i in this . markers ) {
point = this . getMarkerPosition ( this . markers [ i ] . config ) ;
if ( point !== false ) {
this . markers [ i ] . element . setStyle ( { cx : point . x , cy : point . y } ) ;
}
}
} ,
repositionLabels : function ( ) {
var key ;
for ( key in this . regions ) {
this . regions [ key ] . element . updateLabelPosition ( ) ;
}
for ( key in this . markers ) {
this . markers [ key ] . element . updateLabelPosition ( ) ;
}
} ,
getMarkerPosition : function ( markerConfig ) {
if ( jvm . Map . maps [ this . params . map ] . projection ) {
return this . latLngToPoint . apply ( this , markerConfig . latLng || [ 0 , 0 ] ) ;
} else {
return {
x : markerConfig . coords [ 0 ] * this . scale + this . transX * this . scale ,
y : markerConfig . coords [ 1 ] * this . scale + this . transY * this . scale
} ;
}
} ,
/ * *
* Add one marker to the map .
* @ param { String } key Marker unique code .
* @ param { Object } marker Marker configuration parameters .
* @ param { Array } seriesData Values to add to the data series .
* /
addMarker : function ( key , marker , seriesData ) {
var markers = { } ,
data = [ ] ,
values ,
i ,
seriesData = seriesData || [ ] ;
markers [ key ] = marker ;
for ( i = 0 ; i < seriesData . length ; i ++ ) {
values = { } ;
if ( typeof seriesData [ i ] !== 'undefined' ) {
values [ key ] = seriesData [ i ] ;
}
data . push ( values ) ;
}
this . addMarkers ( markers , data ) ;
} ,
/ * *
* Add set of marker to the map .
* @ param { Object | Array } markers Markers to add to the map . In case of array is provided , codes of markers will be set as string representations of array indexes .
* @ param { Array } seriesData Values to add to the data series .
* /
addMarkers : function ( markers , seriesData ) {
var i ;
seriesData = seriesData || [ ] ;
this . createMarkers ( markers ) ;
for ( i = 0 ; i < seriesData . length ; i ++ ) {
this . series . markers [ i ] . setValues ( seriesData [ i ] || { } ) ;
} ;
} ,
/ * *
* Remove some markers from the map .
* @ param { Array } markers Array of marker codes to be removed .
* /
removeMarkers : function ( markers ) {
var i ;
for ( i = 0 ; i < markers . length ; i ++ ) {
this . markers [ markers [ i ] ] . element . remove ( ) ;
delete this . markers [ markers [ i ] ] ;
} ;
} ,
/ * *
* Remove all markers from the map .
* /
removeAllMarkers : function ( ) {
var i ,
markers = [ ] ;
for ( i in this . markers ) {
markers . push ( i ) ;
}
this . removeMarkers ( markers )
} ,
/ * *
* Converts coordinates expressed as latitude and longitude to the coordinates in pixels on the map .
* @ param { Number } lat Latitide of point in degrees .
* @ param { Number } lng Longitude of point in degrees .
* /
latLngToPoint : function ( lat , lng ) {
var point ,
proj = jvm . Map . maps [ this . params . map ] . projection ,
centralMeridian = proj . centralMeridian ,
inset ,
bbox ;
if ( lng < ( - 180 + centralMeridian ) ) {
lng += 360 ;
}
point = jvm . Proj [ proj . type ] ( lat , lng , centralMeridian ) ;
inset = this . getInsetForPoint ( point . x , point . y ) ;
if ( inset ) {
bbox = inset . bbox ;
point . x = ( point . x - bbox [ 0 ] . x ) / ( bbox [ 1 ] . x - bbox [ 0 ] . x ) * inset . width * this . scale ;
point . y = ( point . y - bbox [ 0 ] . y ) / ( bbox [ 1 ] . y - bbox [ 0 ] . y ) * inset . height * this . scale ;
return {
x : point . x + this . transX * this . scale + inset . left * this . scale ,
y : point . y + this . transY * this . scale + inset . top * this . scale
} ;
} else {
return false ;
}
} ,
/ * *
* Converts cartesian coordinates into coordinates expressed as latitude and longitude .
* @ param { Number } x X - axis of point on map in pixels .
* @ param { Number } y Y - axis of point on map in pixels .
* /
pointToLatLng : function ( x , y ) {
var proj = jvm . Map . maps [ this . params . map ] . projection ,
centralMeridian = proj . centralMeridian ,
insets = jvm . Map . maps [ this . params . map ] . insets ,
i ,
inset ,
bbox ,
nx ,
ny ;
for ( i = 0 ; i < insets . length ; i ++ ) {
inset = insets [ i ] ;
bbox = inset . bbox ;
nx = x - ( this . transX * this . scale + inset . left * this . scale ) ;
ny = y - ( this . transY * this . scale + inset . top * this . scale ) ;
nx = ( nx / ( inset . width * this . scale ) ) * ( bbox [ 1 ] . x - bbox [ 0 ] . x ) + bbox [ 0 ] . x ;
ny = ( ny / ( inset . height * this . scale ) ) * ( bbox [ 1 ] . y - bbox [ 0 ] . y ) + bbox [ 0 ] . y ;
if ( nx > bbox [ 0 ] . x && nx < bbox [ 1 ] . x && ny > bbox [ 0 ] . y && ny < bbox [ 1 ] . y ) {
return jvm . Proj [ proj . type + '_inv' ] ( nx , - ny , centralMeridian ) ;
}
}
return false ;
} ,
getInsetForPoint : function ( x , y ) {
var insets = jvm . Map . maps [ this . params . map ] . insets ,
i ,
bbox ;
for ( i = 0 ; i < insets . length ; i ++ ) {
bbox = insets [ i ] . bbox ;
if ( x > bbox [ 0 ] . x && x < bbox [ 1 ] . x && y > bbox [ 0 ] . y && y < bbox [ 1 ] . y ) {
return insets [ i ] ;
}
}
} ,
createSeries : function ( ) {
var i ,
key ;
this . series = {
markers : [ ] ,
regions : [ ]
} ;
for ( key in this . params . series ) {
for ( i = 0 ; i < this . params . series [ key ] . length ; i ++ ) {
this . series [ key ] [ i ] = new jvm . DataSeries (
this . params . series [ key ] [ i ] ,
this [ key ] ,
this
) ;
}
}
} ,
/ * *
* Gracefully remove the map and and all its accessories , unbind event handlers .
* /
remove : function ( ) {
this . tip . remove ( ) ;
this . container . remove ( ) ;
jvm . $ ( window ) . unbind ( 'resize' , this . onResize ) ;
jvm . $ ( 'body' ) . unbind ( 'mouseup' , this . onContainerMouseUp ) ;
}
} ;
jvm . Map . maps = { } ;
jvm . Map . defaultParams = {
map : 'world_mill_en' ,
backgroundColor : '#505050' ,
zoomButtons : true ,
zoomOnScroll : true ,
panOnDrag : true ,
zoomMax : 8 ,
zoomMin : 1 ,
zoomStep : 1.6 ,
zoomAnimate : true ,
regionsSelectable : false ,
markersSelectable : false ,
bindTouchEvents : true ,
regionStyle : {
initial : {
fill : 'white' ,
"fill-opacity" : 1 ,
stroke : 'none' ,
"stroke-width" : 0 ,
"stroke-opacity" : 1
} ,
hover : {
"fill-opacity" : 0.8 ,
cursor : 'pointer'
} ,
selected : {
fill : 'yellow'
} ,
selectedHover : {
}
} ,
regionLabelStyle : {
initial : {
'font-family' : 'Verdana' ,
'font-size' : '12' ,
'font-weight' : 'bold' ,
cursor : 'default' ,
fill : 'black'
} ,
hover : {
cursor : 'pointer'
}
} ,
markerStyle : {
initial : {
fill : 'grey' ,
stroke : '#505050' ,
"fill-opacity" : 1 ,
"stroke-width" : 1 ,
"stroke-opacity" : 1 ,
r : 5
} ,
hover : {
stroke : 'black' ,
"stroke-width" : 2 ,
cursor : 'pointer'
} ,
selected : {
fill : 'blue'
} ,
selectedHover : {
}
} ,
markerLabelStyle : {
initial : {
'font-family' : 'Verdana' ,
'font-size' : '12' ,
'font-weight' : 'bold' ,
cursor : 'default' ,
fill : 'black'
} ,
hover : {
cursor : 'pointer'
}
}
} ;
jvm . Map . apiEvents = {
onRegionTipShow : 'regionTipShow' ,
onRegionOver : 'regionOver' ,
onRegionOut : 'regionOut' ,
onRegionClick : 'regionClick' ,
onRegionSelected : 'regionSelected' ,
onMarkerTipShow : 'markerTipShow' ,
onMarkerOver : 'markerOver' ,
onMarkerOut : 'markerOut' ,
onMarkerClick : 'markerClick' ,
onMarkerSelected : 'markerSelected' ,
onViewportChange : 'viewportChange'
} ;
/ * *
* Creates map with drill - down functionality .
* @ constructor
* @ param { Object } params Parameters to initialize map with .
* @ param { Number } params . maxLevel Maximum number of levels user can go through
* @ param { Object } params . main Config of the main map . See < a href = "./jvm-map/" > jvm . Map < / a > f o r m o r e i n f o r m a t i o n .
* @ param { Function } params . mapNameByCode Function go generate map name by region code . Default value is :
< pre >
function ( code , multiMap ) {
return code . toLowerCase ( ) + '_' +
multiMap . defaultProjection + '_en' ;
}
< / p r e >
* @ param { Function } params . mapUrlByCode Function to generate map url by region code . Default value is :
< pre >
function ( code , multiMap ) {
return 'jquery-jvectormap-data-' +
code . toLowerCase ( ) + '-' +
multiMap . defaultProjection + '-en.js' ;
}
< / p r e >
* /
jvm . MultiMap = function ( params ) {
var that = this ;
this . maps = { } ;
this . params = jvm . $ . extend ( true , { } , jvm . MultiMap . defaultParams , params ) ;
this . params . maxLevel = this . params . maxLevel || Number . MAX _VALUE ;
this . params . main = this . params . main || { } ;
this . params . main . multiMapLevel = 0 ;
this . history = [ this . addMap ( this . params . main . map , this . params . main ) ] ;
this . defaultProjection = this . history [ 0 ] . mapData . projection . type ;
this . mapsLoaded = { } ;
this . params . container . css ( { position : 'relative' } ) ;
this . backButton = jvm . $ ( '<div/>' ) . addClass ( 'jvectormap-goback' ) . text ( 'Back' ) . appendTo ( this . params . container ) ;
this . backButton . hide ( ) ;
this . backButton . click ( function ( ) {
that . goBack ( ) ;
} ) ;
this . spinner = jvm . $ ( '<div/>' ) . addClass ( 'jvectormap-spinner' ) . appendTo ( this . params . container ) ;
this . spinner . hide ( ) ;
} ;
jvm . MultiMap . prototype = {
addMap : function ( name , config ) {
var cnt = jvm . $ ( '<div/>' ) . css ( {
width : '100%' ,
height : '100%'
} ) ;
this . params . container . append ( cnt ) ;
this . maps [ name ] = new jvm . Map ( jvm . $ . extend ( config , { container : cnt } ) ) ;
if ( this . params . maxLevel > config . multiMapLevel ) {
this . maps [ name ] . container . on ( 'regionClick.jvectormap' , { scope : this } , function ( e , code ) {
var multimap = e . data . scope ,
mapName = multimap . params . mapNameByCode ( code , multimap ) ;
if ( ! multimap . drillDownPromise || multimap . drillDownPromise . state ( ) !== 'pending' ) {
multimap . drillDown ( mapName , code ) ;
}
} ) ;
}
return this . maps [ name ] ;
} ,
downloadMap : function ( code ) {
var that = this ,
deferred = jvm . $ . Deferred ( ) ;
if ( ! this . mapsLoaded [ code ] ) {
jvm . $ . get ( this . params . mapUrlByCode ( code , this ) ) . then ( function ( ) {
that . mapsLoaded [ code ] = true ;
deferred . resolve ( ) ;
} , function ( ) {
deferred . reject ( ) ;
} ) ;
} else {
deferred . resolve ( ) ;
}
return deferred ;
} ,
drillDown : function ( name , code ) {
var currentMap = this . history [ this . history . length - 1 ] ,
that = this ,
focusPromise = currentMap . setFocus ( { region : code , animate : true } ) ,
downloadPromise = this . downloadMap ( code ) ;
focusPromise . then ( function ( ) {
if ( downloadPromise . state ( ) === 'pending' ) {
that . spinner . show ( ) ;
}
} ) ;
downloadPromise . always ( function ( ) {
that . spinner . hide ( ) ;
} ) ;
this . drillDownPromise = jvm . $ . when ( downloadPromise , focusPromise ) ;
this . drillDownPromise . then ( function ( ) {
currentMap . params . container . hide ( ) ;
if ( ! that . maps [ name ] ) {
that . addMap ( name , { map : name , multiMapLevel : currentMap . params . multiMapLevel + 1 } ) ;
} else {
that . maps [ name ] . params . container . show ( ) ;
}
that . history . push ( that . maps [ name ] ) ;
that . backButton . show ( ) ;
} ) ;
} ,
goBack : function ( ) {
var currentMap = this . history . pop ( ) ,
prevMap = this . history [ this . history . length - 1 ] ,
that = this ;
currentMap . setFocus ( { scale : 1 , x : 0.5 , y : 0.5 , animate : true } ) . then ( function ( ) {
currentMap . params . container . hide ( ) ;
prevMap . params . container . show ( ) ;
prevMap . updateSize ( ) ;
if ( that . history . length === 1 ) {
that . backButton . hide ( ) ;
}
prevMap . setFocus ( { scale : 1 , x : 0.5 , y : 0.5 , animate : true } ) ;
} ) ;
}
} ;
jvm . MultiMap . defaultParams = {
mapNameByCode : function ( code , multiMap ) {
return code . toLowerCase ( ) + '_' + multiMap . defaultProjection + '_en' ;
} ,
mapUrlByCode : function ( code , multiMap ) {
return 'jquery-jvectormap-data-' + code . toLowerCase ( ) + '-' + multiMap . defaultProjection + '-en.js' ;
}
}