initial import

This commit is contained in:
2020-12-23 10:11:11 +01:00
commit be83b43a59
5600 changed files with 577973 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
{
"name": "jvectormap",
"homepage": "https://github.com/bjornd/jvectormap",
"version": "1.2.2",
"_release": "1.2.2",
"_resolution": {
"type": "version",
"tag": "1.2.2",
"commit": "60059b8d6e68d37ef544ab542060f5ab87b5018a"
},
"_source": "https://github.com/bjornd/jvectormap.git",
"_target": "^1.2.2",
"_originalSource": "jvectormap"
}

View File

@@ -0,0 +1,20 @@
This is an official git repository for the jVectorMap plug-in for jQuery. Its main purpose is to show interactive vector maps on the web pages.
You can find maps, documentation, examples and more at [the official site](http://jvectormap.com/)
It also includes a converter that could be used to create your own maps for jVectorMap from the data in various GIS formats like Shapefile. The following command could be used to convert USA map from the data available at [www.naturalearthdata.com](http://www.naturalearthdata.com/downloads/10m-cultural-vectors/10m-admin-1-states-provinces/):
python \
path/to/converter.py \
path/to/geo-data.shp \
path/to/resulting-map.js \
--width 900 \
--country_name_index 4 \
--where "ISO = 'USA'" \
--codes_file path/to/codes-en.tsv \
--insets '[{"codes": ["US-AK"], "width": 200, "left": 10, "top": 370}, {"codes": ["US-HI"], "width": 100, "left": 220, "top": 400}]' \
--minimal_area 4000000 \
--buffer_distance -0.5 \
--simplify_tolerance 1000 \
--longitude0 -10.15 \
--name us

View File

@@ -0,0 +1,54 @@
#!/bin/bash
files=( \
jquery-jvectormap.js \
jquery-mousewheel.js \
lib/jvectormap.js \
lib/abstract-element.js \
lib/abstract-canvas-element.js \
lib/abstract-shape-element.js \
lib/svg-element.js \
lib/svg-group-element.js \
lib/svg-canvas-element.js \
lib/svg-shape-element.js \
lib/svg-path-element.js \
lib/svg-circle-element.js \
lib/vml-element.js \
lib/vml-group-element.js \
lib/vml-canvas-element.js \
lib/vml-shape-element.js \
lib/vml-path-element.js \
lib/vml-circle-element.js \
lib/vector-canvas.js \
lib/simple-scale.js \
lib/ordinal-scale.js \
lib/numeric-scale.js \
lib/color-scale.js \
lib/data-series.js \
lib/proj.js \
lib/world-map.js \
)
baseDir=`dirname $0`
counter=0
while [ $counter -lt ${#files[@]} ]; do
files[$counter]="$baseDir/${files[$counter]}"
let counter=counter+1
done
if [ -z "$1" ]
then
minified=jquery.jvectormap.min.js
else
minified=$1
fi
if [ -a $minified ]
then
rm $minified
fi
cat ${files[*]} >> $minified
uglifyjs --overwrite $minified

View File

@@ -0,0 +1,295 @@
#
# jVectorMap version 1.2.2
#
# Copyright 2011-2013, Kirill Lebedev
# Licensed under the MIT license.
#
import argparse
import sys
from osgeo import ogr
from osgeo import osr
import json
import shapely.geometry
import codecs
class Map:
def __init__(self, name, language):
self.paths = {}
self.name = name
self.language = language
self.width = 0
self.heoght = 0
self.bbox = []
def addPath(self, path, code, name):
self.paths[code] = {"path": path, "name": name}
def getJSCode(self):
map = {"paths": self.paths, "width": self.width, "height": self.height, "insets": self.insets, "projection": self.projection}
return "jQuery.fn.vectorMap('addMap', '"+self.name+"_"+self.projection['type']+"_"+self.language+"',"+json.dumps(map)+');'
class Converter:
def __init__(self, args):
self.map = Map(args['name'], args.get('language'))
if args.get('sources'):
self.sources = args['sources']
else:
self.sources = [{
'input_file': args.get('input_file'),
'where': args.get('where'),
'codes_file': args.get('codes_file'),
'country_name_index': args.get('country_name_index'),
'country_code_index': args.get('country_code_index'),
'input_file_encoding': args.get('input_file_encoding')
}]
default_source = {
'where': '',
'codes_file': '',
'country_name_index': '0',
'country_code_index': '1',
'input_file_encoding': 'iso-8859-1'
}
for index in range(len(self.sources)):
for key in default_source:
if self.sources[index].get(key) is None:
self.sources[index][key] = default_source[key]
self.features = {}
self.width = args.get('width')
self.minimal_area = args.get('minimal_area')
self.longitude0 = args.get('longitude0')
self.projection = args.get('projection')
self.precision = args.get('precision')
self.buffer_distance = args.get('buffer_distance')
self.simplify_tolerance = args.get('simplify_tolerance')
if args.get('viewport'):
self.viewport = map(lambda s: float(s), args.get('viewport').split(' '))
else:
self.viewport = False
# spatial reference to convert to
self.spatialRef = osr.SpatialReference()
self.spatialRef.ImportFromProj4('+proj='+self.projection+' +a=6381372 +b=6381372 +lat_0=0 +lon_0='+str(self.longitude0))
# handle map insets
if args.get('insets'):
self.insets = json.loads(args.get('insets'))
else:
self.insets = []
def loadData(self):
for sourceConfig in self.sources:
self.loadDataSource( sourceConfig )
def loadDataSource(self, sourceConfig):
source = ogr.Open( sourceConfig['input_file'] )
layer = source.GetLayer(0)
layer.SetAttributeFilter( sourceConfig['where'].encode('ascii') )
self.viewportRect = False
if self.viewport:
layer.SetSpatialFilterRect( *sourceConfig.get('viewport') )
transformation = osr.CoordinateTransformation( layer.GetSpatialRef(), self.spatialRef )
point1 = transformation.TransformPoint(self.viewport[0], self.viewport[1])
point2 = transformation.TransformPoint(self.viewport[2], self.viewport[3])
self.viewportRect = shapely.geometry.box(point1[0], point1[1], point2[0], point2[1])
layer.ResetReading()
# load codes from external tsv file if present or geodata file otherwise
codes = {}
if sourceConfig.get('codes_file'):
for line in codecs.open(sourceConfig.get('codes_file'), 'r', "utf-8"):
row = map(lambda s: s.strip(), line.split('\t'))
codes[row[1]] = row[0]
else:
nextCode = 0
for feature in layer:
code = feature.GetFieldAsString(sourceConfig.get('country_code_index'))
if code == '-99':
code = '_'+str(nextCode)
nextCode += 1
name = feature.GetFieldAsString(sourceConfig.get('country_name_index')).decode(sourceConfig.get('input_file_encoding'))
codes[name] = code
layer.ResetReading()
# load features
for feature in layer:
geometry = feature.GetGeometryRef()
geometryType = geometry.GetGeometryType()
if geometryType == ogr.wkbPolygon or geometryType == ogr.wkbMultiPolygon:
geometry.TransformTo( self.spatialRef )
shapelyGeometry = shapely.wkb.loads( geometry.ExportToWkb() )
if not shapelyGeometry.is_valid:
#buffer to fix selfcrosses
shapelyGeometry = shapelyGeometry.buffer(0, 1)
shapelyGeometry = self.applyFilters(shapelyGeometry)
if shapelyGeometry:
name = feature.GetFieldAsString(sourceConfig.get('country_name_index')).decode(sourceConfig.get('input_file_encoding'))
code = codes[name]
self.features[code] = {"geometry": shapelyGeometry, "name": name, "code": code}
else:
raise Exception, "Wrong geometry type: "+geometryType
def convert(self, outputFile):
self.loadData()
codes = self.features.keys()
self.map.insets = []
envelope = []
for inset in self.insets:
insetBbox = self.renderMapInset(inset['codes'], inset['left'], inset['top'], inset['width'])
insetHeight = (insetBbox[3] - insetBbox[1]) * (inset['width'] / (insetBbox[2] - insetBbox[0]))
self.map.insets.append({
"bbox": [{"x": insetBbox[0], "y": -insetBbox[3]}, {"x": insetBbox[2], "y": -insetBbox[1]}],
"left": inset['left'],
"top": inset['top'],
"width": inset['width'],
"height": insetHeight
})
envelope.append(
shapely.geometry.box(
inset['left'], inset['top'], inset['left'] + inset['width'], inset['top'] + insetHeight
)
)
for code in inset['codes']:
codes.remove(code)
insetBbox = self.renderMapInset(codes, 0, 0, self.width)
insetHeight = (insetBbox[3] - insetBbox[1]) * (self.width / (insetBbox[2] - insetBbox[0]))
envelope.append( shapely.geometry.box( 0, 0, self.width, insetHeight ) )
mapBbox = shapely.geometry.MultiPolygon( envelope ).bounds
self.map.width = mapBbox[2] - mapBbox[0]
self.map.height = mapBbox[3] - mapBbox[1]
self.map.insets.append({
"bbox": [{"x": insetBbox[0], "y": -insetBbox[3]}, {"x": insetBbox[2], "y": -insetBbox[1]}],
"left": 0,
"top": 0,
"width": self.width,
"height": insetHeight
})
self.map.projection = {"type": self.projection, "centralMeridian": float(self.longitude0)}
open(outputFile, 'w').write( self.map.getJSCode() )
def renderMapInset(self, codes, left, top, width):
envelope = []
for code in codes:
envelope.append( self.features[code]['geometry'].envelope )
bbox = shapely.geometry.MultiPolygon( envelope ).bounds
scale = (bbox[2]-bbox[0]) / width
# generate SVG paths
for code in codes:
feature = self.features[code]
geometry = feature['geometry']
if self.buffer_distance:
geometry = geometry.buffer(self.buffer_distance*scale, 1)
if geometry.is_empty:
continue
if self.simplify_tolerance:
geometry = geometry.simplify(self.simplify_tolerance, preserve_topology=True)
if isinstance(geometry, shapely.geometry.multipolygon.MultiPolygon):
polygons = geometry.geoms
else:
polygons = [geometry]
path = ''
for polygon in polygons:
rings = []
rings.append(polygon.exterior)
rings.extend(polygon.interiors)
for ring in rings:
for pointIndex in range( len(ring.coords) ):
point = ring.coords[pointIndex]
if pointIndex == 0:
path += 'M'+str( round( (point[0]-bbox[0]) / scale + left, self.precision) )
path += ','+str( round( (bbox[3] - point[1]) / scale + top, self.precision) )
else:
path += 'l' + str( round(point[0]/scale - ring.coords[pointIndex-1][0]/scale, self.precision) )
path += ',' + str( round(ring.coords[pointIndex-1][1]/scale - point[1]/scale, self.precision) )
path += 'Z'
self.map.addPath(path, feature['code'], feature['name'])
return bbox
def applyFilters(self, geometry):
if self.viewportRect:
geometry = self.filterByViewport(geometry)
if not geometry:
return False
if self.minimal_area:
geometry = self.filterByMinimalArea(geometry)
if not geometry:
return False
return geometry
def filterByViewport(self, geometry):
try:
return geometry.intersection(self.viewportRect)
except shapely.geos.TopologicalError:
return False
def filterByMinimalArea(self, geometry):
if isinstance(geometry, shapely.geometry.multipolygon.MultiPolygon):
polygons = geometry.geoms
else:
polygons = [geometry]
polygons = filter(lambda p: p.area > self.minimal_area, polygons)
return shapely.geometry.multipolygon.MultiPolygon(polygons)
parser = argparse.ArgumentParser(conflict_handler='resolve')
parser.add_argument('input_file')
parser.add_argument('output_file')
parser.add_argument('--country_code_index', type=int)
parser.add_argument('--country_name_index', type=int)
parser.add_argument('--codes_file', type=str)
parser.add_argument('--where', type=str)
parser.add_argument('--width', type=float)
parser.add_argument('--insets', type=str)
parser.add_argument('--minimal_area', type=float)
parser.add_argument('--buffer_distance', type=float)
parser.add_argument('--simplify_tolerance', type=float)
parser.add_argument('--viewport', type=str)
parser.add_argument('--longitude0', type=str)
parser.add_argument('--projection', type=str)
parser.add_argument('--name', type=str)
parser.add_argument('--language', type=str)
parser.add_argument('--input_file_encoding', type=str)
parser.add_argument('--precision', type=int)
args = vars(parser.parse_args())
default_args = {
'buffer_distance': -0.4,
'longitude0': '0',
'projection': 'mill',
'name': 'world',
'language': 'en',
'precision': 2,
'insets': ''
}
if args['input_file'][-4:] == 'json':
args.update( json.loads( open(args['input_file'], 'r').read() ) )
for key in default_args:
if default_args.get(key) and args.get(key) is None:
args[key] = default_args[key]
converter = Converter(args)
converter.convert(args['output_file'])

View File

@@ -0,0 +1,205 @@
import argparse
import sys
import os
from osgeo import ogr
from osgeo import osr
import anyjson
import shapely.geometry
import shapely.ops
import codecs
import time
format = '%.8f %.8f'
tolerance = 0.01
infile = '/Users/kirilllebedev/Maps/50m-admin-0-countries/ne_50m_admin_0_countries.shp'
outfile = 'map.shp'
# Open the datasource to operate on.
in_ds = ogr.Open( infile, update = 0 )
in_layer = in_ds.GetLayer( 0 )
in_defn = in_layer.GetLayerDefn()
# Create output file with similar information.
shp_driver = ogr.GetDriverByName( 'ESRI Shapefile' )
if os.path.exists('map.shp'):
shp_driver.DeleteDataSource( outfile )
shp_ds = shp_driver.CreateDataSource( outfile )
shp_layer = shp_ds.CreateLayer( in_defn.GetName(),
geom_type = in_defn.GetGeomType(),
srs = in_layer.GetSpatialRef() )
in_field_count = in_defn.GetFieldCount()
for fld_index in range(in_field_count):
src_fd = in_defn.GetFieldDefn( fld_index )
fd = ogr.FieldDefn( src_fd.GetName(), src_fd.GetType() )
fd.SetWidth( src_fd.GetWidth() )
fd.SetPrecision( src_fd.GetPrecision() )
shp_layer.CreateField( fd )
# Load geometries
geometries = []
for feature in in_layer:
geometry = feature.GetGeometryRef()
geometryType = geometry.GetGeometryType()
if geometryType == ogr.wkbPolygon or geometryType == ogr.wkbMultiPolygon:
shapelyGeometry = shapely.wkb.loads( geometry.ExportToWkb() )
#if not shapelyGeometry.is_valid:
#buffer to fix selfcrosses
#shapelyGeometry = shapelyGeometry.buffer(0)
if shapelyGeometry:
geometries.append(shapelyGeometry)
in_layer.ResetReading()
start = int(round(time.time() * 1000))
# Simplification
points = []
connections = {}
counter = 0
for geom in geometries:
counter += 1
polygons = []
if isinstance(geom, shapely.geometry.Polygon):
polygons.append(geom)
else:
for polygon in geom:
polygons.append(polygon)
for polygon in polygons:
if polygon.area > 0:
lines = []
lines.append(polygon.exterior)
for line in polygon.interiors:
lines.append(line)
for line in lines:
for i in range(len(line.coords)-1):
indexFrom = i
indexTo = i+1
pointFrom = format % line.coords[indexFrom]
pointTo = format % line.coords[indexTo]
if pointFrom == pointTo:
continue
if not (pointFrom in connections):
connections[pointFrom] = {}
connections[pointFrom][pointTo] = 1
if not (pointTo in connections):
connections[pointTo] = {}
connections[pointTo][pointFrom] = 1
print int(round(time.time() * 1000)) - start
simplifiedLines = {}
pivotPoints = {}
def simplifyRing(ring):
coords = list(ring.coords)[0:-1]
simpleCoords = []
isPivot = False
pointIndex = 0
while not isPivot and pointIndex < len(coords):
pointStr = format % coords[pointIndex]
pointIndex += 1
isPivot = ((len(connections[pointStr]) > 2) or (pointStr in pivotPoints))
pointIndex = pointIndex - 1
if not isPivot:
simpleRing = shapely.geometry.LineString(coords).simplify(tolerance)
if len(simpleRing.coords) <= 2:
return None
else:
pivotPoints[format % coords[0]] = True
pivotPoints[format % coords[-1]] = True
simpleLineKey = format % coords[0]+':'+format % coords[1]+':'+format % coords[-1]
simplifiedLines[simpleLineKey] = simpleRing.coords
return simpleRing
else:
points = coords[pointIndex:len(coords)]
points.extend(coords[0:pointIndex+1])
iFrom = 0
for i in range(1, len(points)):
pointStr = format % points[i]
if ((len(connections[pointStr]) > 2) or (pointStr in pivotPoints)):
line = points[iFrom:i+1]
lineKey = format % line[-1]+':'+format % line[-2]+':'+format % line[0]
if lineKey in simplifiedLines:
simpleLine = simplifiedLines[lineKey]
simpleLine = list(reversed(simpleLine))
else:
simpleLine = shapely.geometry.LineString(line).simplify(tolerance).coords
lineKey = format % line[0]+':'+format % line[1]+':'+format % line[-1]
simplifiedLines[lineKey] = simpleLine
simpleCoords.extend( simpleLine[0:-1] )
iFrom = i
if len(simpleCoords) <= 2:
return None
else:
return shapely.geometry.LineString(simpleCoords)
def simplifyPolygon(polygon):
simpleExtRing = simplifyRing(polygon.exterior)
if simpleExtRing is None:
return None
simpleIntRings = []
for ring in polygon.interiors:
simpleIntRing = simplifyRing(ring)
if simpleIntRing is not None:
simpleIntRings.append(simpleIntRing)
return shapely.geometry.Polygon(simpleExtRing, simpleIntRings)
results = []
for geom in geometries:
polygons = []
simplePolygons = []
if isinstance(geom, shapely.geometry.Polygon):
polygons.append(geom)
else:
for polygon in geom:
polygons.append(polygon)
for polygon in polygons:
simplePolygon = simplifyPolygon(polygon)
if not (simplePolygon is None or simplePolygon._geom is None):
simplePolygons.append(simplePolygon)
if len(simplePolygons) > 0:
results.append(shapely.geometry.MultiPolygon(simplePolygons))
else:
results.append(None)
# Process all features in input layer.
in_feat = in_layer.GetNextFeature()
counter = 0
while in_feat is not None:
if results[counter] is not None:
out_feat = ogr.Feature( feature_def = shp_layer.GetLayerDefn() )
out_feat.SetFrom( in_feat )
out_feat.SetGeometryDirectly(
ogr.CreateGeometryFromWkb(
shapely.wkb.dumps(
results[counter]
)
)
)
shp_layer.CreateFeature( out_feat )
out_feat.Destroy()
else:
print 'geometry is too small: '+in_feat.GetField(16)
in_feat.Destroy()
in_feat = in_layer.GetNextFeature()
counter += 1
# Cleanup
shp_ds.Destroy()
in_ds.Destroy()
print int(round(time.time() * 1000)) - start

View File

@@ -0,0 +1,37 @@
.jvectormap-label {
position: absolute;
display: none;
border: solid 1px #CDCDCD;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
background: #292929;
color: white;
font-family: sans-serif, Verdana;
font-size: smaller;
padding: 3px;
}
.jvectormap-zoomin, .jvectormap-zoomout {
position: absolute;
left: 10px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
background: #292929;
padding: 3px;
color: white;
width: 10px;
height: 10px;
cursor: pointer;
line-height: 10px;
text-align: center;
}
.jvectormap-zoomin {
top: 10px;
}
.jvectormap-zoomout {
top: 30px;
}

View File

@@ -0,0 +1,45 @@
/**
* jVectorMap version 1.2.2
*
* Copyright 2011-2013, Kirill Lebedev
* Licensed under the MIT license.
*
*/
(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,
event,
map = this.children('.jvectormap-container').data('mapObject');
if (options === 'addMap') {
jvm.WorldMap.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.WorldMap(options);
}
return this;
};
})( jQuery );

View File

@@ -0,0 +1,84 @@
/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
* Licensed under the MIT License (LICENSE.txt).
*
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
* Thanks to: Seamus Leahy for adding deltaX and deltaY
*
* Version: 3.0.6
*
* Requires: 1.2.2+
*/
(function($) {
var types = ['DOMMouseScroll', 'mousewheel'];
if ($.event.fixHooks) {
for ( var i=types.length; i; ) {
$.event.fixHooks[ types[--i] ] = $.event.mouseHooks;
}
}
$.event.special.mousewheel = {
setup: function() {
if ( this.addEventListener ) {
for ( var i=types.length; i; ) {
this.addEventListener( types[--i], handler, false );
}
} else {
this.onmousewheel = handler;
}
},
teardown: function() {
if ( this.removeEventListener ) {
for ( var i=types.length; i; ) {
this.removeEventListener( types[--i], handler, false );
}
} else {
this.onmousewheel = null;
}
}
};
$.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, returnValue = true, deltaX = 0, deltaY = 0;
event = $.event.fix(orgEvent);
event.type = "mousewheel";
// Old school scrollwheel delta
if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; }
if ( orgEvent.detail ) { delta = -orgEvent.detail/3; }
// New school multidimensional scroll (touchpads) deltas
deltaY = delta;
// Gecko
if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
deltaY = 0;
deltaX = -1*delta;
}
// Webkit
if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
// Add event and delta to the front of the arguments
args.unshift(event, delta, deltaX, deltaY);
return ($.event.dispatch || $.event.handle).apply(this, args);
}
})(jQuery);

