diff --git a/folium/element.py b/folium/element.py
index 1113989282..7a433c17e9 100644
--- a/folium/element.py
+++ b/folium/element.py
@@ -11,6 +11,7 @@
ENV = Environment(loader=PackageLoader('folium', 'templates'))
from collections import OrderedDict
import json
+import base64
from .six import urlopen
from .utilities import _camelify, _parse_size
@@ -266,7 +267,7 @@ def _repr_html_(self, **kwargs):
iframe = ''\
.format(\
- html = "data:text/html;base64,"+html.encode('utf8').encode('base64'),
+ html = b"data:text/html;base64,"+base64.b64encode(html.encode('utf8')),
#html = self.HTML.replace('"','"'),
width = int(60.*width),
height= int(60.*height),
diff --git a/folium/features.py b/folium/features.py
index 07748bfe61..830c771fb8 100644
--- a/folium/features.py
+++ b/folium/features.py
@@ -7,8 +7,11 @@
"""
from jinja2 import Template
import json
+import base64
-from .utilities import color_brewer, _parse_size
+from .utilities import color_brewer, _parse_size, legend_scaler, _locations_mirror, _locations_tolist, write_png,\
+ mercator_transform
+from .six import text_type, binary_type
from .element import Element, Figure, JavascriptLink, CssLink, Div, MacroElement
from .map import Map, TileLayer, Icon, Marker, Popup
@@ -40,8 +43,8 @@ def __init__(self, url, name=None,
{
format:'{{ this.format }}',
transparent: {{ this.transparent.__str__().lower() }},
- layers:'{{ this.layers }}',
- attribution:'{{this.attribution}}'
+ layers:'{{ this.layers }}'
+ {% if this.attribution %}, attribution:'{{this.attribution}}'{% endif %}
}
).addTo({{this._parent.get_name()}});
@@ -49,7 +52,7 @@ def __init__(self, url, name=None,
""")
class RegularPolygonMarker(MacroElement):
- def __init__(self, location, popup=None, icon=None,
+ def __init__(self, location, popup=None,
color='black', opacity=1, weight=2,
fill_color='blue', fill_opacity=1,
number_of_sides=4, rotation=0, radius=15):
@@ -57,7 +60,6 @@ def __init__(self, location, popup=None, icon=None,
super(RegularPolygonMarker, self).__init__()
self._name = 'RegularPolygonMarker'
self.location = location
- self.icon = "new L.Icon.Default()" if icon is None else icon
self.color = color
self.opacity = opacity
self.weight = weight
@@ -66,6 +68,8 @@ def __init__(self, location, popup=None, icon=None,
self.number_of_sides= number_of_sides
self.rotation = rotation
self.radius = radius
+ if popup is not None:
+ self.add_children(popup)
self._template = Template(u"""
{% macro script(this, kwargs) %}
@@ -119,9 +123,7 @@ def render(self, **kwargs):
self.json = json.dumps(self.data)
self._parent.html.add_children(Element(Template("""
-
").parent().html(),options.html=html,options.className=options.className||"legend-icon",L.DivIcon.prototype.initialize.call(this,options)}}),L.legendIcon=function(fields,layerOptions,options){return new L.LegendIcon(fields,layerOptions,options)},L.GeometryUtils={getName:function(geoJSON){var name=null;if(geoJSON&&geoJSON.features)for(var index=0;geoJSON.features.length>index;++index){var feature=geoJSON.features[index];if(feature.properties&&feature.properties.name){name=feature.properties.name;break}}return name},getGeoJSONLocation:function(geoJSON,record,locationTextField,recordToLayer){var geoJSONLayer=new L.GeoJSON(geoJSON,{pointToLayer:function(feature,latlng){var location={location:latlng,text:locationTextField?L.Util.getFieldValue(record,locationTextField):[latlng.lat.toFixed(3),latlng.lng.toFixed(3)].join(", "),center:latlng};return recordToLayer(location,record)}}),center=null;try{center=L.GeometryUtils.loadCentroid(geoJSON)}catch(ex){console.log("Error loading centroid for "+JSON.stringify(geoJSON))}return center||(center=geoJSONLayer.getBounds().getCenter()),{location:geoJSONLayer,text:locationTextField?L.Util.getFieldValue(record,locationTextField):null,center:center}},mergeProperties:function(properties,featureCollection,mergeKey){var property,mergeValue,features=featureCollection.features,featureIndex=L.GeometryUtils.indexFeatureCollection(features,mergeKey),newFeatureCollection={type:"FeatureCollection",features:[]};for(var key in properties)if(properties.hasOwnProperty(key)&&(property=properties[key],mergeValue=property[mergeKey])){var feature=featureIndex[mergeValue];for(var prop in property)feature.properties[prop]=property[prop];newFeatureCollection.features.push(feature)}return newFeatureCollection},indexFeatureCollection:function(featureCollection,indexKey){for(var feature,properties,value,features=featureCollection.features,featureIndex={},index=0;features.length>index;++index)feature=features[index],properties=feature.properties,value=properties[indexKey],featureIndex[value]=feature;return featureIndex},arrayToMap:function(array,fromKey,toKey){for(var item,from,to,map={},index=0;array.length>index;++index)item=array[index],from=item[fromKey],to=toKey?item[toKey]:item,map[from]=to;return map},arrayToMaps:function(array,mapLinks){for(var map,item,from,to,mapLink,fromKey,toKey,maps=[],i=0;mapLinks.length>i;++i)maps.push({});for(var index=0;array.length>index;++index){item=array[index];for(var keyIndex=0;mapLinks.length>keyIndex;++keyIndex)map=maps[keyIndex],mapLink=mapLinks[keyIndex],fromKey=mapLink.from,toKey=mapLink.to,from=item[fromKey],to=toKey?item[toKey]:item,map[from]=to}return maps},loadCentroid:function(feature){var centroid,x,y,centroidLatLng=null;if(jsts){var parser=new jsts.io.GeoJSONParser,jstsFeature=parser.read(feature);if(jstsFeature.getCentroid)centroid=jstsFeature.getCentroid(),x=centroid.coordinate.x,y=centroid.coordinate.y;else if(jstsFeature.features){for(var totalCentroidX=0,totalCentroidY=0,i=0;jstsFeature.features.length>i;++i)centroid=jstsFeature.features[i].geometry.getCentroid(),totalCentroidX+=centroid.coordinate.x,totalCentroidY+=centroid.coordinate.y;x=totalCentroidX/jstsFeature.features.length,y=totalCentroidY/jstsFeature.features.length}else centroid=jstsFeature.geometry.getCentroid(),x=centroid.coordinate.x,y=centroid.coordinate.y;centroidLatLng=new L.LatLng(y,x)}return centroidLatLng},loadCentroids:function(dictionary){var feature,centroids={};for(var key in dictionary)feature=dictionary[key],centroids[key]=L.GeometryUtils.loadCentroid(feature);return centroids}},L.SVGPathBuilder=L.Class.extend({initialize:function(points,innerPoints,options){this._points=points||[],this._innerPoints=innerPoints||[],L.Util.setOptions(this,options)},_getPathString:function(points,digits){var pathString="";if(points.length>0){var point=points[0],digits=digits||2;pathString="M"+point.x.toFixed(digits)+","+point.y.toFixed(digits);for(var index=1;points.length>index;index++)point=points[index],pathString+="L"+point.x.toFixed(digits)+","+point.y.toFixed(digits);pathString+="Z"}return pathString},addPoint:function(point,inner){inner?this._innerPoints.push(point):this._points.push(point)},toString:function(digits){digits=digits||this.options.digits;var pathString=this._getPathString(this._points,digits);return this._innerPoints&&(pathString+=this._getPathString(this._innerPoints,digits)),pathString}}),L.StyleConverter={keyMap:{fillColor:{property:["background-color"],valueFunction:function(value){return value}},color:{property:["border-color"],valueFunction:function(value){return value}},weight:{property:["border-width"],valueFunction:function(value){return value+"px"}},stroke:{property:["border-style"],valueFunction:function(value){return value===!0?"solid":"none"}},dashArray:{property:["border-style"],valueFunction:function(value){var style="solid";return value&&(style="dashed"),style}},radius:{property:["height"],valueFunction:function(value){return 2*value+"px"}},fillOpacity:{property:["opacity"],valueFunction:function(value){return value}}},applySVGStyle:function($element,svgStyle,additionalKeys){var keyMap=L.StyleConverter.keyMap;additionalKeys&&(keyMap=L.Util.extend(keyMap,additionalKeys)),$element.css("border-style","solid");for(var property in svgStyle)$element=L.StyleConverter.setCSSProperty($element,property,svgStyle[property],keyMap);return $element},setCSSProperty:function($element,key,value,keyMap){var keyMap=keyMap||L.StyleConverter.keyMap,cssProperty=keyMap[key];if(cssProperty)for(var propertyKey=cssProperty.property,propertyIndex=0;propertyKey.length>propertyIndex;++propertyIndex)$element.css(propertyKey[propertyIndex],cssProperty.valueFunction(value));return $element}},L.StylesBuilder=L.Class.extend({initialize:function(categories,styleFunctionMap){this._categories=categories,this._styleFunctionMap=styleFunctionMap,this._buildStyles()},_buildStyles:function(){for(var category,styleFunction,styleValue,map={},index=0;this._categories.length>index;++index){category=this._categories[index],map[category]={};for(var property in this._styleFunctionMap)styleFunction=this._styleFunctionMap[property],styleValue=styleFunction.evaluate?styleFunction.evaluate(index):"function"==typeof styleFunction?styleFunction(index):styleFunction,map[category][property]=styleValue}this._styleMap=map},getStyles:function(){return this._styleMap}}),L.PaletteBuilder=L.Class.extend({initialize:function(styleFunctionMap){this._styleFunctionMap=styleFunctionMap},generate:function(options){options=options||{};var $paletteElement=$('
'),count=options.count||10,categories=function(count){for(var categoryArray=[],i=0;count>i;++i)categoryArray.push(i);return categoryArray}(count),styleBuilder=new L.StylesBuilder(categories,this._styleFunctionMap),styles=styleBuilder.getStyles();options.className&&$paletteElement.addClass(options.className);for(var styleKey in styles){var $i=$('
'),style=styles[styleKey];L.StyleConverter.applySVGStyle($i,style),$paletteElement.append($i)}return $paletteElement.wrap("
").parent().html()}}),L.HTMLUtils={buildTable:function(obj,className,ignoreFields){className=className||"table table-condensed table-striped table-bordered";var html='
',$html=$(html),$tbody=$html.find("tbody");ignoreFields=ignoreFields||[];for(var property in obj)obj.hasOwnProperty(property)&&-1===$.inArray(ignoreFields,property)&&($.isPlainObject(obj[property])||obj[property]instanceof Array?$tbody.append("
"+property+" "+L.HTMLUtils.buildTable(obj[property],ignoreFields).wrap("
").parent().html()+" "):$tbody.append("
"+property+" "+obj[property]+" "));return $html}},L.AnimationUtils={animate:function(layer,from,to,options){var delay=options.delay||0,frames=options.frames||30,duration=options.duration||500,linearFunctions={},easeFunction=options.easeFunction||function(step){return step},complete=options.complete,step=duration/frames;for(var key in from)"color"!=key&&"fillColor"!=key&&to[key]&&(linearFunctions[key]=new L.LinearFunction([0,from[key]],[frames-1,to[key]]));var layerOptions={},frame=0,updateLayer=function(){for(var key in linearFunctions)layerOptions[key]=linearFunctions[key].evaluate(frame);layer.options=$.extend(!0,{},layer.options,layerOptions),layer.redraw(),frame++,step=easeFunction(step),frames>frame?setTimeout(updateLayer,step):complete()};setTimeout(updateLayer,delay)}},L.ColorUtils={hslToRgbString:function(h,s,l){return L.ColorUtils.rgbArrayToString(L.ColorUtils.hslToRgb(h,s,l))},rgbArrayToString:function(rgbArray){for(var hexValues=[],index=0;rgbArray.length>index;++index){var hexValue=rgbArray[index].toString(16);1===hexValue.length&&(hexValue="0"+hexValue),hexValues.push(hexValue)}return"#"+hexValues.join("")},rgbToHsl:function(r,g,b){r/=255,g/=255,b/=255;var h,s,max=Math.max(r,g,b),min=Math.min(r,g,b),l=(max+min)/2;if(max==min)h=s=0;else{var d=max-min;switch(s=l>.5?d/(2-max-min):d/(max+min),max){case r:h=(g-b)/d+(b>g?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4}h/=6}return[h,s,l]},hslToRgb:function(h,s,l){function hue2rgb(p,q,t){return 0>t&&(t+=1),t>1&&(t-=1),1/6>t?p+6*(q-p)*t:.5>t?q:2/3>t?p+6*(q-p)*(2/3-t):p}var r,g,b;if(0==s)r=g=b=l;else{var q=.5>l?l*(1+s):l+s-l*s,p=2*l-q;r=hue2rgb(p,q,h+1/3),g=hue2rgb(p,q,h),b=hue2rgb(p,q,h-1/3)}return[255*r,255*g,255*b]},rgbToHsv:function(r,g,b){r/=255,g/=255,b/=255;var h,s,max=Math.max(r,g,b),min=Math.min(r,g,b),v=max,d=max-min;if(s=0==max?0:d/max,max==min)h=0;else{switch(max){case r:h=(g-b)/d+(b>g?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4}h/=6}return[h,s,v]},hsvToRgb:function(h,s,v){var r,g,b,i=Math.floor(6*h),f=6*h-i,p=v*(1-s),q=v*(1-f*s),t=v*(1-(1-f)*s);switch(i%6){case 0:r=v,g=t,b=p;break;case 1:r=q,g=v,b=p;break;case 2:r=p,g=v,b=t;break;case 3:r=p,g=q,b=v;break;case 4:r=t,g=p,b=v;break;case 5:r=v,g=p,b=q}return[255*r,255*g,255*b]}};var L=L||{};L.LinearFunction=L.Class.extend({initialize:function(minPoint,maxPoint,options){this.setOptions(options),this.setRange(minPoint,maxPoint)},_calculateParameters:function(minPoint,maxPoint){0===this._xRange?(this._slope=0,this._b=minPoint.y):(this._slope=(maxPoint.y-minPoint.y)/this._xRange,this._b=minPoint.y-this._slope*minPoint.x)},_arrayToPoint:function(array){return{x:array[0],y:array[1]}},setOptions:function(options){L.Util.setOptions(this,options),this._preProcess=this.options.preProcess,this._postProcess=this.options.postProcess},getBounds:function(){var minX=Math.min(this._minPoint.x,this._maxPoint.x),maxX=Math.max(this._minPoint.x,this._maxPoint.x),minY=Math.min(this._minPoint.y,this._maxPoint.y),maxY=Math.max(this._minPoint.y,this._maxPoint.y);return[new L.Point(minX,minY),new L.Point(maxX,maxY)]},setRange:function(minPoint,maxPoint){return minPoint=minPoint instanceof Array?this._arrayToPoint(minPoint):minPoint,maxPoint=maxPoint instanceof Array?this._arrayToPoint(maxPoint):maxPoint,this._minPoint=minPoint,this._maxPoint=maxPoint,this._xRange=maxPoint.x-minPoint.x,this._calculateParameters(minPoint,maxPoint),this},setMin:function(point){return this.setRange(point,this._maxPoint),this},setMax:function(point){return this.setRange(this._minPoint,point),this},setPreProcess:function(preProcess){return this._preProcess=preProcess,this},setPostProcess:function(postProcess){return this._postProcess=postProcess,this},evaluate:function(x){var y;return this._preProcess&&(x=this._preProcess(x)),y=Number((this._slope*x).toFixed(6))+Number(this._b.toFixed(6)),this._postProcess&&(y=this._postProcess(y)),y},random:function(){var randomX=Math.random()*this._xRange+this._minPoint.x;return this.evaluate(randomX)},sample:function(count){count=Math.max(count,2);for(var segmentCount=count-1,segmentSize=this._xRange/segmentCount,x=this._minPoint.x,yValues=[];this._maxPoint.x>=x;)yValues.push(this.evaluate(x)),x+=segmentSize;return yValues}}),L.ColorFunction=L.LinearFunction.extend({options:{alpha:1,includeAlpha:!1},initialize:function(minPoint,maxPoint,options){L.Util.setOptions(this,options),this._parts=[],this._dynamicPart=null,this._outputPrecision=0,this._prefix=null,this._formatOutput=function(y){return y.toFixed(this._outputPrecision)},this._mapOutput=function(parts){for(var outputParts=[],i=0;this._parts.length>i;++i){var part=this._parts[i];outputParts.push(parts[part])}return this.options.includeAlpha&&outputParts.push(this.options.alpha),outputParts},this._getColorString=function(y){y=this._formatOutput(y),this.options[this._dynamicPart]=y;var parts=this._mapOutput(this.options);return this._writeColor(this._prefix,parts)},this._writeColor=function(prefix,parts){return this.options.includeAlpha&&(prefix+="a"),prefix+"("+parts.join(",")+")"};var postProcess=function(y){return options&&options.postProcess&&(y=options.postProcess.call(this,y)),this._getColorString(y)};L.LinearFunction.prototype.initialize.call(this,minPoint,maxPoint,{preProcess:this.options.preProcess,postProcess:postProcess})}}),L.HSLColorFunction=L.ColorFunction.extend({initialize:function(minPoint,maxPoint,options){L.ColorFunction.prototype.initialize.call(this,minPoint,maxPoint,options),this._parts=["outputHue","outputSaturation","outputLuminosity"],this._prefix="hsl",this._outputPrecision=2}}),L.RGBColorFunction=L.ColorFunction.extend({initialize:function(minPoint,maxPoint,options){L.ColorFunction.prototype.initialize.call(this,minPoint,maxPoint,options),this._parts=["outputRed","outputBlue","outputGreen"],this._prefix="rgb",this._outputPrecision=0}}),L.RGBRedFunction=L.LinearFunction.extend({options:{outputGreen:0,outputBlue:0},initialize:function(minPoint,maxPoint,options){L.RGBColorFunction.prototype.initialize.call(this,minPoint,maxPoint,options),this._dynamicPart="outputRed"}}),L.RGBBlueFunction=L.LinearFunction.extend({options:{outputRed:0,outputGreen:0},initialize:function(minPoint,maxPoint,options){L.RGBColorFunction.prototype.initialize.call(this,minPoint,maxPoint,options),this._dynamicPart="outputBlue"}}),L.RGBGreenFunction=L.LinearFunction.extend({options:{outputRed:0,outputBlue:0},initialize:function(minPoint,maxPoint,options){L.RGBColorFunction.prototype.initialize.call(this,minPoint,maxPoint,options),this._dynamicPart="outputGreen"}}),L.RGBColorBlendFunction=L.LinearFunction.extend({initialize:function(minX,maxX,rgbMinColor,rgbMaxColor){var red1=rgbMinColor[0],red2=rgbMaxColor[0],green1=rgbMinColor[1],green2=rgbMaxColor[1],blue1=rgbMinColor[2],blue2=rgbMaxColor[2],postProcess=function(y){return y.toFixed(0)};this._minX=minX,this._maxX=maxX,this._redFunction=new L.LinearFunction(new L.Point(minX,red1),new L.Point(maxX,red2),{postProcess:postProcess}),this._greenFunction=new L.LinearFunction(new L.Point(minX,green1),new L.Point(maxX,green2),{postProcess:postProcess}),this._blueFunction=new L.LinearFunction(new L.Point(minX,blue1),new L.Point(maxX,blue2),{postProcess:postProcess})},getBounds:function(){var redBounds=this._redFunction.getBounds(),greenBounds=this._greenFunction.getBounds(),blueBounds=this._blueFunction.getBounds(),minY=Math.min(redBounds[0].y,greenBounds[0].y,blueBounds[0].y),maxY=Math.max(redBounds[0].y,greenBounds[0].y,blueBounds[0].y);return[new L.Point(redBounds[0].x,minY),new L.Point(redBounds[1].x,maxY)]},evaluate:function(x){return"rgb("+[this._redFunction.evaluate(x),this._greenFunction.evaluate(x),this._blueFunction.evaluate(x)].join(",")+")"}}),L.HSLHueFunction=L.HSLColorFunction.extend({options:{outputSaturation:"100%",outputLuminosity:"50%"},initialize:function(minPoint,maxPoint,options){L.HSLColorFunction.prototype.initialize.call(this,minPoint,maxPoint,options),this._dynamicPart="outputHue"}}),L.HSLSaturationFunction=L.LinearFunction.extend({options:{outputHue:0,outputLuminosity:"50%"},initialize:function(minPoint,maxPoint,options){L.HSLColorFunction.prototype.initialize.call(this,minPoint,maxPoint,options),this._formatOutput=function(y){return(100*y).toFixed(this._outputPrecision)+"%"},this._dynamicPart="outputSaturation"}}),L.HSLLuminosityFunction=L.LinearFunction.extend({options:{outputHue:0,outputSaturation:"100%"},initialize:function(minPoint,maxPoint,options){L.HSLColorFunction.prototype.initialize.call(this,minPoint,maxPoint,options),this._formatOutput=function(y){return(100*y).toFixed(this._outputPrecision)+"%"},this._dynamicPart="outputLuminosity"}}),L.PiecewiseFunction=L.LinearFunction.extend({initialize:function(functions,options){L.Util.setOptions(this,options),this._functions=functions;var startPoint,endPoint;startPoint=functions[0].getBounds()[0],endPoint=functions[functions.length-1].getBounds()[1],L.LinearFunction.prototype.initialize.call(this,startPoint,endPoint,{preProcess:this.options.preProcess,postProcess:this.options.postProcess})},_getFunction:function(x){for(var bounds,startPoint,endPoint,currentFunction,found=!1,index=0;this._functions.length>index;++index)if(currentFunction=this._functions[index],bounds=currentFunction.getBounds(),startPoint=bounds[0],endPoint=bounds[1],x>=startPoint.x&&endPoint.x>x){found=!0;break}return found?currentFunction:this._functions[this._functions.length-1]},evaluate:function(x){var currentFunction,y=null;return this._preProcess&&(x=this._preProcess(x)),currentFunction=this._getFunction(x),currentFunction&&(y=currentFunction.evaluate(x),this._postProcess&&(y=this._postProcess(y))),y}}),L.CategoryFunction=L.Class.extend({initialize:function(categoryMap,options){L.Util.setOptions(this,options),this._categoryKeys=Object.keys(categoryMap),this._categoryMap=categoryMap,this._preProcess=this.options.preProcess,this._postProcess=this.options.postProcess},evaluate:function(x){var y;return this._preProcess&&(x=this._preProcess(x)),y=this._categoryMap[x],this._postProcess&&(y=this._postProcess(y)),y},getCategories:function(){return this._categoryKeys}});var L=L||{},PathFunctions={__updateStyle:L.Path.prototype._updateStyle,_createDefs:function(){this._defs=this._createElement("defs"),this._container.appendChild(this._defs)},_createGradient:function(options){this._defs||this._createDefs();var gradient=this._createElement("linearGradient"),gradientGuid=L.Util.guid();options=options||{x1:"0%",x2:"100%",y1:"0%",y2:"100%"},options.id="grad"+gradientGuid;var stops=[{offset:"0%",style:"stop-color:rgb(255, 255, 255);stop-opacity:1"},{offset:"60%",style:"stop-color:"+(this.options.fillColor||this.options.color)+";stop-opacity:1"}];for(var key in options)gradient.setAttribute(key,options[key]);for(var i=0;stops.length>i;++i){var stop=stops[i],stopElement=this._createElement("stop");for(var key in stop)stopElement.setAttribute(key,stop[key]);gradient.appendChild(stopElement)}this._gradient=gradient,this._defs.appendChild(gradient)},_createDropShadow:function(options){this._defs||this._createDefs();var filterGuid=L.Util.guid(),filter=this._createElement("filter"),feOffset=this._createElement("feOffset"),feGaussianBlur=this._createElement("feGaussianBlur"),feBlend=this._createElement("feBlend");options=options||{width:"200%",height:"200%"},options.id="filter"+filterGuid;for(var key in options)filter.setAttribute(key,options[key]);var offsetOptions={result:"offOut","in":"SourceAlpha",dx:"2",dy:"2"},blurOptions={result:"blurOut","in":"offOut",stdDeviation:"2"},blendOptions={"in":"SourceGraphic",in2:"blurOut",mode:"lighten"};for(var key in offsetOptions)feOffset.setAttribute(key,offsetOptions[key]);for(var key in blurOptions)feGaussianBlur.setAttribute(key,blurOptions[key]);for(var key in blendOptions)feBlend.setAttribute(key,blendOptions[key]);filter.appendChild(feOffset),filter.appendChild(feGaussianBlur),filter.appendChild(feBlend),this._dropShadow=filter,this._defs.appendChild(filter)},_updateStyle:function(){this.__updateStyle.call(this),this.options.gradient&&(this._gradient||this._createGradient(),this._path.setAttribute("fill","url(#"+this._gradient.getAttribute("id")+")")),this.options.dropShadow&&(this._dropShadow||this._createDropShadow(),this._path.setAttribute("filter","url(#"+this._dropShadow.getAttribute("id")+")"))}};L.Path.include(PathFunctions),L.Polygon.include(PathFunctions),L.Polyline.include(PathFunctions),L.CircleMarker.include(PathFunctions),L.MapMarker=L.Path.extend({initialize:function(centerLatLng,options){L.Path.prototype.initialize.call(this,options),this._centerLatLng=centerLatLng},options:{fill:!0,fillOpacity:1,opacity:1,radius:15,innerRadius:5,position:{x:0,y:0},rotation:0,numberOfSides:50,color:"#000000",fillColor:"#0000FF",weight:1,gradient:!0,dropShadow:!0},setLatLng:function(latlng){return this._centerLatLng=latlng,this.redraw()},projectLatlngs:function(){this._point=this._map.latLngToLayerPoint(this._centerLatLng),this._points=this._getPoints(),this.options.innerRadius&&(this._innerPoints=this._getPoints(!0).reverse())},getBounds:function(){var map=this._map,height=3*this.options.radius,point=map.project(this._centerLatLng),swPoint=new L.Point(point.x-this.options.radius,point.y),nePoint=new L.Point(point.x+this.options.radius,point.y-height),sw=map.unproject(swPoint),ne=map.unproject(nePoint);return new L.LatLngBounds(sw,ne)},getLatLng:function(){return this._centerLatLng},getPathString:function(){return this._path.setAttribute("shape-rendering","geometricPrecision"),new L.SVGPathBuilder(this._points,this._innerPoints).toString(6)},_getPoints:function(inner){var newPoint,angleRadians,maxDegrees=inner?360:210,angleSize=inner?maxDegrees/Math.max(this.options.numberOfSides,3):maxDegrees/50,degrees=inner?maxDegrees+this.options.rotation:maxDegrees,angle=inner?this.options.rotation:-30,points=[],radius=this.options.radius,toRad=function(number){return number*Math.PI/180},startPoint=this._point;for(inner||(points.push(startPoint),points.push(new L.Point(startPoint.x+Math.sqrt(.75)*radius,startPoint.y-1.5*radius)));degrees>angle;)angleRadians=toRad(angle),newPoint=this._getPoint(angleRadians,radius,inner),points.push(newPoint),angle+=angleSize;return inner||points.push(new L.Point(startPoint.x-Math.sqrt(.75)*radius,startPoint.y-1.5*radius)),points},_getPoint:function(angle,radius,inner){var markerRadius=radius;return radius=inner?this.options.innerRadius:radius,new L.Point(this._point.x+this.options.position.x+radius*Math.cos(angle),this._point.y-2*markerRadius+this.options.position.y-radius*Math.sin(angle))}}),L.mapMarker=function(centerLatLng,options){return new L.MapMarker(centerLatLng,options)},L.RegularPolygonMarker=L.Path.extend({initialize:function(centerLatLng,options){L.Path.prototype.initialize.call(this,options),this._centerLatLng=centerLatLng,this.options.numberOfSides=Math.max(this.options.numberOfSides,3)},options:{fill:!0,radiusX:10,radiusY:10,rotation:0,numberOfSides:3,position:{x:0,y:0},maxDegrees:360,gradient:!0,dropShadow:!1},setLatLng:function(latlng){return this._centerLatLng=latlng,this.redraw()},projectLatlngs:function(){this._point=this._map.latLngToLayerPoint(this._centerLatLng),this._points=this._getPoints(),(this.options.innerRadius||this.options.innerRadiusX&&this.options.innerRadiusY)&&(this._innerPoints=this._getPoints(!0).reverse())},getBounds:function(){var map=this._map,radiusX=this.options.radius||this.options.radiusX,radiusY=this.options.radius||this.options.radiusY,deltaX=radiusX*Math.cos(Math.PI/4),deltaY=radiusY*Math.sin(Math.PI/4),point=map.project(this._centerLatLng),swPoint=new L.Point(point.x-deltaX,point.y+deltaY),nePoint=new L.Point(point.x+deltaX,point.y-deltaY),sw=map.unproject(swPoint),ne=map.unproject(nePoint);return new L.LatLngBounds(sw,ne)},getLatLng:function(){return this._centerLatLng},getPathString:function(){return this._path.setAttribute("shape-rendering","geometricPrecision"),new L.SVGPathBuilder(this._points,this._innerPoints).toString(6)},_getPoints:function(inner){for(var newPoint,angleRadians,maxDegrees=this.options.maxDegrees||360,angleSize=maxDegrees/Math.max(this.options.numberOfSides,3),degrees=maxDegrees+this.options.rotation,angle=this.options.rotation,points=[],radiusX=inner?this.options.innerRadius||this.options.innerRadiusX:this.options.radius||this.options.radiusX,radiusY=inner?this.options.innerRadius||this.options.innerRadiusY:this.options.radius||this.options.radiusY,toRad=function(number){return number*Math.PI/180};degrees>angle;)angleRadians=toRad(angle),newPoint=this._getPoint(angleRadians,radiusX,radiusY),points.push(newPoint),angle+=angleSize;return points},_getPoint:function(angle,radiusX,radiusY){return new L.Point(this._point.x+this.options.position.x+radiusX*Math.cos(angle),this._point.y+this.options.position.y+radiusY*Math.sin(angle))}}),L.regularPolygonMarker=function(centerLatLng,options){return new L.RegularPolygonMarker(centerLatLng,options)},L.StarMarker=L.RegularPolygonMarker.extend({options:{numberOfPoints:5,rotation:-15,maxDegrees:360,gradient:!0,dropShadow:!0},_getPoints:function(inner){for(var newPoint,newPointInner,angleRadians,maxDegrees=this.options.maxDegrees||360,angleSize=maxDegrees/this.options.numberOfPoints,degrees=maxDegrees+this.options.rotation,angle=this.options.rotation,points=[],radiusX=inner?this.options.innerRadius||this.options.innerRadiusX:this.options.radius||this.options.radiusX,radiusY=inner?this.options.innerRadius||this.options.innerRadiusY:this.options.radius||this.options.radiusY,toRad=function(number){return number*Math.PI/180};degrees>angle;)angleRadians=toRad(angle),newPoint=this._getPoint(angleRadians,radiusX,radiusY),newPointInner=this._getPoint(angleRadians+toRad(angleSize)/2,radiusX/2,radiusY/2),points.push(newPoint),points.push(newPointInner),angle+=angleSize;return points}}),L.starMarker=function(centerLatLng,options){return new L.StarMarker(centerLatLng,options)},L.TriangleMarker=L.RegularPolygonMarker.extend({options:{numberOfSides:3,rotation:30,radius:5}}),L.triangleMarker=function(centerLatLng,options){return new L.TriangleMarker(centerLatLng,options)},L.DiamondMarker=L.RegularPolygonMarker.extend({options:{numberOfSides:4,radiusX:5,radiusY:10}}),L.diamondMarker=function(centerLatLng,options){return new L.DiamondMarker(centerLatLng,options)},L.SquareMarker=L.RegularPolygonMarker.extend({options:{numberOfSides:4,rotation:45,radius:5}}),L.squareMarker=function(centerLatLng,options){return new L.SquareMarker(centerLatLng,options)},L.PentagonMarker=L.RegularPolygonMarker.extend({options:{numberOfSides:5,rotation:-18,radius:5}}),L.pentagonMarker=function(centerLatLng,options){return new L.PentagonMarker(centerLatLng,options)},L.HexagonMarker=L.RegularPolygonMarker.extend({options:{numberOfSides:6,rotation:30,radius:5}}),L.hexagonMarker=function(centerLatLng,options){return new L.HexagonMarker(centerLatLng,options)},L.OctagonMarker=L.RegularPolygonMarker.extend({options:{numberOfSides:8,rotation:22.5,radius:5}}),L.octagonMarker=function(centerLatLng,options){return new L.OctagonMarker(centerLatLng,options)};var L=L||{};L.BarMarker=L.Path.extend({initialize:function(centerLatLng,options){L.Path.prototype.initialize.call(this,options),this._centerLatLng=centerLatLng},options:{fill:!0,width:2,maxHeight:10,position:{x:0,y:0},weight:1,color:"#000",opacity:1,gradient:!0,dropShadow:!1},setLatLng:function(latlng){return this._centerLatLng=latlng,this.redraw()},projectLatlngs:function(){this._point=this._map.latLngToLayerPoint(this._centerLatLng),this._points=this._getPoints()},getBounds:function(){var map=this._map,point=map.project(this._centerLatLng),halfWidth=this.options.width/2,swPoint=new L.Point(point.x-halfWidth,point.y),nePoint=new L.Point(point.x+halfWidth,point.y-this.options.maxHeight),sw=map.unproject(swPoint),ne=map.unproject(nePoint);return new L.LatLngBounds(sw,ne)},getLatLng:function(){return this._centerLatlng},getPathString:function(){return this._path.setAttribute("shape-rendering","crispEdges"),""+new L.SVGPathBuilder(this._points)},_getPoints:function(){var sePoint,nePoint,nwPoint,swPoint,points=[],startX=this._point.x+this.options.position.x,startY=this._point.y+this.options.position.y,halfWidth=this.options.width/2,height=this.options.value/this.options.maxValue*this.options.maxHeight;return sePoint=new L.Point(startX+halfWidth,startY),nePoint=new L.Point(startX+halfWidth,startY-height),nwPoint=new L.Point(startX-halfWidth,startY-height),swPoint=new L.Point(startX-halfWidth,startY),points=[sePoint,nePoint,nwPoint,swPoint]}}),L.barMarker=function(centerLatLng,options){return new L.BarMarker(centerLatLng,options)},L.ChartMarker=L.FeatureGroup.extend({initialize:function(centerLatLng,options){L.Util.setOptions(this,options),this._layers={},this._centerLatLng=centerLatLng,this._loadBars()},setLatLng:function(latlng){return this._centerLatLng=latlng,this.redraw()
-},getLatLng:function(){return this._centerLatlng},_loadBars:function(){},_highlight:function(options){return options.weight&&(options.weight*=2),options},_unhighlight:function(options){return options.weight&&(options.weight/=2),options},_bindMouseEvents:function(chartElement){var self=this,tooltipOptions=this.options.tooltipOptions;chartElement.on("mouseover",function(e){var newPoint,currentOptions=this.options,key=currentOptions.key,value=currentOptions.value,layerPoint=e.layerPoint,x=layerPoint.x-this._point.x,y=layerPoint.y-this._point.y,iconSize=currentOptions.iconSize,newX=x,newY=y,offset=5;newX=0>x?iconSize.x-x+offset:-x-offset,newY=0>y?iconSize.y-y+offset:-y-offset,newPoint=new L.Point(newX,newY);var legendOptions={},displayText=currentOptions.displayText?currentOptions.displayText(value):value;legendOptions[key]={name:currentOptions.displayName,value:displayText};var icon=new L.LegendIcon(legendOptions,currentOptions,{className:"leaflet-div-icon",iconSize:tooltipOptions?tooltipOptions.iconSize:iconSize,iconAnchor:newPoint});currentOptions.marker=new L.Marker(self._centerLatLng,{icon:icon}),currentOptions=self._highlight(currentOptions),this.initialize(self._centerLatLng,currentOptions),this.redraw(),this.setStyle(currentOptions),self.addLayer(currentOptions.marker)}),chartElement.on("mouseout",function(){var currentOptions=this.options;currentOptions=self._unhighlight(currentOptions),this.initialize(self._centerLatLng,currentOptions),this.redraw(),this.setStyle(currentOptions),self.removeLayer(currentOptions.marker)})},bindPopup:function(content,options){this.eachLayer(function(layer){layer.bindPopup(content,options)})}}),L.BarChartMarker=L.ChartMarker.extend({initialize:function(centerLatLng,options){L.Util.setOptions(this,options),L.ChartMarker.prototype.initialize.call(this,centerLatLng,options)},options:{weight:1,opacity:1,color:"#000",fill:!0,position:{x:0,y:0},width:10,offset:0,iconSize:new L.Point(50,40)},_loadBars:function(){var value,minValue,maxValue;this.options.rotation,this.options.maxDegrees||360;var bar,options=this.options;this.options.radiusX||this.options.radius,this.options.radiusY||this.options.radius;var x,y,chartOption,keys=Object.keys(this.options.data),count=keys.length,width=this.options.width,offset=this.options.offset||0,data=this.options.data,chartOptions=this.options.chartOptions;x=-(width*count+offset*(count-1))/2+width/2,y=0;for(var key in data)value=data[key],chartOption=chartOptions[key],minValue=chartOption.minValue||0,maxValue=chartOption.maxValue||100,options.fillColor=chartOption.fillColor||this.options.fillColor,options.value=value,options.minValue=minValue,options.maxValue=maxValue,options.position={x:x,y:y},options.width=width,options.maxHeight=chartOption.maxHeight||10,options.key=key,options.value=value,options.displayName=chartOption.displayName,options.opacity=this.options.opacity||1,options.fillOpacity=this.options.fillOpacity||.7,options.weight=this.options.weight||1,options.color=chartOption.color||this.options.color,options.displayText=chartOption.displayText,bar=new L.BarMarker(this._centerLatLng,options),this._bindMouseEvents(bar),this.addLayer(bar),x+=width+offset}}),L.RadialBarMarker=L.Path.extend({initialize:function(centerLatLng,options){L.Path.prototype.initialize.call(this,options),this._centerLatLng=centerLatLng},options:{fill:!0,radius:10,rotation:0,numberOfSides:30,position:{x:0,y:0},gradient:!0,dropShadow:!1},setLatLng:function(latlng){return this._centerLatLng=latlng,this.redraw()},projectLatlngs:function(){this._point=this._map.latLngToLayerPoint(this._centerLatLng),this._points=this._getPoints()},getBounds:function(){var map=this._map,radiusX=this.options.radiusX||this.options.radius,radiusY=this.options.radiusY||this.options.radius,deltaX=radiusX*Math.cos(Math.PI/4),deltaY=radiusY*Math.sin(Math.PI/4),point=map.project(this._centerLatLng),swPoint=new L.Point(point.x-deltaX,point.y+deltaY),nePoint=new L.Point(point.x+deltaX,point.y-deltaY),sw=map.unproject(swPoint),ne=map.unproject(nePoint);return new L.LatLngBounds(sw,ne)},getLatLng:function(){return this._centerLatlng},getPathString:function(){var angle=this.options.endAngle-this.options.startAngle,largeArc=angle>=180?"1":"0",radiusX=this.options.radiusX||this.options.radius,radiusY=this.options.radiusY||this.options.radius,path="M"+this._points[0].x.toFixed(2)+","+this._points[0].y.toFixed(2)+"A"+radiusX.toFixed(2)+","+radiusY.toFixed(2)+" 0 "+largeArc+",1 "+this._points[1].x.toFixed(2)+","+this._points[1].y.toFixed(2)+"L";return this._innerPoints?(path=path+this._innerPoints[0].x.toFixed(2)+","+this._innerPoints[0].y.toFixed(2),path=path+"A"+(radiusX-this.options.barThickness).toFixed(2)+","+(radiusY-this.options.barThickness).toFixed(2)+" 0 "+largeArc+",0 "+this._innerPoints[1].x.toFixed(2)+","+this._innerPoints[1].y.toFixed(2)+"z"):path=path+this._point.x.toFixed(2)+","+this._point.y.toFixed(2)+"z",this._path.setAttribute("shape-rendering","geometricPrecision"),path},_getPoints:function(){var angleDelta=this.options.endAngle-this.options.startAngle;angleDelta/this.options.numberOfSides;var degrees=this.options.endAngle+this.options.rotation,angle=this.options.startAngle+this.options.rotation,points=[],radiusX="radiusX"in this.options?this.options.radiusX:this.options.radius,radiusY="radiusY"in this.options?this.options.radiusY:this.options.radius,toRad=function(number){return number*Math.PI/180};360===angleDelta&&(degrees-=.1);var startRadians=toRad(angle),endRadians=toRad(degrees);return points.push(this._getPoint(startRadians,radiusX,radiusY)),points.push(this._getPoint(endRadians,radiusX,radiusY)),this.options.barThickness&&(this._innerPoints=[],radiusX-this.options.barThickness,radiusY-this.options.barThickness,this._innerPoints.push(this._getPoint(endRadians,radiusX-this.options.barThickness,radiusY-this.options.barThickness)),this._innerPoints.push(this._getPoint(startRadians,radiusX-this.options.barThickness,radiusY-this.options.barThickness))),points},_getPoint:function(angle,radiusX,radiusY){return new L.Point(this._point.x+this.options.position.x+radiusX*Math.cos(angle),this._point.y+this.options.position.y+radiusY*Math.sin(angle))}}),L.radialBarMarker=function(centerLatLng,options){return new L.RadialBarMarker(centerLatLng,options)},L.PieChartMarker=L.ChartMarker.extend({initialize:function(centerLatLng,options){L.Util.setOptions(this,options),L.ChartMarker.prototype.initialize.call(this,centerLatLng,options)},options:{weight:1,opacity:1,color:"#000",fill:!0,radius:10,rotation:0,numberOfSides:50,mouseOverExaggeration:1.2,maxDegrees:360,iconSize:new L.Point(50,40)},_highlight:function(options){var oldRadiusX=options.radiusX,oldBarThickness=options.barThickness;return options.oldBarThickness=oldBarThickness,options.radiusX*=options.mouseOverExaggeration,options.radiusY*=options.mouseOverExaggeration,options.barThickness=options.radiusX-oldRadiusX+oldBarThickness,options},_unhighlight:function(options){return options.radiusX/=options.mouseOverExaggeration,options.radiusY/=options.mouseOverExaggeration,options.barThickness=options.oldBarThickness,options},_loadBars:function(){var value,bar,chartOption,key,sum=0,angle=0,percentage=0,maxDegrees=this.options.maxDegrees||360,lastAngle=this.options.rotation,options=this.options,data=this.options.data,chartOptions=this.options.chartOptions,getValue=function(data,key){var value=0;return data[key]&&(value=parseFloat(data[key])),value};for(key in data)value=getValue(data,key),sum+=value;if(sum>0)for(key in data)value=parseFloat(data[key]),chartOption=chartOptions[key],percentage=value/sum,angle=percentage*maxDegrees,options.startAngle=lastAngle,options.endAngle=lastAngle+angle,options.fillColor=chartOption.fillColor,options.color=chartOption.color||"#000",options.radiusX=this.options.radiusX||this.options.radius,options.radiusY=this.options.radiusY||this.options.radius,options.rotation=0,options.key=key,options.value=value,options.displayName=chartOption.displayName,options.displayText=chartOption.displayText,bar=new L.RadialBarMarker(this._centerLatLng,options),this._bindMouseEvents(bar),lastAngle=options.endAngle,this.addLayer(bar)}}),L.pieChartMarker=function(centerLatLng,options){return new L.PieChartMarker(centerLatLng,options)},L.CoxcombChartMarker=L.PieChartMarker.extend({initialize:function(centerLatLng,options){L.Util.setOptions(this,options),L.PieChartMarker.prototype.initialize.call(this,centerLatLng,options)},options:{weight:1,opacity:1,color:"#000",fill:!0,radius:10,rotation:0,numberOfSides:50,mouseOverExaggeration:1.2,maxDegrees:360,iconSize:new L.Point(50,40)},_loadBars:function(){var value,minValue,maxValue,bar,chartOption,angle=0,maxDegrees=this.options.maxDegrees||360,lastAngle=this.options.rotation,options=this.options,radiusX="radiusX"in this.options?this.options.radiusX:this.options.radius,radiusY="radiusY"in this.options?this.options.radiusY:this.options.radius,keys=Object.keys(this.options.data),count=keys.length,data=this.options.data,chartOptions=this.options.chartOptions;angle=maxDegrees/count;for(var key in data){value=parseFloat(data[key]),chartOption=chartOptions[key];var minValue=chartOption.minValue||0,maxValue=chartOption.maxValue,evalFunctionX=new L.LinearFunction(new L.Point(minValue,0),new L.Point(maxValue,radiusX)),evalFunctionY=new L.LinearFunction(new L.Point(minValue,0),new L.Point(maxValue,radiusY));options.startAngle=lastAngle,options.endAngle=lastAngle+angle,options.fillColor=chartOption.fillColor,options.color=chartOption.color||"#000",options.radiusX=evalFunctionX.evaluate(value),options.radiusY=evalFunctionY.evaluate(value),options.rotation=0,options.key=key,options.value=value,options.displayName=chartOption.displayName,options.displayText=chartOption.displayText,bar=new L.RadialBarMarker(this._centerLatLng,options),this._bindMouseEvents(bar),lastAngle=options.endAngle,this.addLayer(bar)}}}),L.coxcombChartMarker=function(centerLatLng,options){return new L.CoxcombChartMarker(centerLatLng,options)},L.RadialBarChartMarker=L.ChartMarker.extend({initialize:function(centerLatLng,options){L.Util.setOptions(this,options),L.ChartMarker.prototype.initialize.call(this,centerLatLng,options)},options:{weight:1,opacity:1,color:"#000",fill:!0,radius:10,rotation:0,numberOfSides:30,offset:2,barThickness:5,maxDegrees:360,iconSize:new L.Point(50,40)},_loadBars:function(){var value,minValue,maxValue,bar,chartOption,angle=this.options.rotation,maxDegrees=this.options.maxDegrees||360,options=this.options,lastRadiusX=this.options.radiusX||this.options.radius,lastRadiusY=this.options.radiusY||this.options.radius,data=this.options.data,chartOptions=this.options.chartOptions,barThickness=this.options.barThickness||4,offset=this.options.offset||2;for(var key in data){value=parseFloat(data[key]),chartOption=chartOptions[key],minValue=chartOption.minValue||0,maxValue=chartOption.maxValue||100;var angleFunction=new L.LinearFunction(new L.Point(minValue,0),new L.Point(maxValue,maxDegrees));angle=angleFunction.evaluate(value),options.startAngle=this.options.rotation,options.endAngle=this.options.rotation+angle,options.fillColor=chartOption.fillColor,options.radiusX=lastRadiusX,options.radiusY=lastRadiusY,options.barThickness=barThickness,options.rotation=0,options.key=key,options.value=value,options.displayName=chartOption.displayName,options.displayText=chartOption.displayText,options.weight=this.options.weight||1,bar=new L.RadialBarMarker(this._centerLatLng,options),this._bindMouseEvents(bar),this.addLayer(bar),lastRadiusX+=barThickness+offset,lastRadiusY+=barThickness+offset}}}),L.radialBarChartMarker=function(centerLatLng,options){return new L.RadialBarChartMarker(centerLatLng,options)},L.StackedRegularPolygonMarker=L.ChartMarker.extend({options:{iconSize:new L.Point(50,40)},initialize:function(centerLatLng,options){L.Util.setOptions(this,options),L.ChartMarker.prototype.initialize.call(this,centerLatLng,options)},_loadBars:function(){var value;this.options.maxDegrees||360;var bar,chartOption,key,lastRadiusX=0,lastRadiusY=0,options=this.options,data=this.options.data,chartOptions=this.options.chartOptions;for(key in data){value=parseFloat(data[key]),chartOption=chartOptions[key],minValue=chartOption.minValue||0,maxValue=chartOption.maxValue||100,minRadius=chartOption.minRadius||0,maxRadius=chartOption.maxRadius||10,options.fillColor=chartOption.fillColor||this.options.fillColor,options.value=value,options.minValue=minValue,options.maxValue=maxValue;var evalFunction=new L.LinearFunction(new L.Point(minValue,minRadius),new L.Point(maxValue,maxRadius)),barThickness=evalFunction.evaluate(value);options.radiusX=lastRadiusX+barThickness,options.radiusY=lastRadiusY+barThickness,options.innerRadiusX=lastRadiusX,options.innerRadiusY=lastRadiusY,options.key=key,options.displayName=chartOption.displayName,options.opacity=this.options.opacity||1,options.fillOpacity=this.options.fillOpacity||.7,options.weight=this.options.weight||1,options.color=chartOption.color||this.options.color,options.displayText=chartOption.displayText,bar=new L.RegularPolygonMarker(this._centerLatLng,options),this._bindMouseEvents(bar),lastRadiusX=options.radiusX,lastRadiusY=options.radiusY,this.addLayer(bar)}}}),L.RadialMeterMarker=L.ChartMarker.extend({initialize:function(centerLatLng,options){L.Util.setOptions(this,options),L.ChartMarker.prototype.initialize.call(this,centerLatLng,options)},options:{weight:1,opacity:1,color:"#000",fill:!0,radius:10,rotation:180,numberOfSides:30,offset:2,barThickness:5,maxDegrees:180,iconSize:new L.Point(50,40)},_loadBars:function(){var value,minValue,maxValue,bar,chartOption,startAngle=this.options.rotation,maxDegrees=this.options.maxDegrees||360,options=this.options,radiusX=this.options.radiusX||this.options.radius,radiusY=this.options.radiusY||this.options.radius,data=this.options.data,chartOptions=this.options.chartOptions,barThickness=this.options.barThickness||4;this.options.offset||2;var displayOptions,lastAngle=startAngle,numSegments=this.options.numSegments||10,angleDelta=maxDegrees/numSegments;for(var key in data){value=parseFloat(data[key]),chartOption=chartOptions[key],displayOptions=this.options.displayOptions?this.options.displayOptions[key]:{},minValue=chartOption.minValue||0,maxValue=chartOption.maxValue||100;for(var range=maxValue-minValue,angle=maxDegrees/range*(value-minValue),endAngle=startAngle+angle,evalFunction=new L.LinearFunction(new L.Point(startAngle,minValue),new L.Point(startAngle+maxDegrees,maxValue));endAngle>lastAngle;){options.startAngle=lastAngle;var delta=Math.min(angleDelta,endAngle-lastAngle);options.endAngle=lastAngle+delta,options.fillColor=chartOption.fillColor,options.radiusX=radiusX,options.radiusY=radiusY,options.barThickness=barThickness,options.rotation=0,options.key=key,options.value=value,options.displayName=chartOption.displayName,options.displayText=chartOption.displayText;var evalValue=evalFunction.evaluate(lastAngle+delta);for(var displayKey in displayOptions)options[displayKey]=displayOptions[displayKey].evaluate?displayOptions[displayKey].evaluate(evalValue):displayOptions[displayKey];bar=new L.RadialBarMarker(this._centerLatLng,options),this._bindMouseEvents(bar),this.addLayer(bar),lastAngle+=delta}}}});
\ No newline at end of file
diff --git a/folium/plugins/marker_cluster.py b/folium/plugins/marker_cluster.py
index 8011dae417..0c758c1ad8 100644
--- a/folium/plugins/marker_cluster.py
+++ b/folium/plugins/marker_cluster.py
@@ -5,48 +5,66 @@
Creates a MarkerCluster plugin to add on a folium map.
"""
-import json
+#import json
+from jinja2 import Template
-from .plugin import Plugin
+from folium.element import JavascriptLink, CssLink, MacroElement, Figure
+from folium.map import Popup, Icon, Marker
-class MarkerCluster(Plugin):
- """Adds a MarkerCluster layer on the map."""
- def __init__(self, data):
+class MarkerCluster(MacroElement):
+ def __init__(self, locations, popups=None, icons=None):
"""Creates a MarkerCluster plugin to append into a map with
- Map.add_plugin.
+ Map.add_children.
Parameters
----------
- data: list of list or array of shape (n,3).
- Data points of the form [[lat, lng, popup]].
+ locations: list of list or array of shape (n,2).
+ Data points of the form [[lat, lng]].
+
+ popups: list of length n.
+ Popup for each marker.
+
+ icons: list of length n.
+ Icon for each marker.
"""
super(MarkerCluster, self).__init__()
- self.plugin_name = 'MarkerCluster'
- self.data = [tuple(x) for x in data]
-
- def render_header(self, nb):
- """Generates the HTML part of the plugin."""
- return """
-
-
-
- """ if nb==0 else ""
-
- def render_js(self, nb):
- """Generates the Javascript part of the plugin."""
- out = """
- var addressPoints = """+json.dumps(self.data)+""";
-
- var markers = L.markerClusterGroup();
-
- for (var i = 0; i < addressPoints.length; i++) {
- var a = addressPoints[i];
- var title = a[2];
- var marker = L.marker(new L.LatLng(a[0], a[1]), { title: title });
- marker.bindPopup(title);
- markers.addLayer(marker);
- }
-
- map.addLayer(markers);
- """
- return out
+ self._name = 'MarkerCluster'
+
+ if popups is None:
+ popups = [None]*len(locations)
+ if icons is None:
+ icons = [None]*len(locations)
+
+ for location, popup, icon in zip(locations,popups,icons):
+ if popup is None or isinstance(popup, Popup):
+ p = popup
+ else:
+ p = Popup(popup)
+ if icon is None or isinstance(icon, Icon):
+ i = icon
+ else:
+ i = Icon(icon)
+ self.add_children(Marker(location, popup=p, icon=i))
+
+ self._template = Template(u"""
+ {% macro script(this, kwargs) %}
+ var {{this.get_name()}} = L.markerClusterGroup();
+ {{this._parent.get_name()}}.addLayer({{this.get_name()}});
+ {% endmacro %}
+ """)
+ def render(self,**kwargs):
+ super(MarkerCluster,self).render(**kwargs)
+
+ figure = self.get_root()
+ assert isinstance(figure,Figure), ("You cannot render this Element "
+ "if it's not in a Figure.")
+
+ figure.header.add_children(\
+ JavascriptLink("https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/0.4.0/leaflet.markercluster.js"),
+ name='markerclusterjs')
+ figure.header.add_children(\
+ CssLink("https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/0.4.0/MarkerCluster.css"),
+ name='markerclustercss')
+ figure.header.add_children(\
+ CssLink("https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/0.4.0/MarkerCluster.Default.css"),
+ name='markerclusterdefaultcss')
diff --git a/folium/plugins/plugin.py b/folium/plugins/plugin.py
deleted file mode 100644
index 088bce39f7..0000000000
--- a/folium/plugins/plugin.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Plugin
-------
-
-A generic class for creating plugins.
-Basic plugin object that does nothing.
-Other plugins may inherit from this one.
-"""
-from uuid import uuid4
-
-from jinja2 import Environment, PackageLoader
-ENV = Environment(loader=PackageLoader('folium', 'plugins'))
-
-class Plugin(object):
- """Basic plugin object that does nothing.
- Other plugins may inherit from this one."""
- def __init__(self):
- """Creates a plugin to append into a map with Map.add_plugin. """
- self.plugin_name = 'Plugin'
- self.object_name = uuid4().hex
- self.env = ENV
-
- def add_to_map(self, map):
- """Adds the plugin on a folium.map object."""
- map.plugins.setdefault(self.plugin_name,[]).append(self)
- self.map = map
-
- def render_html(self, nb):
- """Generates the HTML part of the plugin."""
- return ""
-
- def render_css(self, nb):
- """Generates the CSS part of the plugin."""
- return ""
-
- def render_js(self, nb):
- """Generates the Javascript part of the plugin."""
- return ""
- def render_header(self, nb):
- """Generates the Header part of the plugin."""
- return ""
\ No newline at end of file
diff --git a/folium/plugins/scroll_zoom_toggler.py b/folium/plugins/scroll_zoom_toggler.py
index 7d091baa0d..8a7c473c28 100644
--- a/folium/plugins/scroll_zoom_toggler.py
+++ b/folium/plugins/scroll_zoom_toggler.py
@@ -5,48 +5,54 @@
Adds a button to enable/disable zoom scrolling.
"""
-from .template_plugin import TemplatePlugin
-
-class ScrollZoomToggler(TemplatePlugin):
- """Adds a button to enable/disable zoom scrolling."""
- template = """
- {% set plugin_name = "ScrollZoomToggler" %}
- {% macro css(nb) %}
- #ScrollZoomToggler_{{nb}} {
- position:absolute;
- width:35px;
- bottom:10px;
- height:35px;
- left:10px;
- background-color:#fff;
- text-align:center;
- line-height:35px;
- vertical-align: middle;
- }
- {% endmacro %}
-
- {% macro html(nb) %}
-
- {% endmacro %}
-
- {% macro js(nb) %}
- {% if nb==0 %}
- map.scrollEnabled = true;
-
- var toggleScroll = function() {
- if (map.scrollEnabled) {
- map.scrollEnabled = false;
- map.scrollWheelZoom.disable();
- }
- else {
- map.scrollEnabled = true;
- map.scrollWheelZoom.enable();
- }
- };
-
- toggleScroll();
- {% endif %}
- {% endmacro %}
- """
\ No newline at end of file
+from jinja2 import Template
+
+from folium.element import MacroElement, Figure, Element
+
+class ScrollZoomToggler(MacroElement):
+ def __init__(self):
+ """TODO docstring here.
+ """
+ super(ScrollZoomToggler, self).__init__()
+ self._name = 'ScrollZoomToggler'
+
+ self._template = Template("""
+ {% macro header(this,kwargs) %}
+
+ {% endmacro %}
+
+ {% macro html(this,kwargs) %}
+
+ {% endmacro %}
+
+ {% macro script(this,kwargs) %}
+ {{this._parent.get_name()}}.scrollEnabled = true;
+
+ {{this._parent.get_name()}}.toggleScroll = function() {
+ if (this.scrollEnabled) {
+ this.scrollEnabled = false;
+ this.scrollWheelZoom.disable();
+ }
+ else {
+ this.scrollEnabled = true;
+ this.scrollWheelZoom.enable();
+ }
+ };
+
+ {{this._parent.get_name()}}.toggleScroll();
+ {% endmacro %}
+ """)
\ No newline at end of file
diff --git a/folium/plugins/template_plugin.py b/folium/plugins/template_plugin.py
deleted file mode 100644
index c326ae7e55..0000000000
--- a/folium/plugins/template_plugin.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Template Plugin
-
-A generic class to create plugins based on jinja2 templates.
-"""
-from .plugin import Plugin
-from jinja2 import Template
-from uuid import uuid4
-
-
-class TemplatePlugin(Plugin):
- """Generates a plugin out of a jinja2 template."""
- def __init__(self):
- """Creates a TemplatePlugin plugin to append into a map with
- Map.add_plugin.
-
- Parameters
- ----------
- template: jinja2.Template
- The template that will be used to generate the plugin.
- """
- super(TemplatePlugin, self).__init__()
- assert 'template' in dir(self), 'template attibute does not exist ; you have to define one.'
- self.template = self.template if self.template.__class__ is Template else Template(self.template)
- self.plugin_name = self.template.module.__dict__.get('plugin_name','Unknown_'+uuid4().hex)
-
- def render_header(self, nb):
- """Generates the header part of the plugin."""
- header = self.template.module.__dict__.get('header',None)
- if header is None:
- return super(TemplatePlugin, self).render_header(nb)
- else:
- return header(nb)
-
- def render_css(self, nb):
- """Generates the CSS part of the plugin."""
- css = self.template.module.__dict__.get('css',None)
- if css is None:
- return super(TemplatePlugin, self).render_css(nb)
- else:
- return css(nb)
-
- def render_html(self, nb):
- """Generates the HTML part of the plugin."""
- html = self.template.module.__dict__.get('html',None)
- if html is None:
- return super(TemplatePlugin, self).render_html(nb)
- else:
- return html(nb)
-
- def render_js(self, nb):
- """Generates the Javascript part of the plugin."""
- js = self.template.module.__dict__.get('js',None)
- if js is None:
- return super(TemplatePlugin, self).render_js(nb)
- else:
- return js(nb)
diff --git a/folium/plugins/terminator.py b/folium/plugins/terminator.py
index b9d4fe21ae..69196449fb 100644
--- a/folium/plugins/terminator.py
+++ b/folium/plugins/terminator.py
@@ -5,19 +5,11 @@
Leaflet.Terminator is a simple plug-in to the Leaflet library to overlay day and night regions on maps.
"""
-try:
- from urllib.request import urlopen as _urlopen
-except:
- from urllib import urlopen as _urlopen
+from jinja2 import Template
-from .plugin import Plugin
+from folium.element import JavascriptLink, MacroElement, Figure
-# As LO.Terminator.js is not served on both HTTP and HTTPS, we need to embed it explicitely into the code.
-_request = _urlopen("http://rawgithub.com/joergdietrich/Leaflet.Terminator/master/L.Terminator.js")
-assert _request.getcode()==200, "Error while loading Leaflet.terminator.js"
-_terminator_script = _request.read().decode('utf8')
-
-class Terminator(Plugin):
+class Terminator(MacroElement):
"""Leaflet.Terminator is a simple plug-in to the Leaflet library to overlay day and night regions on maps."""
def __init__(self):
"""Creates a Terminator plugin to append into a map with
@@ -27,12 +19,20 @@ def __init__(self):
----------
"""
super(Terminator, self).__init__()
- self.plugin_name = 'Terminator'
+ self._name = 'Terminator'
+
+ self._template = Template(u"""
+ {% macro script(this, kwargs) %}
+ L.terminator().addTo({{this._parent.get_name()}});
+ {% endmacro %}
+ """)
+ def render(self,**kwargs):
+ super(Terminator,self).render(**kwargs)
- def render_header(self, nb):
- """Generates the header part of the plugin."""
- return '' if nb==0 else ""
+ figure = self.get_root()
+ assert isinstance(figure,Figure), ("You cannot render this Element "
+ "if it's not in a Figure.")
- def render_js(self, nb):
- """Generates the Javascript part of the plugin."""
- return "L.terminator().addTo(map);" if nb==0 else ""
+ figure.header.add_children(\
+ JavascriptLink("https://rawgithub.com/joergdietrich/Leaflet.Terminator/master/L.Terminator.js"),
+ name='markerclusterjs')
diff --git a/folium/plugins/timestamped_geo_json.py b/folium/plugins/timestamped_geo_json.py
index 8c3c0c96bc..a3ad8e6a2b 100644
--- a/folium/plugins/timestamped_geo_json.py
+++ b/folium/plugins/timestamped_geo_json.py
@@ -13,14 +13,14 @@
Eventually, you may have Point features with a "times" property being an array of length 1.
"""
import json
+from jinja2 import Template
-from .plugin import Plugin
+from folium.element import MacroElement, Figure, JavascriptLink, CssLink
-class TimestampedGeoJson(Plugin):
- """Adds a TimestampedGeoJson layer on the map."""
+class TimestampedGeoJson(MacroElement):
def __init__(self, data, transition_time=200, loop=True, auto_play=True):
"""Creates a TimestampedGeoJson plugin to append into a map with
- Map.add_plugin.
+ Map.add_children.
Parameters
----------
@@ -69,8 +69,9 @@ def __init__(self, data, transition_time=200, loop=True, auto_play=True):
"""
super(TimestampedGeoJson, self).__init__()
- self.plugin_name = 'TimestampedGeoJson'
- self.template = self.env.get_template('timestamped_geo_json.tpl')
+ self._name = 'TimestampedGeoJson'
+
+ #self.template = self.env.get_template('timestamped_geo_json.tpl')
if 'read' in dir(data):
self.data = data.read()
elif type(data) is dict:
@@ -81,13 +82,53 @@ def __init__(self, data, transition_time=200, loop=True, auto_play=True):
self.loop = bool(loop)
self.auto_play = bool(auto_play)
- def render_header(self, nb):
- """Generates the header part of the plugin."""
- header = self.template.module.__dict__.get('header',None)
- assert header is not None, "This template must have a 'header' macro."
- return header(nb)
- def render_js(self, nb):
- """Generates the Javascript part of the plugin."""
- js = self.template.module.__dict__.get('js',None)
- assert js is not None, "This template must have a 'js' macro."
- return js(nb,self)
+ self._template = Template("""
+ {% macro script(this, kwargs) %}
+ {{this._parent.get_name()}}.timeDimension = L.timeDimension();
+ {{this._parent.get_name()}}.timeDimensionControl = L.control.timeDimension({
+ position: 'bottomleft',
+ autoPlay: {{'true' if this.auto_play else 'false'}},
+ playerOptions: {
+ transitionTime: {{this.transition_time}},
+ loop: {{'true' if this.loop else 'false'}}}
+ });
+ {{this._parent.get_name()}}.addControl({{this._parent.get_name()}}.timeDimensionControl);
+
+ var {{this.get_name()}} = L.timeDimension.layer.geoJson(
+ L.geoJson({{this.data}}),
+ {updateTimeDimension: true,addlastPoint: true}
+ ).addTo({{this._parent.get_name()}});
+ {% endmacro %}
+ """)
+
+ def render(self, **kwargs):
+ super(TimestampedGeoJson, self).render()
+
+ figure = self.get_root()
+ assert isinstance(figure,Figure), ("You cannot render this Element "
+ "if it's not in a Figure.")
+
+ figure.header.add_children(\
+ JavascriptLink("https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js"),
+ name='jquery2.0.0')
+
+ figure.header.add_children(\
+ JavascriptLink("https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js"),
+ name='jqueryui1.10.2')
+
+ figure.header.add_children(\
+ JavascriptLink("https://raw.githubusercontent.com/nezasa/iso8601-js-period/master/iso8601.min.js"),
+ name='iso8601')
+
+ figure.header.add_children(\
+ JavascriptLink("https://raw.githubusercontent.com/socib/Leaflet.TimeDimension/master/"
+ "dist/leaflet.timedimension.min.js"),
+ name='leaflet.timedimension')
+
+ figure.header.add_children(\
+ CssLink("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/default.min.css"),
+ name='highlight.js_css')
+
+ figure.header.add_children(\
+ CssLink("http://apps.socib.es/Leaflet.TimeDimension/dist/leaflet.timedimension.control.min.css"),
+ name='leaflet.timedimension_css')
diff --git a/folium/plugins/timestamped_geo_json.tpl b/folium/plugins/timestamped_geo_json.tpl
deleted file mode 100644
index e63c821963..0000000000
--- a/folium/plugins/timestamped_geo_json.tpl
+++ /dev/null
@@ -1,31 +0,0 @@
-{% macro header(nb) %}
- {% if nb==0 %}
-
-
-
-
-
-
-
-
-
-
-
-
- {% endif %}
-{% endmacro %}
-
-{% macro js(nb,self) %}
- {% if nb==0 %}
- map.timeDimension = L.timeDimension();
- map.timeDimensionControl = L.control.timeDimension({
- position: 'bottomleft',
- autoPlay: {{'true' if self.auto_play else 'false'}},
- playerOptions: {transitionTime: {{self.transition_time}},loop: {{'true' if self.loop else 'false'}}}
- });
- map.addControl(map.timeDimensionControl);
- {% endif %}
-
- var tsgeojson_{{nb}} = L.timeDimension.layer.geoJson(L.geoJson({{self.data}}),
- {updateTimeDimension: true,addlastPoint: true}).addTo(map);
-{% endmacro %}
\ No newline at end of file
diff --git a/folium/templates/click_for_marker.js b/folium/templates/click_for_marker.js
index 2151869468..2dd5f8021c 100644
--- a/folium/templates/click_for_marker.js
+++ b/folium/templates/click_for_marker.js
@@ -1,9 +1,9 @@
function newMarker(e){
- var new_mark = L.marker().setLatLng(e.latlng).addTo(map);
+ var new_mark = L.marker().setLatLng(e.latlng).addTo({{map}});
new_mark.dragging.enable();
- new_mark.on('dblclick', function(e){map.removeLayer(e.target)})
+ new_mark.on('dblclick', function(e){ {{map}}.removeLayer(e.target)})
var lat = e.latlng.lat.toFixed(4),
lng = e.latlng.lng.toFixed(4);
new_mark.bindPopup({{ popup }});
};
-map.on('click', newMarker)
\ No newline at end of file
+{{map}}.on('click', newMarker)
\ No newline at end of file
diff --git a/folium/templates/color_scale.js b/folium/templates/color_scale.js
new file mode 100644
index 0000000000..58f01b5c3c
--- /dev/null
+++ b/folium/templates/color_scale.js
@@ -0,0 +1,55 @@
+{% macro script(this, kwargs) %}
+ var {{this.get_name()}} = {};
+
+ {%if this.color_range %}
+ {{this.get_name()}}.color = d3.scale.threshold()
+ .domain({{this.color_domain}})
+ .range({{this.color_range}});
+ {%else%}
+ {{this.get_name()}}.color = d3.scale.threshold()
+ .domain([{{ this.color_domain[0] }}, {{ this.color_domain[-1] }}])
+ .range(['{{ this.fill_color }}', '{{ this.fill_color }}']);
+ {%endif%}
+
+ {{this.get_name()}}.x = d3.scale.linear()
+ .domain([{{ this.color_domain[0] }}, {{ this.color_domain[-1] }}])
+ .range([0, 400]);
+
+ {{this.get_name()}}.legend = L.control({position: 'topright'});
+ {{this.get_name()}}.legend.onAdd = function (map) {var div = L.DomUtil.create('div', 'legend'); return div};
+ {{this.get_name()}}.legend.addTo({{this._parent.get_name()}});
+
+ {{this.get_name()}}.xAxis = d3.svg.axis()
+ .scale({{this.get_name()}}.x)
+ .orient("top")
+ .tickSize(1)
+ .tickValues({{ this.tick_labels }});
+
+ {{this.get_name()}}.svg = d3.select(".legend.leaflet-control").append("svg")
+ .attr("id", 'legend')
+ .attr("width", 450)
+ .attr("height", 40);
+
+ {{this.get_name()}}.g = {{this.get_name()}}.svg.append("g")
+ .attr("class", "key")
+ .attr("transform", "translate(25,16)");
+
+ {{this.get_name()}}.g.selectAll("rect")
+ .data({{this.get_name()}}.color.range().map(function(d, i) {
+ return {
+ x0: i ? {{this.get_name()}}.x({{this.get_name()}}.color.domain()[i - 1]) : {{this.get_name()}}.x.range()[0],
+ x1: i < {{this.get_name()}}.color.domain().length ? {{this.get_name()}}.x({{this.get_name()}}.color.domain()[i]) : {{this.get_name()}}.x.range()[1],
+ z: d
+ };
+ }))
+ .enter().append("rect")
+ .attr("height", 10)
+ .attr("x", function(d) { return d.x0; })
+ .attr("width", function(d) { return d.x1 - d.x0; })
+ .style("fill", function(d) { return d.z; });
+
+ {{this.get_name()}}.g.call({{this.get_name()}}.xAxis).append("text")
+ .attr("class", "caption")
+ .attr("y", 21)
+ .text('{{ this.caption }}');
+{% endmacro %}
\ No newline at end of file
diff --git a/folium/templates/d3_threshold.js b/folium/templates/d3_threshold.js
index 2009006205..de94a24f6a 100644
--- a/folium/templates/d3_threshold.js
+++ b/folium/templates/d3_threshold.js
@@ -1,3 +1,3 @@
-var color = d3.scale.threshold()
+{{ this.get_name() }}.color = d3.scale.threshold()
.domain({{ domain }})
.range({{ range }});
\ No newline at end of file
diff --git a/folium/templates/fit_bounds.js b/folium/templates/fit_bounds.js
index f9d7430fe1..70429698bf 100644
--- a/folium/templates/fit_bounds.js
+++ b/folium/templates/fit_bounds.js
@@ -5,7 +5,7 @@ var autobounds = L.featureGroup({{ features }}).getBounds()
{% endif %}
{% endif %}
{% if bounds %}
-map.fitBounds({{ bounds }},
+{{this._parent.get_name()}}.fitBounds({{ bounds }},
{{ fit_bounds_options }}
);
{% endif %}
diff --git a/folium/templates/fol_template.html b/folium/templates/fol_template.html
index 9306c2d619..3a2d0fa6b0 100644
--- a/folium/templates/fol_template.html
+++ b/folium/templates/fol_template.html
@@ -1,40 +1,22 @@
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
- {% for name, plugin in plugins.items() %}
- {% set plugin_nb = 0 %}
- {% for plugin_object in plugin %}
- {{plugin_object.render_header(plugin_nb)}}
- {% set plugin_nb = plugin_nb +1 %}
- {% endfor %}
- {% endfor %}
-
- {{ dvf_js }}
- {{ d3 }}
- {{ vega }}
- {{ jquery }}
+
+
+
+
+
+
+
+
+
+
+
-
+
- {% for name, plugin in plugins.items() %}
- {% set plugin_nb = 0 %}
- {% for plugin_object in plugin %}
- {{plugin_object.render_html(plugin_nb)}}
- {% set plugin_nb = plugin_nb +1 %}
- {% endfor %}
- {% endfor %}
+
-
+
-