View File

@@ -0,0 +1,30 @@
{
"name": "jvectormap",
"title": "jVectorMap",
"description": "jQuery plugin for embedding vector maps with reach API and methods for data visualization to the web-pages.",
"keywords": [
"map",
"vector",
"world",
"usa",
"choropleth"
],
"version": "1.2.2",
"author": {
"name": "Kirill Lebedev",
"email" : "echo.bjornd@gmail.com"
},
"licenses": [
{
"type": "MIT",
"url": "https://github.com/jquery/jquery-color/blob/2.1.2/MIT-LICENSE.txt"
}
],
"bugs": "https://github.com/bjornd/jvectormap/issues",
"homepage": "http://jvectormap.com",
"docs": "http://jvectormap.com/documentation/",
"download": "http://jvectormap.com/download/",
"dependencies": {
"jquery": ">=1.5"
}
}

View File

@@ -0,0 +1,67 @@
/**
* 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;
};
/**
* 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;
};

View File

@@ -0,0 +1,73 @@
/**
* 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();
};

View File

@@ -0,0 +1,85 @@
/**
* 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.isHovered = false;
this.isSelected = false;
this.updateStyle();
};
/**
* Set hovered state to the element. Hovered state means mouse cursor is over element. Styles will be updates respectively.
* @param {Boolean} isHovered <code>true</code> to make element hovered, <code>false</code> otherwise.
*/
jvm.AbstractShapeElement.prototype.setHovered = function(isHovered){
if (this.isHovered !== isHovered) {
this.isHovered = isHovered;
this.updateStyle();
}
};
/**
* Set selected state to the element. Styles will be updates respectively.
* @param {Boolean} isSelected <code>true</code> to make element selected, <code>false</code> otherwise.
*/
jvm.AbstractShapeElement.prototype.setSelected = function(isSelected){
if (this.isSelected !== isSelected) {
this.isSelected = isSelected;
this.updateStyle();
jvm.$(this.node).trigger('selected', [isSelected]);
}
};
/**
* 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];
}
}
}

View File

@@ -0,0 +1,44 @@
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)];
};

View File

@@ -0,0 +1,139 @@
/**
* 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</code>, <code>stroke</code>, <code>fill-opacity</code>, <code>stroke-opacity</code> for markers and regions and <code>r</code> (radius) for markers only.
* @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']</code>
* @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'</code> or <code>'polynomial'</code>, while <code>'linear'</code> is used by default. The function provided takes value from the data set as an input and returns corresponding value from the scale.
* @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) {
var scaleConstructor;
params = params || {};
params.attribute = params.attribute || 'fill';
this.elements = elements;
this.params = params;
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);
};
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.MIN_VALUE,
min = Number.MAX_VALUE,
val,
cc,
attrs = {};
if (!(this.scale instanceof jvm.OrdinalScale) && !(this.scale instanceof jvm.SimpleScale)) {
if (!this.params.min || !this.params.max) {
for (cc in values) {
val = parseFloat(values[cc]);
if (val > max) max = values[cc];
if (val < min) min = val;
}
if (!this.params.min) {
this.scale.setMin(min);
}
if (!this.params.max) {
this.scale.setMax(max);
}
this.params.min = min;
this.params.max = max;
}
for (cc in values) {
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.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);
}
}
};

View File

@@ -0,0 +1,99 @@
/**
* @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;
}
};
jvm.$ = jQuery;

View File

@@ -0,0 +1,147 @@
jvm.NumericScale = function(scale, normalizeFunction, minValue, maxValue) {
this.scale = [];
normalizeFunction = normalizeFunction || 'linear';
if (scale) this.setScale(scale);
if (normalizeFunction) this.setNormalizeFunction(normalizeFunction);
if (minValue) this.setMin(minValue);
if (maxValue) this.setMax(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;
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);
}
};

View File

@@ -0,0 +1,7 @@
jvm.OrdinalScale = function(scale){
this.scale = scale;
};
jvm.OrdinalScale.prototype.getValue = function(value){
return this.scale[value];
};

View File

@@ -0,0 +1,181 @@
/**
* 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
};
}
};

View File

@@ -0,0 +1,7 @@
jvm.SimpleScale = function(scale){
this.scale = scale;
};
jvm.SimpleScale.prototype.getValue = function(value){
return value;
};

View File

@@ -0,0 +1,22 @@
jvm.SVGCanvasElement = function(container, width, height){
this.classPrefix = 'SVG';
jvm.SVGCanvasElement.parentClass.call(this, 'svg');
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+')');
};

View File

@@ -0,0 +1,5 @@
jvm.SVGCircleElement = function(config, style){
jvm.SVGCircleElement.parentClass.call(this, 'circle', config, style);
};
jvm.inherits(jvm.SVGCircleElement, jvm.SVGShapeElement);

View File

@@ -0,0 +1,48 @@
/**
* 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();
};

View File

@@ -0,0 +1,9 @@
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 );
};

View File

@@ -0,0 +1,6 @@
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);

View File

@@ -0,0 +1,7 @@
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);

View File

@@ -0,0 +1,16 @@
/**
* 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);
}
return this.impl;
};

View File

@@ -0,0 +1,45 @@
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;
};

View File

@@ -0,0 +1,26 @@
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);
}
};

View File

@@ -0,0 +1,106 @@
/**
* 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
};
};

View File

@@ -0,0 +1,13 @@
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 );
};

View File

@@ -0,0 +1,111 @@
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 result = '',
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(',');
break;
case 'M':
cx = coords[0];
cy = coords[1];
return 'm'+coords.join(',');
break;
case 'l':
cx += coords[0];
cy += coords[1];
return 'r'+coords.join(',');
break;
case 'L':
cx = coords[0];
cy = coords[1];
return 'l'+coords.join(',');
break;
case 'h':
cx += coords[0];
return 'r'+coords[0]+',0';
break;
case 'H':
cx = coords[0];
return 'l'+cx+','+cy;
break;
case 'v':
cy += coords[0];
return 'r0,'+coords[0];
break;
case 'V':
cy = coords[0];
return 'l'+cx+','+cy;
break;
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(',');
break;
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(',');
break;
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(',');
break;
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(',');
break;
}
return '';
}).replace(/z/g, 'e');
};

View File

@@ -0,0 +1,49 @@
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);
}
};

View File

@@ -0,0 +1,987 @@
/**
* 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</code> where <code>territory</code> is a unique code or name of the territory which the map represents (ISO 3166 alpha 2 standard is used where possible), <code>proj</code> is a name of projection used to generate representation of the map on the plane (projections are named according to the conventions of proj4 utility) and <code>lang</code> is a code of the language, used for the names of regions.
* @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</code>.
* @param {Number} params.zoomMax Indicates the maximum zoom ratio which could be reached zooming the map. Default value is <code>8</code>.
* @param {Number} params.zoomMin Indicates the minimum zoom ratio which could be reached zooming the map. Default value is <code>1</code>.
* @param {Number} params.zoomStep Indicates the multiplier used to zoom map with +/- buttons. Default value is <code>1.6</code>.
* @param {Boolean} params.regionsSelectable When set to true regions of the map could be selected. Default value is <code>false</code>.
* @param {Boolean} params.regionsSelectableOne Allow only one region to be selected at the moment. Default value is <code>false</code>.
* @param {Boolean} params.markersSelectable When set to true markers on the map could be selected. Default value is <code>false</code>.
* @param {Boolean} params.markersSelectableOne Allow only one marker to be selected at the moment. Default value is <code>false</code>.
* @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
},
selected: {
fill: 'yellow'
},
selectedHover: {
}
}</pre>
* @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
},
selected: {
fill: 'blue'
},
selectedHover: {
}
}</pre>
* @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</code> (array of two numeric values), <code>name</code> (string which will be show on marker's label) and any marker styles.
* @param {Object} params.series Object with two keys: <code>markers</code> and <code>regions</code>. Each of which is an array of series configs to be applied to the respective map elements. See <a href="jvm.DataSeries.html">DataSeries</a> description for a list of parameters available.
* @param {Object|String} params.focusOn This parameter sets the initial position and scale of the map viewport. It could be expressed as a string representing region which should be in focus or an object representing coordinates and scale to set. For example to focus on the center of the map at the double scale you can provide the following value:
<pre>{
x: 0.5,
y: 0.5,
scale: 2
}</pre>
* @param {Array|Object|String} params.selectedRegions Set initially selected regions.
* @param {Array|Object|String} params.selectedMarkers Set initially selected markers.
* @param {Function} params.onRegionLabelShow <code>(Event e, Object label, String code)</code> Will be called right before the region label is going to be shown.
* @param {Function} params.onRegionOver <code>(Event e, String code)</code> Will be called on region mouse over event.
* @param {Function} params.onRegionOut <code>(Event e, String code)</code> Will be called on region mouse out event.
* @param {Function} params.onRegionClick <code>(Event e, String code)</code> Will be called on region click event.
* @param {Function} params.onRegionSelected <code>(Event e, String code, Boolean isSelected, Array selectedRegions)</code> Will be called when region is (de)selected. <code>isSelected</code> parameter of the callback indicates whether region is selected or not. <code>selectedRegions</code> contains codes of all currently selected regions.
* @param {Function} params.onMarkerLabelShow <code>(Event e, Object label, String code)</code> Will be called right before the marker label is going to be shown.
* @param {Function} params.onMarkerOver <code>(Event e, String code)</code> Will be called on marker mouse over event.
* @param {Function} params.onMarkerOut <code>(Event e, String code)</code> Will be called on marker mouse out event.
* @param {Function} params.onMarkerClick <code>(Event e, String code)</code> Will be called on marker click event.
* @param {Function} params.onMarkerSelected <code>(Event e, String code, Boolean isSelected, Array selectedMarkers)</code> Will be called when marker is (de)selected. <code>isSelected</code> parameter of the callback indicates whether marker is selected or not. <code>selectedMarkers</code> contains codes of all currently selected markers.
* @param {Function} params.onViewportChange <code>(Event e, Number scale)</code> Triggered when the map's viewport is changed (map was panned or zoomed).
*/
jvm.WorldMap = function(params) {
var map = this,
e;
this.params = jvm.$.extend(true, {}, jvm.WorldMap.defaultParams, params);
if (!jvm.WorldMap.maps[this.params.map]) {
throw new Error('Attempt to use map which was not loaded: '+this.params.map);
}
this.mapData = jvm.WorldMap.maps[this.params.map];
this.markers = {};
this.regions = {};
this.regionsColors = {};
this.regionsData = {};
this.container = jvm.$('<div>').css({width: '100%', height: '100%'}).addClass('jvectormap-container');
this.params.container.append( this.container );
this.container.data('mapObject', this);
this.container.css({
position: 'relative',
overflow: 'hidden'
});
this.defaultWidth = this.mapData.width;
this.defaultHeight = this.mapData.height;
this.setBackgroundColor(this.params.backgroundColor);
this.onResize = function(){
map.setSize();
}
jvm.$(window).resize(this.onResize);
for (e in jvm.WorldMap.apiEvents) {
if (this.params[e]) {
this.container.bind(jvm.WorldMap.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();
}
} else {
this.bindContainerEvents();
}
this.bindElementEvents();
this.createLabel();
if (this.params.zoomButtons) {
this.bindZoomButtons();
}
this.createRegions();
this.createMarkers(this.params.markers || {});
this.setSize();
if (this.params.focusOn) {
if (typeof this.params.focusOn === 'object') {
this.setFocus.call(this, this.params.focusOn.scale, this.params.focusOn.x, this.params.focusOn.y);
} else {
this.setFocus.call(this, this.params.focusOn);
}
}
if (this.params.selectedRegions) {
this.setSelectedRegions(this.params.selectedRegions);
}
if (this.params.selectedMarkers) {
this.setSelectedMarkers(this.params.selectedMarkers);
}
if (this.params.series) {
this.createSeries();
}
};
jvm.WorldMap.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.
*/
setSize: 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.container.trigger('viewportChange', [this.scale/this.baseScale, this.transX, this.transY]);
},
bindContainerEvents: function(){
var mouseDown = false,
oldPageX,
oldPageY,
map = this;
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;
});
jvm.$('body').mouseup(function(){
mouseDown = false;
});
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.3, deltaY);
map.label.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.label.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.label.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;
});
/* Can not use common class selectors here because of the bug in jQuery
SVG handling, use with caution. */
this.container.delegate("[class~='jvectormap-element']", 'mouseover mouseout', function(e){
var path = this,
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'),
element = type == 'region' ? map.regions[code].element : map.markers[code].element,
labelText = type == 'region' ? map.mapData.paths[code].name : (map.markers[code].config.name || ''),
labelShowEvent = jvm.$.Event(type+'LabelShow.jvectormap'),
overEvent = jvm.$.Event(type+'Over.jvectormap');
if (e.type == 'mouseover') {
map.container.trigger(overEvent, [code]);
if (!overEvent.isDefaultPrevented()) {
element.setHovered(true);
}
map.label.text(labelText);
map.container.trigger(labelShowEvent, [map.label, code]);
if (!labelShowEvent.isDefaultPrevented()) {
map.label.show();
map.labelWidth = map.label.width();
map.labelHeight = map.label.height();
}
} else {
element.setHovered(false);
map.label.hide();
map.container.trigger(type+'Out.jvectormap', [code]);
}
});
/* Can not use common class selectors here because of the bug in jQuery
SVG handling, use with caution. */
this.container.delegate("[class~='jvectormap-element']", 'mousedown', function(e){
mouseMoved = false;
});
/* Can not use common class selectors here because of the bug in jQuery
SVG handling, use with caution. */
this.container.delegate("[class~='jvectormap-element']", 'mouseup', function(e){
var path = this,
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('&#x2212;').appendTo(this.container);
this.container.find('.jvectormap-zoomin').click(function(){
map.setScale(map.scale * map.params.zoomStep, map.width / 2, map.height / 2);
});
this.container.find('.jvectormap-zoomout').click(function(){
map.setScale(map.scale / map.params.zoomStep, map.width / 2, map.height / 2);
});
},
createLabel: function(){
var map = this;
this.label = jvm.$('<div/>').addClass('jvectormap-label').appendTo(jvm.$('body'));
this.container.mousemove(function(e){
var left = e.pageX-15-map.labelWidth,
top = e.pageY-15-map.labelHeight;
if (left < 5) {
left = e.pageX + 15;
}
if (top < 5) {
top = e.pageY + 15;
}
if (map.label.is(':visible')) {
map.label.css({
left: left,
top: top
})
}
});
},
setScale: function(scale, anchorX, anchorY, isCentered) {
var zoomStep,
viewportChangeEvent = jvm.$.Event('zoom.jvectormap');
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) {
this.transX = anchorX + this.defaultWidth * (this.width / (this.defaultWidth * scale)) / 2;
this.transY = anchorY + this.defaultHeight * (this.height / (this.defaultHeight * scale)) / 2;
} else {
this.transX -= (zoomStep - 1) / scale * anchorX;
this.transY -= (zoomStep - 1) / scale * anchorY;
}
}
this.scale = scale;
this.applyTransform();
this.container.trigger(viewportChangeEvent, [scale/this.baseScale]);
},
/**
* 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 {Number|String|Array} scale|regionCode|regionCodes If the first parameter of this method is a string or array of strings and there are regions with the these codes, the viewport will be set to show all these regions. Otherwise if the first parameter is a number, the viewport will be set to show the map with provided scale.
* @param {Number} centerX Number from 0 to 1 specifying the horizontal coordinate of the central point of the viewport.
* @param {Number} centerY Number from 0 to 1 specifying the vertical coordinate of the central point of the viewport.
*/
setFocus: function(scale, centerX, centerY){
var bbox,
itemBbox,
newBbox,
codes,
i;
if (jvm.$.isArray(scale) || this.regions[scale]) {
if (jvm.$.isArray(scale)) {
codes = scale;
} else {
codes = [scale]
}
for (i = 0; i < codes.length; i++) {
if (this.regions[codes[i]]) {
itemBbox = this.regions[codes[i]].element.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;
}
}
}
}
this.setScale(
Math.min(this.width / bbox.width, this.height / bbox.height),
- (bbox.x + bbox.width / 2),
- (bbox.y + bbox.height / 2),
true
);
} else {
scale = scale * this.baseScale;
this.setScale(scale, - centerX * this.defaultWidth, - centerY * this.defaultHeight, true);
}
},
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</code> or <code>Array</code> the region(s) with the corresponding code(s) will be selected. If <code>Object</code> was provided its keys are codes of regions, state of which should be changed. Selected state will be set if value is true, removed otherwise.
*/
setSelectedRegions: function(keys){
this.setSelected('regions', keys);
},
/**
* Set or remove selected state for the markers.
* @param {String|Array|Object} keys If <code>String</code> or <code>Array</code> the marker(s) with the corresponding code(s) will be selected. If <code>Object</code> was provided its keys are codes of markers, state of which should be changed. Selected state will be set if value is true, removed otherwise.
*/
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 WorldMap. Useful when instantiated as a jQuery plug-in.
* @returns {WorldMap}
*/
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;
for (key in this.mapData.paths) {
region = this.canvas.addPath({
d: this.mapData.paths[key].path,
"data-code": key
}, jvm.$.extend(true, {}, this.params.regionStyle));
jvm.$(region.node).bind('selected', function(e, isSelected){
map.container.trigger('regionSelected.jvectormap', [jvm.$(this).attr('data-code'), isSelected, map.getSelectedRegions()]);
});
region.addClass('jvectormap-region jvectormap-element');
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();
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 = this.canvas.addCircle({
"data-index": i,
cx: point.x,
cy: point.y
}, jvm.$.extend(true, {}, this.params.markerStyle, {initial: markerConfig.style || {}}), this.markersGroup);
marker.addClass('jvectormap-marker jvectormap-element');
jvm.$(marker.node).bind('selected', function(e, isSelected){
map.container.trigger('markerSelected.jvectormap', [jvm.$(this).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});
}
}
},
getMarkerPosition: function(markerConfig) {
if (jvm.WorldMap.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 = {};
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.WorldMap.maps[this.params.map].projection,
centralMeridian = proj.centralMeridian,
width = this.width - this.baseTransX * 2 * this.baseScale,
height = this.height - this.baseTransY * 2 * this.baseScale,
inset,
bbox,
scaleFactor = this.scale / this.baseScale;
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.WorldMap.maps[this.params.map].projection,
centralMeridian = proj.centralMeridian,
insets = jvm.WorldMap.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.WorldMap.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]
);
}
}
},
/**
* Gracefully remove the map and and all its accessories, unbind event handlers.
*/
remove: function(){
this.label.remove();
this.container.remove();
jvm.$(window).unbind('resize', this.onResize);
}
};
jvm.WorldMap.maps = {};
jvm.WorldMap.defaultParams = {
map: 'world_mill_en',
backgroundColor: '#505050',
zoomButtons: true,
zoomOnScroll: true,
zoomMax: 8,
zoomMin: 1,
zoomStep: 1.6,
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
},
selected: {
fill: 'yellow'
},
selectedHover: {
}
},
markerStyle: {
initial: {
fill: 'grey',
stroke: '#505050',
"fill-opacity": 1,
"stroke-width": 1,
"stroke-opacity": 1,
r: 5
},
hover: {
stroke: 'black',
"stroke-width": 2
},
selected: {
fill: 'blue'
},
selectedHover: {
}
}
};
jvm.WorldMap.apiEvents = {
onRegionLabelShow: 'regionLabelShow',
onRegionOver: 'regionOver',
onRegionOut: 'regionOut',
onRegionClick: 'regionClick',
onRegionSelected: 'regionSelected',
onMarkerLabelShow: 'markerLabelShow',
onMarkerOver: 'markerOver',
onMarkerOut: 'markerOut',
onMarkerClick: 'markerClick',
onMarkerSelected: 'markerSelected',
onViewportChange: 'viewportChange'
};

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>jVectorMap demo</title>
<link rel="stylesheet" media="all" href="../jquery-jvectormap.css"/>
<script src="assets/jquery-1.8.2.js"></script>
<script src="../jquery-jvectormap.min.js"></script>
<script src="assets/jquery-jvectormap-world-mill-en.js"></script>
<script>
$(function(){
$('#map').vectorMap({
map: 'world_mill_en'
});
})
</script>
</head>
<body>
<div id="map" style="width: 600px; height: 400px"></div>
</body>
</html>

View File

@@ -0,0 +1,55 @@
<!DOCTYPE html>
<html>
<head>
<title>jVectorMap demo</title>
<link rel="stylesheet" media="all" href="../jquery-jvectormap.css"/>
<script src="assets/jquery-1.8.2.js"></script>
<script src="../jquery-jvectormap.js"></script>
<script src="../jquery-mousewheel.js"></script>
<script src="../lib/jvectormap.js"></script>
<script src="../lib/abstract-element.js"></script>
<script src="../lib/abstract-canvas-element.js"></script>
<script src="../lib/abstract-shape-element.js"></script>
<script src="../lib/svg-element.js"></script>
<script src="../lib/svg-group-element.js"></script>
<script src="../lib/svg-canvas-element.js"></script>
<script src="../lib/svg-shape-element.js"></script>
<script src="../lib/svg-path-element.js"></script>
<script src="../lib/svg-circle-element.js"></script>
<script src="../lib/vml-element.js"></script>
<script src="../lib/vml-group-element.js"></script>
<script src="../lib/vml-canvas-element.js"></script>
<script src="../lib/vml-shape-element.js"></script>
<script src="../lib/vml-path-element.js"></script>
<script src="../lib/vml-circle-element.js"></script>
<script src="../lib/vector-canvas.js"></script>
<script src="../lib/simple-scale.js"></script>
<script src="../lib/numeric-scale.js"></script>
<script src="../lib/ordinal-scale.js"></script>
<script src="../lib/color-scale.js"></script>
<script src="../lib/data-series.js"></script>
<script src="../lib/proj.js"></script>
<script src="../lib/world-map.js"></script>
<script src="assets/jquery-jvectormap-map.js"></script>
<script>
$(function(){
var map = $('#map1').vectorMap({
map: 'map',
markers: [
{coords: [100, 100], name: 'Marker 1', style: {fill: 'yellow'}},
{coords: [200, 200], name: 'Marker 2', style: {fill: 'yellow'}},
]
});
})
</script>
</head>
<body>
<div id="map1" style="width: 600px; height: 600px"></div>
</body>
</html>

View File

@@ -0,0 +1,262 @@
<!DOCTYPE html>
<html>
<head>
<title>jVectorMap demo</title>
<link rel="stylesheet" media="all" href="../jquery-jvectormap.css"/>
<script src="assets/jquery-1.8.2.js"></script>
<script src="../jquery-jvectormap.js"></script>
<script src="../jquery-mousewheel.js"></script>
<script src="../lib/jvectormap.js"></script>
<script src="../lib/abstract-element.js"></script>
<script src="../lib/abstract-canvas-element.js"></script>
<script src="../lib/abstract-shape-element.js"></script>
<script src="../lib/svg-element.js"></script>
<script src="../lib/svg-group-element.js"></script>
<script src="../lib/svg-canvas-element.js"></script>
<script src="../lib/svg-shape-element.js"></script>
<script src="../lib/svg-path-element.js"></script>
<script src="../lib/svg-circle-element.js"></script>
<script src="../lib/vml-element.js"></script>
<script src="../lib/vml-group-element.js"></script>
<script src="../lib/vml-canvas-element.js"></script>
<script src="../lib/vml-shape-element.js"></script>
<script src="../lib/vml-path-element.js"></script>
<script src="../lib/vml-circle-element.js"></script>
<script src="../lib/vector-canvas.js"></script>
<script src="../lib/simple-scale.js"></script>
<script src="../lib/numeric-scale.js"></script>
<script src="../lib/ordinal-scale.js"></script>
<script src="../lib/color-scale.js"></script>
<script src="../lib/data-series.js"></script>
<script src="../lib/proj.js"></script>
<script src="../lib/world-map.js"></script>
<script src="assets/jquery-jvectormap-world-mill-en.js"></script>
<script>
jQuery.noConflict();
jQuery(function(){
var $ = jQuery;
$('#focus-single').click(function(){
$('#map1').vectorMap('set', 'focus', 'AU');
});
$('#focus-multiple').click(function(){
$('#map1').vectorMap('set', 'focus', ['AU', 'JP']);
});
$('#focus-init').click(function(){
$('#map1').vectorMap('set', 'focus', 1, 0, 0);
});
$('#map1').vectorMap({
map: 'world_mill_en',
focusOn: {
x: 0.5,
y: 0.5,
scale: 2
},
series: {
regions: [{
scale: ['#C8EEFF', '#0071A4'],
normalizeFunction: 'polynomial',
values: {
"AF": 16.63,
"AL": 11.58,
"DZ": 158.97,
"AO": 85.81,
"AG": 1.1,
"AR": 351.02,
"AM": 8.83,
"AU": 1219.72,
"AT": 366.26,
"AZ": 52.17,
"BS": 7.54,
"BH": 21.73,
"BD": 105.4,
"BB": 3.96,
"BY": 52.89,
"BE": 461.33,
"BZ": 1.43,
"BJ": 6.49,
"BT": 1.4,
"BO": 19.18,
"BA": 16.2,
"BW": 12.5,
"BR": 2023.53,
"BN": 11.96,
"BG": 44.84,
"BF": 8.67,
"BI": 1.47,
"KH": 11.36,
"CM": 21.88,
"CA": 1563.66,
"CV": 1.57,
"CF": 2.11,
"TD": 7.59,
"CL": 199.18,
"CN": 5745.13,
"CO": 283.11,
"KM": 0.56,
"CD": 12.6,
"CG": 11.88,
"CR": 35.02,
"CI": 22.38,
"HR": 59.92,
"CY": 22.75,
"CZ": 195.23,
"DK": 304.56,
"DJ": 1.14,
"DM": 0.38,
"DO": 50.87,
"EC": 61.49,
"EG": 216.83,
"SV": 21.8,
"GQ": 14.55,
"ER": 2.25,
"EE": 19.22,
"ET": 30.94,
"FJ": 3.15,
"FI": 231.98,
"FR": 2555.44,
"GA": 12.56,
"GM": 1.04,
"GE": 11.23,
"DE": 3305.9,
"GH": 18.06,
"GR": 305.01,
"GD": 0.65,
"GT": 40.77,
"GN": 4.34,
"GW": 0.83,
"GY": 2.2,
"HT": 6.5,
"HN": 15.34,
"HK": 226.49,
"HU": 132.28,
"IS": 12.77,
"IN": 1430.02,
"ID": 695.06,
"IR": 337.9,
"IQ": 84.14,
"IE": 204.14,
"IL": 201.25,
"IT": 2036.69,
"JM": 13.74,
"JP": 5390.9,
"JO": 27.13,
"KZ": 129.76,
"KE": 32.42,
"KI": 0.15,
"KR": 986.26,
"KW": 117.32,
"KG": 4.44,
"LA": 6.34,
"LV": 23.39,
"LB": 39.15,
"LS": 1.8,
"LR": 0.98,
"LY": 77.91,
"LT": 35.73,
"LU": 52.43,
"MK": 9.58,
"MG": 8.33,
"MW": 5.04,
"MY": 218.95,
"MV": 1.43,
"ML": 9.08,
"MT": 7.8,
"MR": 3.49,
"MU": 9.43,
"MX": 1004.04,
"MD": 5.36,
"MN": 5.81,
"ME": 3.88,
"MA": 91.7,
"MZ": 10.21,
"MM": 35.65,
"NA": 11.45,
"NP": 15.11,
"NL": 770.31,
"NZ": 138,
"NI": 6.38,
"NE": 5.6,
"NG": 206.66,
"NO": 413.51,
"OM": 53.78,
"PK": 174.79,
"PA": 27.2,
"PG": 8.81,
"PY": 17.17,
"PE": 153.55,
"PH": 189.06,
"PL": 438.88,
"PT": 223.7,
"QA": 126.52,
"RO": 158.39,
"RU": 1476.91,
"RW": 5.69,
"WS": 0.55,
"ST": 0.19,
"SA": 434.44,
"SN": 12.66,
"RS": 38.92,
"SC": 0.92,
"SL": 1.9,
"SG": 217.38,
"SK": 86.26,
"SI": 46.44,
"SB": 0.67,
"ZA": 354.41,
"ES": 1374.78,
"LK": 48.24,
"KN": 0.56,
"LC": 1,
"VC": 0.58,
"SD": 65.93,
"SR": 3.3,
"SZ": 3.17,
"SE": 444.59,
"CH": 522.44,
"SY": 59.63,
"TW": 426.98,
"TJ": 5.58,
"TZ": 22.43,
"TH": 312.61,
"TL": 0.62,
"TG": 3.07,
"TO": 0.3,
"TT": 21.2,
"TN": 43.86,
"TR": 729.05,
"TM": 0,
"UG": 17.12,
"UA": 136.56,
"AE": 239.65,
"GB": 2258.57,
"US": 14624.18,
"UY": 40.71,
"UZ": 37.72,
"VU": 0.72,
"VE": 285.21,
"VN": 101.99,
"YE": 30.02,
"ZM": 15.69,
"ZW": 5.57
}
}]
}
});
})
</script>
</head>
<body>
<div style="height: 400px"></div>
<div id="map1" style="width: 600px; height: 400px"></div>
<button id="focus-single">Focus on Australia</button>
<button id="focus-multiple">Focus on Australia and Japan</button>
<button id="focus-init">Return to the initial state</button>
</body>
</html>

View File

@@ -0,0 +1,209 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Maps</title>
<link rel="stylesheet" media="all" href="../jquery-jvectormap.css"/>
<style>
ul {
padding: 0;
list-style: none;
}
</style>
<script src="assets/jquery-1.8.2.js"></script>
<script src="../jquery-jvectormap.js"></script>
<script src="../jquery-mousewheel.js"></script>
<script src="../lib/jvectormap.js"></script>
<script src="../lib/abstract-element.js"></script>
<script src="../lib/abstract-canvas-element.js"></script>
<script src="../lib/abstract-shape-element.js"></script>
<script src="../lib/svg-element.js"></script>
<script src="../lib/svg-group-element.js"></script>
<script src="../lib/svg-canvas-element.js"></script>
<script src="../lib/svg-shape-element.js"></script>
<script src="../lib/svg-path-element.js"></script>
<script src="../lib/svg-circle-element.js"></script>
<script src="../lib/vml-element.js"></script>
<script src="../lib/vml-group-element.js"></script>
<script src="../lib/vml-canvas-element.js"></script>
<script src="../lib/vml-shape-element.js"></script>
<script src="../lib/vml-path-element.js"></script>
<script src="../lib/vml-circle-element.js"></script>
<script src="../lib/vector-canvas.js"></script>
<script src="../lib/simple-scale.js"></script>
<script src="../lib/ordinal-scale.js"></script>
<script src="../lib/numeric-scale.js"></script>
<script src="../lib/color-scale.js"></script>
<script src="../lib/data-series.js"></script>
<script src="../lib/proj.js"></script>
<script src="../lib/world-map.js"></script>
<script src="assets/jquery-jvectormap-us-aea-en.js"></script>
<script>
$(function(){
var markers = [
[61.18, -149.53],
[21.18, -157.49],
{latLng: [40.66, -73.56], name: 'New York City', style: {r: 8, fill: 'yellow'}},
{latLng: [41.52, -87.37], style: {fill: 'red', r: 10}}
],
values1 = [1, 2, 3, 4],
values2 = [1, 2, 3, 4];
var map = new jvm.WorldMap({
container: $('.map'),
map: 'us_aea_en',
markers: markers,
series: {
markers: [{
attribute: 'fill',
scale: ['#C8EEFF', '#0071A4'],
normalizeFunction: 'polynomial',
values: values1
},{
attribute: 'r',
scale: [5, 20],
normalizeFunction: 'polynomial',
values: values2
}],
regions: [{
scale: {
red: '#ff0000',
blue: '#00ff00'
},
attribute: 'fill',
normalizeFunction: 'polynomial',
values: {
"US-KS": 'red',
"US-MO": 'red',
"US-IA": 'blue',
"US-NE": 'blue'
}
},{
values: {
"US-NY": 'blue',
"US-FL": 'blue'
},
attribute: 'fill'
}]
},
regionsSelectable: true,
markersSelectable: true,
markersSelectableOne: true,
selectedRegions: JSON.parse( window.localStorage.getItem('jvectormap-selected-regions') || '[]' ),
selectedMarkers: JSON.parse( window.localStorage.getItem('jvectormap-selected-markers') || '[]' ),
onMarkerLabelShow: function(event, label, index){
label.html(label.html()+' (modified marker)');
},
onMarkerOver: function(event, index){
console.log('marker-over', index);
},
onMarkerOut: function(event, index){
console.log('marker-out', index);
},
onMarkerClick: function(event, index){
console.log('marker-click', index);
},
onMarkerSelected: function(event, index, isSelected, selectedMarkers){
console.log('marker-select', index, isSelected, selectedMarkers);
if (window.localStorage) {
window.localStorage.setItem(
'jvectormap-selected-markers',
JSON.stringify(selectedMarkers)
);
}
},
onRegionLabelShow: function(event, label, code){
label.html(label.html()+' (modified)');
},
onRegionOver: function(event, code){
console.log('region-over', code, map.getRegionName(code));
},
onRegionOut: function(event, code){
console.log('region-out', code);
},
onRegionClick: function(event, code){
console.log('region-click', code);
},
onRegionSelected: function(event, code, isSelected, selectedRegions){
console.log('region-select', code, isSelected, selectedRegions);
if (window.localStorage) {
window.localStorage.setItem(
'jvectormap-selected-regions',
JSON.stringify(selectedRegions)
);
}
},
onViewportChange: function(e, scale, transX, transY){
console.log('viewportChange', scale, transX, transY);
}
});
$('.list-markers :checkbox').change(function(){
var index = $(this).closest('li').attr('data-marker-index');
if ($(this).prop('checked')) {
map.addMarker( index, markers[index], [values1[index], values2[index]] );
} else {
map.removeMarkers( [index] );
}
});
$('.button-add-all').click(function(){
$('.list-markers :checkbox').prop('checked', true);
map.addMarkers(markers, [values1, values2]);
});
$('.button-remove-all').click(function(){
$('.list-markers :checkbox').prop('checked', false);
map.removeAllMarkers();
});
$('.button-clear-selected-regions').click(function(){
map.clearSelectedRegions();
});
$('.button-clear-selected-markers').click(function(){
map.clearSelectedMarkers();
});
$('.button-remove-map').click(function(){
map.remove();
});
$('.button-change-values').click(function(){
map.series.regions[1].clear();
map.series.regions[1].setValues({
"US-TX": "black",
"US-CA": "black"
});
});
$('.button-reset-map').click(function(){
map.reset();
});
});
</script>
</head>
<body>
<div class="map" style="width: 800px; height: 500px"></div>
<ul class="list-markers">
<li data-marker-index="0"><label><input checked type="checkbox"/> Marker 1</label></li>
<li data-marker-index="1"><label><input checked type="checkbox"/> Marker 2</label></li>
<li data-marker-index="2"><label><input checked type="checkbox"/> Marker 3</label></li>
<li data-marker-index="3"><label><input checked type="checkbox"/> Marker 4</label></li>
</ul>
<input type="button" value="Add all" class="button-add-all"/>
<input type="button" value="Remove all" class="button-remove-all"/>
&nbsp;&nbsp;&nbsp;
<input type="button" value="Clear selected regions" class="button-clear-selected-regions"/>
<input type="button" value="Clear selected markers" class="button-clear-selected-markers"/>
&nbsp;&nbsp;&nbsp;
<input type="button" value="Remove map" class="button-remove-map"/>
&nbsp;&nbsp;&nbsp;
<input type="button" value="Change values" class="button-change-values"/>
&nbsp;&nbsp;&nbsp;
<input type="button" value="Reset map" class="button-reset-map"/>
</body>
</html>

View File

@@ -0,0 +1,80 @@
<!DOCTYPE html>
<html>
<head>
<title>jVectorMap demo</title>
<link rel="stylesheet" media="all" href="../jquery-jvectormap.css"/>
<script src="assets/jquery-1.8.2.js"></script>
<script src="../jquery-jvectormap.js"></script>
<script src="../jquery-mousewheel.js"></script>
<script src="../lib/jvectormap.js"></script>
<script src="../lib/abstract-element.js"></script>
<script src="../lib/abstract-canvas-element.js"></script>
<script src="../lib/abstract-shape-element.js"></script>
<script src="../lib/svg-element.js"></script>
<script src="../lib/svg-group-element.js"></script>
<script src="../lib/svg-canvas-element.js"></script>
<script src="../lib/svg-shape-element.js"></script>
<script src="../lib/svg-path-element.js"></script>
<script src="../lib/svg-circle-element.js"></script>
<script src="../lib/vml-element.js"></script>
<script src="../lib/vml-group-element.js"></script>
<script src="../lib/vml-canvas-element.js"></script>
<script src="../lib/vml-shape-element.js"></script>
<script src="../lib/vml-path-element.js"></script>
<script src="../lib/vml-circle-element.js"></script>
<script src="../lib/vector-canvas.js"></script>
<script src="../lib/simple-scale.js"></script>
<script src="../lib/numeric-scale.js"></script>
<script src="../lib/ordinal-scale.js"></script>
<script src="../lib/color-scale.js"></script>
<script src="../lib/data-series.js"></script>
<script src="../lib/proj.js"></script>
<script src="../lib/world-map.js"></script>
<script src="assets/jquery-jvectormap-us-lcc-en.js"></script>
<script>
$(function(){
var map,
markerIndex = 0,
markersCoords = {};
map = new jvm.WorldMap({
map: 'us_lcc_en',
markerStyle: {
initial: {
fill: 'red'
}
},
container: $('#map'),
onMarkerLabelShow: function(e, label, code){
map.label.text(markersCoords[code].lat.toFixed(2)+' '+markersCoords[code].lng.toFixed(2));
},
onMarkerClick: function(e, code){
map.removeMarkers([code]);
map.label.hide();
}
});
$('#map').click(function(e){
var latLng = map.pointToLatLng(e.offsetX, e.offsetY),
targetCls = $(e.target).attr('class');
if (latLng && (!targetCls || (targetCls && $(e.target).attr('class').indexOf('jvectormap-marker') === -1))) {
markersCoords[markerIndex] = latLng;
map.addMarker(markerIndex, {latLng: [latLng.lat, latLng.lng]});
markerIndex += 1;
}
});
$('#map').bind('');
});
</script>
</head>
<body>
<div id="map" style="width: 900px; height: 600px"></div>
</body>
</html>