diff --git a/dist/esri-leaflet-renderers-src.js b/dist/esri-leaflet-renderers-src.js new file mode 100644 index 0000000..f9810ee --- /dev/null +++ b/dist/esri-leaflet-renderers-src.js @@ -0,0 +1,1038 @@ +/*! esri-leaflet-renderers - v1.0.0 - 2015-09-08 +* Copyright (c) 2015 Environmental Systems Research Institute, Inc. +* Apache 2.0 License */ + +var EsriLeafletRenderers = { + VERSION: '0.0.1-beta.3' +}; + +// attach to the L.esri global if we can +if(typeof window !== 'undefined' && window.L && window.L.esri) { + window.L.esri.Renderers = EsriLeafletRenderers; +} + +// We do not have an 'Esri' variable e.g loading this file directly from source define 'Esri' +if(!Esri){ + var Esri = window.L.esri; +} + + +EsriLeafletRenderers.Symbol = L.Class.extend({ + + initialize: function(symbolJson){ + this._symbolJson = symbolJson; + this.val = null; + this._styles = {}; + this._isDefault = false; + }, + + //the geojson values returned are in points + pixelValue: function(pointValue){ + return pointValue * 1.333; + }, + + //color is an array [r,g,b,a] + colorValue: function(color){ + return 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')'; + }, + + alphaValue: function(color){ + return color[3] / 255.0; + }, + + getSize: function(feature, sizeInfo) { + + var attr = feature.properties, + field = sizeInfo.field, + size = 0, + featureValue = null; + + if(field){ + featureValue = attr[field]; + var minSize = sizeInfo.minSize, + maxSize = sizeInfo.maxSize, + minDataValue = sizeInfo.minDataValue, + maxDataValue = sizeInfo.maxDataValue, + featureRatio, + normField = sizeInfo.normalizationField, + normValue = attr ? parseFloat(attr[normField]) : undefined; + + if(featureValue === null || (normField && ((isNaN(normValue) || normValue === 0)))){ + return null; + } + + if(!isNaN(normValue)){ + featureValue /= normValue; + } + + if(minSize !== null && maxSize !== null && minDataValue !== null && maxDataValue !== null){ + if(featureValue <= minDataValue){ + size = minSize; + } + else if(featureValue >= maxDataValue){ + size = maxSize; + } + else{ + featureRatio = (featureValue - minDataValue) / (maxDataValue - minDataValue); + size = minSize + (featureRatio * (maxSize - minSize)); + } + } + size = isNaN(size) ? 0 : size; + } + return size; + }, + + getColor: function(feature, colorInfo) { + //required information to get color + if(!(feature.properties && colorInfo && colorInfo.field && colorInfo.stops)){ + return null; + } + + var attr = feature.properties; + var featureValue = attr[colorInfo.field]; + var lowerBoundColor, upperBoundColor, lowerBound, upperBound; + var normField = colorInfo.normalizationField; + var normValue = attr ? parseFloat(attr[normField]) : undefined; + if(featureValue === null || (normField && ((isNaN(normValue) || normValue === 0)))){ + return null; + } + + if(!isNaN(normValue)){ + featureValue /= normValue; + } + + if(featureValue <= colorInfo.stops[0].value){ + return colorInfo.stops[0].color; + } + var lastStop = colorInfo.stops[colorInfo.stops.length - 1]; + if(featureValue >= lastStop.value){ + return lastStop.color; + } + + //go through the stops to find min and max + for(var i=0; i featureValue){ + upperBoundColor = stopInfo.color; + upperBound = stopInfo.value; + break; + } + } + + //feature falls between two stops, interplate the colors + if(!isNaN(lowerBound) && !isNaN(upperBound)){ + var range = upperBound - lowerBound; + if(range > 0){ + //more weight the further it is from the lower bound + var upperBoundColorWeight = (featureValue - lowerBound) / range; + if(upperBoundColorWeight){ + //more weight the further it is from the upper bound + var lowerBoundColorWeight = (upperBound - featureValue) / range; + if(lowerBoundColorWeight){ + + //interpolate the lower and upper bound color by applying the + //weights to each of the rgba colors and adding them together + var interpolatedColor = []; + for(var j=0; j<4; j++){ + interpolatedColor[j] = Math.round(lowerBoundColor[j] * lowerBoundColorWeight + upperBoundColor[j] * upperBoundColorWeight); + } + return interpolatedColor; + } else { + //no difference between featureValue and upperBound, 100% of upperBoundColor + return upperBoundColor; + } + } else { + //no difference between featureValue and lowerBound, 100% of lowerBoundColor + return lowerBoundColor; + } + } + } + //if we get to here, none of the cases apply so return null + return null; + } +}); + + +EsriLeafletRenderers.PointSymbol = EsriLeafletRenderers.Symbol.extend({ + statics: { + MARKERTYPES: ['esriSMSCircle','esriSMSCross', 'esriSMSDiamond', 'esriSMSSquare', 'esriSMSX', 'esriPMS'] + }, + initialize: function(symbolJson, options){ + EsriLeafletRenderers.Symbol.prototype.initialize.call(this, symbolJson); + if(options) { + this.serviceUrl = options.url; + } + if(symbolJson){ + if(symbolJson.type === 'esriPMS'){ + var url = this.serviceUrl + 'images/' + this._symbolJson.url; + this._iconUrl = options && options.token ? url + '?token=' + options.token : url; + //leaflet does not allow resizing icons so keep a hash of different + //icon sizes to try and keep down on the number of icons created + this._icons = {}; + //create base icon + this.icon = this._createIcon(this._symbolJson); + } else { + this._fillStyles(); + } + } + }, + + _fillStyles: function(){ + if(this._symbolJson.outline && this._symbolJson.size > 0){ + this._styles.stroke = true; + this._styles.weight = this.pixelValue(this._symbolJson.outline.width); + this._styles.color = this.colorValue(this._symbolJson.outline.color); + this._styles.opacity = this.alphaValue(this._symbolJson.outline.color); + }else{ + this._styles.stroke = false; + } + if(this._symbolJson.color){ + this._styles.fillColor = this.colorValue(this._symbolJson.color); + this._styles.fillOpacity = this.alphaValue(this._symbolJson.color); + } else { + this._styles.fillOpacity = 0; + } + + if(this._symbolJson.style === 'esriSMSCircle'){ + this._styles.radius = this.pixelValue(this._symbolJson.size) / 2.0; + } + }, + + _createIcon: function(options){ + var width = this.pixelValue(options.width); + var height = width; + if(options.height){ + height = this.pixelValue(options.height); + } + var xOffset = width / 2.0; + var yOffset = height / 2.0; + + + if(options.xoffset){ + xOffset += this.pixelValue(options.xoffset); + } + if(options.yoffset){ + yOffset += this.pixelValue(options.yoffset); + } + + var icon = L.icon({ + iconUrl: this._iconUrl, + iconSize: [width, height], + iconAnchor: [xOffset, yOffset] + }); + this._icons[options.width.toString()] = icon; + return icon; + }, + + _getIcon: function(size) { + //check to see if it is already created by size + var icon = this._icons[size.toString()]; + if(!icon){ + icon = this._createIcon({width: size}); + } + return icon; + }, + + pointToLayer: function(geojson, latlng, visualVariables){ + var size = this._symbolJson.size || this._symbolJson.width; + if(!this._isDefault){ + if( visualVariables.sizeInfo) { + var calculatedSize = this.getSize(geojson, visualVariables.sizeInfo); + if (calculatedSize) { + size = calculatedSize; + } + } + if(visualVariables.colorInfo){ + var color = this.getColor(geojson, visualVariables.colorInfo); + if(color){ + this._styles.fillColor = this.colorValue(color); + this._styles.fillOpacity = this.alphaValue(color); + } + } + } + + if (this._symbolJson.type === 'esriPMS'){ + return L.marker(latlng, {icon: this._getIcon(size)}); + } + size = this.pixelValue(size); + + switch(this._symbolJson.style){ + case 'esriSMSSquare': + return EsriLeafletRenderers.squareMarker(latlng, size, this._styles); + case 'esriSMSDiamond': + return EsriLeafletRenderers.diamondMarker(latlng, size, this._styles); + case 'esriSMSCross': + return EsriLeafletRenderers.crossMarker(latlng, size, this._styles); + case 'esriSMSX': + return EsriLeafletRenderers.xMarker(latlng, size, this._styles); + } + this._styles.radius = size / 2.0; + return L.circleMarker(latlng, this._styles); + } +}); +EsriLeafletRenderers.pointSymbol = function(symbolJson, options){ + return new EsriLeafletRenderers.PointSymbol(symbolJson, options); +}; + + +EsriLeafletRenderers.LineSymbol = EsriLeafletRenderers.Symbol.extend({ + statics: { + //Not implemented 'esriSLSNull' + LINETYPES: ['esriSLSDash','esriSLSDot','esriSLSDashDotDot','esriSLSDashDot','esriSLSSolid'] + }, + initialize: function(symbolJson){ + EsriLeafletRenderers.Symbol.prototype.initialize.call(this, symbolJson); + this._fillStyles(); + }, + + _fillStyles: function(){ + //set the defaults that show up on arcgis online + this._styles.lineCap = 'butt'; + this._styles.lineJoin = 'miter'; + this._styles.fill = false; + + if (!this._symbolJson){ + return; + } + + if(this._symbolJson.color ){ + this._styles.color = this.colorValue(this._symbolJson.color); + this._styles.opacity = this.alphaValue(this._symbolJson.color); + } + + if(this._symbolJson.width){ + this._styles.weight = this.pixelValue(this._symbolJson.width); + + var dashValues = []; + + switch(this._symbolJson.style){ + case 'esriSLSDash': + dashValues = [4,3]; + break; + case 'esriSLSDot': + dashValues = [1,3]; + break; + case 'esriSLSDashDot': + dashValues = [8,3,1,3]; + break; + case 'esriSLSDashDotDot': + dashValues = [8,3,1,3,1,3]; + break; + } + + //use the dash values and the line weight to set dash array + if (dashValues.length > 0) { + for (var i = 0; i < dashValues.length; i++){ + dashValues[i] *= this._styles.weight; + } + + this._styles.dashArray = dashValues.join(','); + } + } + }, + + style: function(feature, visualVariables){ + if(!this._isDefault && visualVariables){ + if(visualVariables.sizeInfo){ + var calculatedSize = this.pixelValue(this.getSize(feature, visualVariables.sizeInfo)); + if (calculatedSize) { + this._styles.weight = calculatedSize; + } + } + if(visualVariables.colorInfo){ + var color = this.getColor(feature, visualVariables.colorInfo); + if(color){ + this._styles.color = this.colorValue(color); + this._styles.opacity = this.alphaValue(color); + } + } + } + return this._styles; + } +}); +EsriLeafletRenderers.lineSymbol = function(symbolJson){ + return new EsriLeafletRenderers.LineSymbol(symbolJson); +}; + + +EsriLeafletRenderers.PolygonSymbol = EsriLeafletRenderers.Symbol.extend({ + statics: { + //not implemented: 'esriSFSBackwardDiagonal','esriSFSCross','esriSFSDiagonalCross','esriSFSForwardDiagonal','esriSFSHorizontal','esriSFSNull','esriSFSVertical' + POLYGONTYPES: ['esriSFSSolid'] + }, + initialize: function(symbolJson){ + EsriLeafletRenderers.Symbol.prototype.initialize.call(this, symbolJson); + if (symbolJson){ + this._lineStyles = EsriLeafletRenderers.lineSymbol(symbolJson.outline).style(); + this._fillStyles(); + } + }, + + _fillStyles: function(){ + if (this._lineStyles) { + if (this._lineStyles.weight === 0){ + //when weight is 0, setting the stroke to false can still look bad + //(gaps between the polygons) + this._styles.stroke = false; + } else { + //copy the line symbol styles into this symbol's styles + for (var styleAttr in this._lineStyles){ + this._styles[styleAttr] = this._lineStyles[styleAttr]; + } + } + } + + //set the fill for the polygon + if (this._symbolJson) { + if (this._symbolJson.color && + //don't fill polygon if type is not supported + EsriLeafletRenderers.PolygonSymbol.POLYGONTYPES.indexOf(this._symbolJson.style >= 0)) { + + this._styles.fill = true; + this._styles.fillColor = this.colorValue(this._symbolJson.color); + this._styles.fillOpacity = this.alphaValue(this._symbolJson.color); + } else { + this._styles.fill = false; + this._styles.fillOpacity = 0; + } + } + + }, + + style: function(feature, visualVariables) { + if(!this._isDefault && visualVariables && visualVariables.colorInfo){ + var color = this.getColor(feature, visualVariables.colorInfo); + if(color){ + this._styles.fillColor = this.colorValue(color); + this._styles.fillOpacity = this.alphaValue(color); + } + } + return this._styles; + } +}); +EsriLeafletRenderers.polygonSymbol = function(symbolJson){ + return new EsriLeafletRenderers.PolygonSymbol(symbolJson); +}; + + +EsriLeafletRenderers.Renderer = L.Class.extend({ + + options: { + proportionalPolygon: false, + clickable: true + }, + + initialize: function(rendererJson, options){ + this._rendererJson = rendererJson; + this._pointSymbols = false; + this._symbols = []; + this._visualVariables = this._parseVisualVariables(rendererJson.visualVariables); + L.Util.setOptions(this, options); + }, + + _parseVisualVariables: function(visualVariables){ + var visVars = {}; + if (visualVariables) { + for (var i = 0; i < visualVariables.length; i++){ + visVars[visualVariables[i].type] = visualVariables[i]; + } + } + return visVars; + }, + + _createDefaultSymbol: function(){ + if(this._rendererJson.defaultSymbol){ + this._defaultSymbol = this._newSymbol(this._rendererJson.defaultSymbol); + this._defaultSymbol._isDefault = true; + } + }, + + _newSymbol: function(symbolJson){ + if(symbolJson.type === 'esriSMS' || symbolJson.type === 'esriPMS'){ + this._pointSymbols = true; + return EsriLeafletRenderers.pointSymbol(symbolJson, this.options); + } + if(symbolJson.type === 'esriSLS'){ + return EsriLeafletRenderers.lineSymbol(symbolJson); + } + if(symbolJson.type === 'esriSFS'){ + return EsriLeafletRenderers.polygonSymbol(symbolJson); + } + }, + + _getSymbol: function(){ + //override + }, + + attachStylesToLayer: function(layer){ + if(this._pointSymbols){ + layer.options.pointToLayer = L.Util.bind(this.pointToLayer, this); + } else { + layer.options.style = L.Util.bind(this.style, this); + } + }, + + pointToLayer: function(geojson, latlng){ + var sym = this._getSymbol(geojson); + if(sym && sym.pointToLayer){ + return sym.pointToLayer(geojson, latlng, this._visualVariables); + } + //invisible symbology + return L.circleMarker(latlng, {radius: 0, opacity: 0}); + }, + + style: function(feature){ + //find the symbol to represent this feature + var sym = this._getSymbol(feature); + if(sym){ + return sym.style(feature, this._visualVariables); + }else{ + //invisible symbology + return {opacity: 0, fillOpacity: 0}; + } + } +}); + + +EsriLeafletRenderers.SimpleRenderer = EsriLeafletRenderers.Renderer.extend({ + + initialize: function(rendererJson, options){ + EsriLeafletRenderers.Renderer.prototype.initialize.call(this, rendererJson, options); + this._createSymbol(); + }, + + _createSymbol: function(){ + if(this._rendererJson.symbol){ + this._symbols.push(this._newSymbol(this._rendererJson.symbol)); + } + }, + + _getSymbol: function(){ + return this._symbols[0]; + } +}); + +EsriLeafletRenderers.simpleRenderer = function(rendererJson, options){ + return new EsriLeafletRenderers.SimpleRenderer(rendererJson, options); +}; + + +EsriLeafletRenderers.ClassBreaksRenderer = EsriLeafletRenderers.Renderer.extend({ + + initialize: function(rendererJson, options){ + EsriLeafletRenderers.Renderer.prototype.initialize.call(this, rendererJson, options); + this._field = this._rendererJson.field; + if (this._rendererJson.normalizationType && this._rendererJson.normalizationType === 'esriNormalizeByField'){ + this._normalizationField = this._rendererJson.normalizationField; + } + this._createSymbols(); + }, + + _createSymbols: function(){ + var symbol, + classbreaks = this._rendererJson.classBreakInfos; + + this._symbols = []; + + //create a symbol for each class break + for (var i = classbreaks.length - 1; i >= 0; i--){ + if(this.options.proportionalPolygon && this._rendererJson.backgroundFillSymbol){ + symbol = this._newSymbol(this._rendererJson.backgroundFillSymbol); + } else { + symbol = this._newSymbol(classbreaks[i].symbol); + } + symbol.val = classbreaks[i].classMaxValue; + this._symbols.push(symbol); + } + //sort the symbols in ascending value + this._symbols.sort(function(a, b){ + return a.val > b.val ? 1 : -1; + }); + this._createDefaultSymbol(); + this._maxValue = this._symbols[this._symbols.length - 1].val; + }, + + _getSymbol: function(feature){ + var val = feature.properties[this._field]; + if (this._normalizationField){ + var normValue = feature.properties[this._normalizationField]; + if (!isNaN(normValue) && normValue !== 0) { + val = val / normValue; + } else { + return this._defaultSymbol; + } + } + + if(val > this._maxValue){ + return this._defaultSymbol; + } + var symbol = this._symbols[0]; + for (var i = this._symbols.length - 1; i >= 0; i--){ + if(val > this._symbols[i].val){ + break; + } + symbol = this._symbols[i]; + } + return symbol; + } +}); + +EsriLeafletRenderers.classBreaksRenderer = function(rendererJson, options){ + return new EsriLeafletRenderers.ClassBreaksRenderer(rendererJson, options); +}; + + +EsriLeafletRenderers.UniqueValueRenderer = EsriLeafletRenderers.Renderer.extend({ + + initialize: function(rendererJson, options){ + EsriLeafletRenderers.Renderer.prototype.initialize.call(this, rendererJson, options); + + //what to do when there are other fields? + this._field = this._rendererJson.field1; + this._createSymbols(); + }, + + _createSymbols: function(){ + var symbol, uniques = this._rendererJson.uniqueValueInfos; + + //create a symbol for each unique value + for (var i = uniques.length - 1; i >= 0; i--){ + symbol = this._newSymbol(uniques[i].symbol); + symbol.val = uniques[i].value; + this._symbols.push(symbol); + } + this._createDefaultSymbol(); + }, + + /* jshint ignore:start */ + _getSymbol: function(feature){ + var val = feature.properties[this._field]; + var symbol = this._defaultSymbol; + for (var i = this._symbols.length - 1; i >= 0; i--){ + //using the === operator does not work if the field + //of the unique renderer is not a string + if(this._symbols[i].val == val){ + symbol = this._symbols[i]; + } + } + return symbol; + } + /* jshint ignore:end */ +}); + +EsriLeafletRenderers.uniqueValueRenderer = function(rendererJson, options){ + return new EsriLeafletRenderers.UniqueValueRenderer(rendererJson, options); +}; + + +EsriLeafletRenderers.SquareMarker = L.Path.extend({ + options: { + fill: true + }, + + initialize: function(center, size, options){ + L.Path.prototype.initialize.call(this, options); + this._size = size; + this._center = center; + }, + + projectLatlngs: function(){ + this._point = this._map.latLngToLayerPoint(this._center); + }, + + getPathString: function(){ + if (!this._map){ + return ''; + } + + var center = this._point, + offset = this._size / 2.0; + + if(L.Path.VML){ + center._round(); + offset = Math.round(offset); + } + + var str = 'M' + (center.x + offset) + ',' + (center.y + offset) + + 'L' + (center.x - offset) + ',' + (center.y + offset) + + 'L' + (center.x - offset) + ',' + (center.y - offset) + + 'L' + (center.x + offset) + ',' + (center.y - offset); + + return str + (L.Browser.svg ? 'z' : 'x'); + }, + + setLatLng: function(latlng){ + this._center = latlng; + return this.redraw(); + }, + + getLatLng: function(){ + return L.latLng(this._center); + }, + + getSize: function(){ + return this._size; + }, + + setSize: function(size){ + this._size = size; + return this.redraw(); + } +}); + +EsriLeafletRenderers.squareMarker = function(center, size, options){ + return new EsriLeafletRenderers.SquareMarker(center, size, options); +}; + + +EsriLeafletRenderers.DiamondMarker = L.Path.extend({ + options: { + fill: true + }, + + initialize: function(center, size, options){ + L.Path.prototype.initialize.call(this, options); + this._size = size; + this._center = center; + }, + + projectLatlngs: function(){ + this._point = this._map.latLngToLayerPoint(this._center); + }, + + getPathString: function(){ + if (!this._map){ + return ''; + } + + var center = this._point, + offset = this._size / 2.0; + + if(L.Path.VML){ + center._round(); + offset = Math.round(offset); + } + + var str = 'M' + center.x + ',' + (center.y + offset) + + 'L' + (center.x - offset) + ',' + center.y + + 'L' + center.x + ',' + (center.y - offset) + + 'L' + (center.x + offset) + ',' + center.y; + + return str + (L.Browser.svg ? 'z' : 'x'); + }, + + setLatLng: function(latlng){ + this._center = latlng; + return this.redraw(); + }, + + getLatLng: function(){ + return L.latLng(this._center); + }, + + getSize: function(){ + return this._size; + }, + + setSize: function(size){ + this._size = size; + return this.redraw(); + } +}); + +EsriLeafletRenderers.diamondMarker = function(center, size, options){ + return new EsriLeafletRenderers.DiamondMarker(center, size, options); +}; + + +EsriLeafletRenderers.CrossMarker = L.Path.extend({ + initialize: function (center, size, options){ + L.Path.prototype.initialize.call(this, options); + this._size = size; + this._center = center; + }, + + projectLatlngs: function(){ + this._point = this._map.latLngToLayerPoint(this._center); + }, + + getPathString: function(){ + if (!this._map){ + return ''; + } + + var center = this._point, + offset = this._size / 2.0; + + if(L.Path.VML){ + center._round(); + offset = Math.round(offset); + } + + return 'M' + center.x + ',' + (center.y + offset) + + 'L' + center.x + ',' + (center.y - offset) + + 'M' + (center.x - offset) + ',' + center.y + + 'L' + (center.x + offset) + ',' + center.y; + }, + + setLatLng: function(latlng){ + this._center = latlng; + return this.redraw(); + }, + + getLatLng: function(){ + return L.latLng(this._center); + }, + + getSize: function(){ + return this._size; + }, + + setSize: function(size){ + this._size = size; + return this.redraw(); + } +}); + +EsriLeafletRenderers.crossMarker = function(center, size, options){ + return new EsriLeafletRenderers.CrossMarker(center, size, options); +}; + + +EsriLeafletRenderers.XMarker = L.Path.extend({ + initialize: function(center, size, options){ + L.Path.prototype.initialize.call(this, options); + this._size = size; + this._center = center; + }, + + projectLatlngs: function(){ + this._point = this._map.latLngToLayerPoint(this._center); + }, + + getPathString: function(){ + if (!this._map){ + return ''; + } + + var center = this._point, + offset = this._size / 2.0; + + if(L.Path.VML){ + center._round(); + offset = Math.round(offset); + } + + return 'M' + (center.x + offset) + ',' + (center.y + offset) + + 'L' + (center.x - offset) + ',' + (center.y - offset) + + 'M' + (center.x - offset) + ',' + (center.y + offset) + + 'L' + (center.x + offset) + ',' + (center.y - offset); + }, + + setLatLng: function(latlng){ + this._center = latlng; + return this.redraw(); + }, + + getLatLng: function(){ + return L.latLng(this._center); + }, + + getSize: function(){ + return this._size; + }, + + setSize: function(size){ + this._size = size; + return this.redraw(); + } +}); + +EsriLeafletRenderers.xMarker = function(center, size, options){ + return new EsriLeafletRenderers.XMarker(center, size, options); +}; + + +Esri.FeatureLayer.addInitHook(function() { + var oldOnAdd = L.Util.bind(this.onAdd, this); + var oldUnbindPopup = L.Util.bind(this.unbindPopup, this); + var oldOnRemove = L.Util.bind(this.onRemove, this); + L.Util.bind(this.createNewLayer, this); + + this.metadata(function(error, response) { + if(error) { + return; + } + if(response && response.drawingInfo && !this.options.style){ + this._setRenderers(response); + } + + this._metadataLoaded = true; + if(this._loadedMap){ + oldOnAdd(this._loadedMap); + this._addPointLayer(this._loadedMap); + } + }, this); + + this.onAdd = function(map){ + + this._loadedMap = map; + if(this._metadataLoaded){ + oldOnAdd(this._loadedMap); + this._addPointLayer(this._loadedMap); + } + }; + + this.onRemove = function(map){ + oldOnRemove(map); + if(this._pointLayer){ + var pointLayers = this._pointLayer.getLayers(); + for(var i in pointLayers){ + map.removeLayer(pointLayers[i]); + } + } + }; + + this.unbindPopup = function(){ + oldUnbindPopup(); + if(this._pointLayer){ + var pointLayers = this._pointLayer.getLayers(); + for(var i in pointLayers){ + pointLayers[i].unbindPopup(); + } + } + }; + + this._addPointLayer = function(map){ + if(this._pointLayer){ + this._pointLayer.addTo(map); + this._pointLayer.bringToFront(); + } + }; + + this._createPointLayer = function(){ + if(!this._pointLayer){ + this._pointLayer = L.geoJson(); + //store the feature ids that have already been added to the map + this._pointLayerIds = {}; + + if(this._popup){ + var popupFunction = function (feature, layer) { + layer.bindPopup(this._popup(feature, layer), this._popupOptions); + }; + this._pointLayer.options.onEachFeature = L.Util.bind(popupFunction, this); + } + } + }; + + this.createNewLayer = function(geojson){ + + var fLayer = L.GeoJSON.geometryToLayer(geojson, this.options.pointToLayer, L.GeoJSON.coordsToLatLng, this.options); + + //add a point layer when the polygon is represented as proportional marker symbols + if(this._hasProportionalSymbols){ + var centroid = this.getPolygonCentroid(geojson.geometry.coordinates); + if(!(isNaN(centroid[0]) || isNaN(centroid[0]))){ + this._createPointLayer(); + + var featureId = geojson.id.toString(); + //only add the feature if it does not already exist on the map + if(!this._pointLayerIds[featureId]){ + var pointjson = this.getPointJson(geojson, centroid); + + this._pointLayer.addData(pointjson); + this._pointLayerIds[featureId] = true; + } + + this._pointLayer.bringToFront(); + } + } + return fLayer; + }; + + this.getPolygonCentroid = function(coordinates){ + var pts = coordinates[0][0]; + if(pts.length === 2){ + pts = coordinates[0]; + } + + + var twicearea=0, + x=0, y=0, + nPts = pts.length, + p1, p2, f; + + for (var i=0, j=nPts-1 ;i=f?e=h:f>=k?e=i:(g=(f-j)/(k-j),e=h+g*(i-h))),e=isNaN(e)?0:e}return e},getColor:function(a,b){if(!(a.properties&&b&&b.field&&b.stops))return null;var c,d,e,f,g=a.properties,h=g[b.field],i=b.normalizationField,j=g?parseFloat(g[i]):void 0;if(null===h||i&&(isNaN(j)||0===j))return null;if(isNaN(j)||(h/=j),h<=b.stops[0].value)return b.stops[0].color;var k=b.stops[b.stops.length-1];if(h>=k.value)return k.color;for(var l=0;lh){d=m.color,f=m.value;break}}if(!isNaN(e)&&!isNaN(f)){var n=f-e;if(n>0){var o=(h-e)/n;if(o){var p=(f-h)/n;if(p){for(var q=[],r=0;4>r;r++)q[r]=Math.round(c[r]*p+d[r]*o);return q}return d}return c}}return null}}),EsriLeafletRenderers.PointSymbol=EsriLeafletRenderers.Symbol.extend({statics:{MARKERTYPES:["esriSMSCircle","esriSMSCross","esriSMSDiamond","esriSMSSquare","esriSMSX","esriPMS"]},initialize:function(a,b){if(EsriLeafletRenderers.Symbol.prototype.initialize.call(this,a),b&&(this.serviceUrl=b.url),a)if("esriPMS"===a.type){var c=this.serviceUrl+"images/"+this._symbolJson.url;this._iconUrl=b&&b.token?c+"?token="+b.token:c,this._icons={},this.icon=this._createIcon(this._symbolJson)}else this._fillStyles()},_fillStyles:function(){this._symbolJson.outline&&this._symbolJson.size>0?(this._styles.stroke=!0,this._styles.weight=this.pixelValue(this._symbolJson.outline.width),this._styles.color=this.colorValue(this._symbolJson.outline.color),this._styles.opacity=this.alphaValue(this._symbolJson.outline.color)):this._styles.stroke=!1,this._symbolJson.color?(this._styles.fillColor=this.colorValue(this._symbolJson.color),this._styles.fillOpacity=this.alphaValue(this._symbolJson.color)):this._styles.fillOpacity=0,"esriSMSCircle"===this._symbolJson.style&&(this._styles.radius=this.pixelValue(this._symbolJson.size)/2)},_createIcon:function(a){var b=this.pixelValue(a.width),c=b;a.height&&(c=this.pixelValue(a.height));var d=b/2,e=c/2;a.xoffset&&(d+=this.pixelValue(a.xoffset)),a.yoffset&&(e+=this.pixelValue(a.yoffset));var f=L.icon({iconUrl:this._iconUrl,iconSize:[b,c],iconAnchor:[d,e]});return this._icons[a.width.toString()]=f,f},_getIcon:function(a){var b=this._icons[a.toString()];return b||(b=this._createIcon({width:a})),b},pointToLayer:function(a,b,c){var d=this._symbolJson.size||this._symbolJson.width;if(!this._isDefault){if(c.sizeInfo){var e=this.getSize(a,c.sizeInfo);e&&(d=e)}if(c.colorInfo){var f=this.getColor(a,c.colorInfo);f&&(this._styles.fillColor=this.colorValue(f),this._styles.fillOpacity=this.alphaValue(f))}}if("esriPMS"===this._symbolJson.type)return L.marker(b,{icon:this._getIcon(d)});switch(d=this.pixelValue(d),this._symbolJson.style){case"esriSMSSquare":return EsriLeafletRenderers.squareMarker(b,d,this._styles);case"esriSMSDiamond":return EsriLeafletRenderers.diamondMarker(b,d,this._styles);case"esriSMSCross":return EsriLeafletRenderers.crossMarker(b,d,this._styles);case"esriSMSX":return EsriLeafletRenderers.xMarker(b,d,this._styles)}return this._styles.radius=d/2,L.circleMarker(b,this._styles)}}),EsriLeafletRenderers.pointSymbol=function(a,b){return new EsriLeafletRenderers.PointSymbol(a,b)},EsriLeafletRenderers.LineSymbol=EsriLeafletRenderers.Symbol.extend({statics:{LINETYPES:["esriSLSDash","esriSLSDot","esriSLSDashDotDot","esriSLSDashDot","esriSLSSolid"]},initialize:function(a){EsriLeafletRenderers.Symbol.prototype.initialize.call(this,a),this._fillStyles()},_fillStyles:function(){if(this._styles.lineCap="butt",this._styles.lineJoin="miter",this._styles.fill=!1,this._symbolJson&&(this._symbolJson.color&&(this._styles.color=this.colorValue(this._symbolJson.color),this._styles.opacity=this.alphaValue(this._symbolJson.color)),this._symbolJson.width)){this._styles.weight=this.pixelValue(this._symbolJson.width);var a=[];switch(this._symbolJson.style){case"esriSLSDash":a=[4,3];break;case"esriSLSDot":a=[1,3];break;case"esriSLSDashDot":a=[8,3,1,3];break;case"esriSLSDashDotDot":a=[8,3,1,3,1,3]}if(a.length>0){for(var b=0;b=0)?(this._styles.fill=!0,this._styles.fillColor=this.colorValue(this._symbolJson.color),this._styles.fillOpacity=this.alphaValue(this._symbolJson.color)):(this._styles.fill=!1,this._styles.fillOpacity=0))},style:function(a,b){if(!this._isDefault&&b&&b.colorInfo){var c=this.getColor(a,b.colorInfo);c&&(this._styles.fillColor=this.colorValue(c),this._styles.fillOpacity=this.alphaValue(c))}return this._styles}}),EsriLeafletRenderers.polygonSymbol=function(a){return new EsriLeafletRenderers.PolygonSymbol(a)},EsriLeafletRenderers.Renderer=L.Class.extend({options:{proportionalPolygon:!1,clickable:!0},initialize:function(a,b){this._rendererJson=a,this._pointSymbols=!1,this._symbols=[],this._visualVariables=this._parseVisualVariables(a.visualVariables),L.Util.setOptions(this,b)},_parseVisualVariables:function(a){var b={};if(a)for(var c=0;c=0;c--)a=this.options.proportionalPolygon&&this._rendererJson.backgroundFillSymbol?this._newSymbol(this._rendererJson.backgroundFillSymbol):this._newSymbol(b[c].symbol),a.val=b[c].classMaxValue,this._symbols.push(a);this._symbols.sort(function(a,b){return a.val>b.val?1:-1}),this._createDefaultSymbol(),this._maxValue=this._symbols[this._symbols.length-1].val},_getSymbol:function(a){var b=a.properties[this._field];if(this._normalizationField){var c=a.properties[this._normalizationField];if(isNaN(c)||0===c)return this._defaultSymbol;b/=c}if(b>this._maxValue)return this._defaultSymbol;for(var d=this._symbols[0],e=this._symbols.length-1;e>=0&&!(b>this._symbols[e].val);e--)d=this._symbols[e];return d}}),EsriLeafletRenderers.classBreaksRenderer=function(a,b){return new EsriLeafletRenderers.ClassBreaksRenderer(a,b)},EsriLeafletRenderers.UniqueValueRenderer=EsriLeafletRenderers.Renderer.extend({initialize:function(a,b){EsriLeafletRenderers.Renderer.prototype.initialize.call(this,a,b),this._field=this._rendererJson.field1,this._createSymbols()},_createSymbols:function(){for(var a,b=this._rendererJson.uniqueValueInfos,c=b.length-1;c>=0;c--)a=this._newSymbol(b[c].symbol),a.val=b[c].value,this._symbols.push(a);this._createDefaultSymbol()},_getSymbol:function(a){for(var b=a.properties[this._field],c=this._defaultSymbol,d=this._symbols.length-1;d>=0;d--)this._symbols[d].val==b&&(c=this._symbols[d]);return c}}),EsriLeafletRenderers.uniqueValueRenderer=function(a,b){return new EsriLeafletRenderers.UniqueValueRenderer(a,b)},EsriLeafletRenderers.SquareMarker=L.Path.extend({options:{fill:!0},initialize:function(a,b,c){L.Path.prototype.initialize.call(this,c),this._size=b,this._center=a},projectLatlngs:function(){this._point=this._map.latLngToLayerPoint(this._center)},getPathString:function(){if(!this._map)return"";var a=this._point,b=this._size/2;L.Path.VML&&(a._round(),b=Math.round(b));var c="M"+(a.x+b)+","+(a.y+b)+"L"+(a.x-b)+","+(a.y+b)+"L"+(a.x-b)+","+(a.y-b)+"L"+(a.x+b)+","+(a.y-b);return c+(L.Browser.svg?"z":"x")},setLatLng:function(a){return this._center=a,this.redraw()},getLatLng:function(){return L.latLng(this._center)},getSize:function(){return this._size},setSize:function(a){return this._size=a,this.redraw()}}),EsriLeafletRenderers.squareMarker=function(a,b,c){return new EsriLeafletRenderers.SquareMarker(a,b,c)},EsriLeafletRenderers.DiamondMarker=L.Path.extend({options:{fill:!0},initialize:function(a,b,c){L.Path.prototype.initialize.call(this,c),this._size=b,this._center=a},projectLatlngs:function(){this._point=this._map.latLngToLayerPoint(this._center)},getPathString:function(){if(!this._map)return"";var a=this._point,b=this._size/2;L.Path.VML&&(a._round(),b=Math.round(b));var c="M"+a.x+","+(a.y+b)+"L"+(a.x-b)+","+a.y+"L"+a.x+","+(a.y-b)+"L"+(a.x+b)+","+a.y;return c+(L.Browser.svg?"z":"x")},setLatLng:function(a){return this._center=a,this.redraw()},getLatLng:function(){return L.latLng(this._center)},getSize:function(){return this._size},setSize:function(a){return this._size=a,this.redraw()}}),EsriLeafletRenderers.diamondMarker=function(a,b,c){return new EsriLeafletRenderers.DiamondMarker(a,b,c)},EsriLeafletRenderers.CrossMarker=L.Path.extend({initialize:function(a,b,c){L.Path.prototype.initialize.call(this,c),this._size=b,this._center=a},projectLatlngs:function(){this._point=this._map.latLngToLayerPoint(this._center)},getPathString:function(){if(!this._map)return"";var a=this._point,b=this._size/2;return L.Path.VML&&(a._round(),b=Math.round(b)),"M"+a.x+","+(a.y+b)+"L"+a.x+","+(a.y-b)+"M"+(a.x-b)+","+a.y+"L"+(a.x+b)+","+a.y},setLatLng:function(a){return this._center=a,this.redraw()},getLatLng:function(){return L.latLng(this._center)},getSize:function(){return this._size},setSize:function(a){return this._size=a,this.redraw()}}),EsriLeafletRenderers.crossMarker=function(a,b,c){return new EsriLeafletRenderers.CrossMarker(a,b,c)},EsriLeafletRenderers.XMarker=L.Path.extend({initialize:function(a,b,c){L.Path.prototype.initialize.call(this,c),this._size=b,this._center=a},projectLatlngs:function(){this._point=this._map.latLngToLayerPoint(this._center)},getPathString:function(){if(!this._map)return"";var a=this._point,b=this._size/2;return L.Path.VML&&(a._round(),b=Math.round(b)),"M"+(a.x+b)+","+(a.y+b)+"L"+(a.x-b)+","+(a.y-b)+"M"+(a.x-b)+","+(a.y+b)+"L"+(a.x+b)+","+(a.y-b)},setLatLng:function(a){return this._center=a,this.redraw()},getLatLng:function(){return L.latLng(this._center)},getSize:function(){return this._size},setSize:function(a){return this._size=a,this.redraw()}}),EsriLeafletRenderers.xMarker=function(a,b,c){return new EsriLeafletRenderers.XMarker(a,b,c)},Esri.FeatureLayer.addInitHook(function(){var a=L.Util.bind(this.onAdd,this),b=L.Util.bind(this.unbindPopup,this),c=L.Util.bind(this.onRemove,this);L.Util.bind(this.createNewLayer,this),this.metadata(function(b,c){b||(c&&c.drawingInfo&&!this.options.style&&this._setRenderers(c),this._metadataLoaded=!0,this._loadedMap&&(a(this._loadedMap),this._addPointLayer(this._loadedMap)))},this),this.onAdd=function(b){this._loadedMap=b,this._metadataLoaded&&(a(this._loadedMap),this._addPointLayer(this._loadedMap))},this.onRemove=function(a){if(c(a),this._pointLayer){var b=this._pointLayer.getLayers();for(var d in b)a.removeLayer(b[d])}},this.unbindPopup=function(){if(b(),this._pointLayer){var a=this._pointLayer.getLayers();for(var c in a)a[c].unbindPopup()}},this._addPointLayer=function(a){this._pointLayer&&(this._pointLayer.addTo(a),this._pointLayer.bringToFront())},this._createPointLayer=function(){if(!this._pointLayer&&(this._pointLayer=L.geoJson(),this._pointLayerIds={},this._popup)){var a=function(a,b){b.bindPopup(this._popup(a,b),this._popupOptions)};this._pointLayer.options.onEachFeature=L.Util.bind(a,this)}},this.createNewLayer=function(a){var b=L.GeoJSON.geometryToLayer(a,this.options.pointToLayer,L.GeoJSON.coordsToLatLng,this.options);if(this._hasProportionalSymbols){var c=this.getPolygonCentroid(a.geometry.coordinates);if(!isNaN(c[0])&&!isNaN(c[0])){this._createPointLayer();var d=a.id.toString();if(!this._pointLayerIds[d]){var e=this.getPointJson(a,c);this._pointLayer.addData(e),this._pointLayerIds[d]=!0}this._pointLayer.bringToFront()}}return b},this.getPolygonCentroid=function(a){var b=a[0][0];2===b.length&&(b=a[0]);for(var c,d,e,f=0,g=0,h=0,i=b.length,j=0,k=i-1;i>j;k=j++)c=b[j],d=b[k],f+=c[0]*d[1],f-=c[1]*d[0],e=c[0]*d[1]-d[0]*c[1],g+=(c[0]+d[0])*e,h+=(c[1]+d[1])*e;return e=3*f,[g/e,h/e]},this.getPointJson=function(a,b){return{type:"Feature",properties:a.properties,id:a.id,geometry:{type:"Point",coordinates:[b[0],b[1]]}}},this._checkForProportionalSymbols=function(a,b){if(this._hasProportionalSymbols=!1,"esriGeometryPolygon"===a&&(b.backgroundFillSymbol&&(this._hasProportionalSymbols=!0),b.classBreakInfos&&b.classBreakInfos.length)){var c=b.classBreakInfos[0].symbol;!c||"esriSMS"!==c.type&&"esriPMS"!==c.type||(this._hasProportionalSymbols=!0)}},this._setRenderers=function(a){var b,c=a.drawingInfo.renderer,d={url:this.url?this.url:this._service.options.url,token:this._service.options.token};switch(c.type){case"classBreaks":if(this._checkForProportionalSymbols(a.geometryType,c),this._hasProportionalSymbols){this._createPointLayer();var e=EsriLeafletRenderers.classBreaksRenderer(c,d);e.attachStylesToLayer(this._pointLayer),d.proportionalPolygon=!0}b=EsriLeafletRenderers.classBreaksRenderer(c,d);break;case"uniqueValue":b=EsriLeafletRenderers.uniqueValueRenderer(c,d);break;default:b=EsriLeafletRenderers.simpleRenderer(c,d)}b.attachStylesToLayer(this)}}); +//# sourceMappingURL=esri-leaflet-renderers.js.map \ No newline at end of file diff --git a/dist/esri-leaflet-renderers.js.map b/dist/esri-leaflet-renderers.js.map new file mode 100644 index 0000000..5b47274 --- /dev/null +++ b/dist/esri-leaflet-renderers.js.map @@ -0,0 +1 @@ +{"version":3,"file":"esri-leaflet-renderers.js","sources":["../src/EsriLeafletRenderers.js","../src/Symbols/Symbol.js","../src/Symbols/PointSymbol.js","../src/Symbols/LineSymbol.js","../src/Symbols/PolygonSymbol.js","../src/Renderers/Renderer.js","../src/Renderers/SimpleRenderer.js","../src/Renderers/ClassBreaksRenderer.js","../src/Renderers/UniqueValueRenderer.js","../src/Markers/SquareMarker.js","../src/Markers/DiamondMarker.js","../src/Markers/CrossMarker.js","../src/Markers/XMarker.js","../src/FeatureLayerHook.js"],"names":["EsriLeafletRenderers","VERSION","window","L","esri","Renderers","Esri","Symbol","Class","extend","initialize","symbolJson","this","_symbolJson","val","_styles","_isDefault","pixelValue","pointValue","colorValue","color","alphaValue","getSize","feature","sizeInfo","attr","properties","field","size","featureValue","featureRatio","minSize","maxSize","minDataValue","maxDataValue","normField","normalizationField","normValue","parseFloat","undefined","isNaN","getColor","colorInfo","stops","lowerBoundColor","upperBoundColor","lowerBound","upperBound","value","lastStop","length","i","stopInfo","range","upperBoundColorWeight","lowerBoundColorWeight","interpolatedColor","j","Math","round","PointSymbol","statics","MARKERTYPES","options","prototype","call","serviceUrl","url","type","_iconUrl","token","_icons","icon","_createIcon","_fillStyles","outline","stroke","weight","width","opacity","fillColor","fillOpacity","style","radius","height","xOffset","yOffset","xoffset","yoffset","iconUrl","iconSize","iconAnchor","toString","_getIcon","pointToLayer","geojson","latlng","visualVariables","calculatedSize","marker","squareMarker","diamondMarker","crossMarker","xMarker","circleMarker","pointSymbol","LineSymbol","LINETYPES","lineCap","lineJoin","fill","dashValues","dashArray","join","lineSymbol","PolygonSymbol","POLYGONTYPES","_lineStyles","styleAttr","indexOf","polygonSymbol","Renderer","proportionalPolygon","clickable","rendererJson","_rendererJson","_pointSymbols","_symbols","_visualVariables","_parseVisualVariables","Util","setOptions","visVars","_createDefaultSymbol","defaultSymbol","_defaultSymbol","_newSymbol","_getSymbol","attachStylesToLayer","layer","bind","sym","SimpleRenderer","_createSymbol","symbol","push","simpleRenderer","ClassBreaksRenderer","_field","normalizationType","_normalizationField","_createSymbols","classbreaks","classBreakInfos","backgroundFillSymbol","classMaxValue","sort","a","b","_maxValue","classBreaksRenderer","UniqueValueRenderer","field1","uniques","uniqueValueInfos","uniqueValueRenderer","SquareMarker","Path","center","_size","_center","projectLatlngs","_point","_map","latLngToLayerPoint","getPathString","offset","VML","_round","str","x","y","Browser","svg","setLatLng","redraw","getLatLng","latLng","setSize","DiamondMarker","CrossMarker","XMarker","FeatureLayer","addInitHook","oldOnAdd","onAdd","oldUnbindPopup","unbindPopup","oldOnRemove","onRemove","createNewLayer","metadata","error","response","drawingInfo","_setRenderers","_metadataLoaded","_loadedMap","_addPointLayer","map","_pointLayer","pointLayers","getLayers","removeLayer","addTo","bringToFront","_createPointLayer","geoJson","_pointLayerIds","_popup","popupFunction","bindPopup","_popupOptions","onEachFeature","fLayer","GeoJSON","geometryToLayer","coordsToLatLng","_hasProportionalSymbols","centroid","getPolygonCentroid","geometry","coordinates","featureId","id","pointjson","getPointJson","addData","pts","p1","p2","f","twicearea","nPts","_checkForProportionalSymbols","geometryType","renderer","rend","rendererInfo","_service","pRend"],"mappings":"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","sourcesContent":["var EsriLeafletRenderers = {\n VERSION: '0.0.1-beta.3'\n};\n\n// attach to the L.esri global if we can\nif(typeof window !== 'undefined' && window.L && window.L.esri) {\n window.L.esri.Renderers = EsriLeafletRenderers;\n}\n\n// We do not have an 'Esri' variable e.g loading this file directly from source define 'Esri'\nif(!Esri){\n var Esri = window.L.esri;\n}\n","EsriLeafletRenderers.Symbol = L.Class.extend({\n\n initialize: function(symbolJson){\n this._symbolJson = symbolJson;\n this.val = null;\n this._styles = {};\n this._isDefault = false;\n },\n\n //the geojson values returned are in points\n pixelValue: function(pointValue){\n return pointValue * 1.333;\n },\n\n //color is an array [r,g,b,a]\n colorValue: function(color){\n return 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';\n },\n\n alphaValue: function(color){\n return color[3] / 255.0;\n },\n\n getSize: function(feature, sizeInfo) {\n\n var attr = feature.properties,\n field = sizeInfo.field,\n size = 0,\n featureValue = null;\n\n if(field){\n featureValue = attr[field];\n var minSize = sizeInfo.minSize,\n maxSize = sizeInfo.maxSize,\n minDataValue = sizeInfo.minDataValue,\n maxDataValue = sizeInfo.maxDataValue,\n featureRatio,\n normField = sizeInfo.normalizationField,\n normValue = attr ? parseFloat(attr[normField]) : undefined;\n\n if(featureValue === null || (normField && ((isNaN(normValue) || normValue === 0)))){\n return null;\n }\n\n if(!isNaN(normValue)){\n featureValue /= normValue;\n }\n\n if(minSize !== null && maxSize !== null && minDataValue !== null && maxDataValue !== null){\n if(featureValue <= minDataValue){\n size = minSize;\n }\n else if(featureValue >= maxDataValue){\n size = maxSize;\n }\n else{\n featureRatio = (featureValue - minDataValue) / (maxDataValue - minDataValue);\n size = minSize + (featureRatio * (maxSize - minSize));\n }\n }\n size = isNaN(size) ? 0 : size;\n }\n return size;\n },\n\n getColor: function(feature, colorInfo) {\n //required information to get color\n if(!(feature.properties && colorInfo && colorInfo.field && colorInfo.stops)){\n return null;\n }\n\n var attr = feature.properties;\n var featureValue = attr[colorInfo.field];\n var lowerBoundColor, upperBoundColor, lowerBound, upperBound;\n var normField = colorInfo.normalizationField;\n var normValue = attr ? parseFloat(attr[normField]) : undefined;\n if(featureValue === null || (normField && ((isNaN(normValue) || normValue === 0)))){\n return null;\n }\n\n if(!isNaN(normValue)){\n featureValue /= normValue;\n }\n\n if(featureValue <= colorInfo.stops[0].value){\n return colorInfo.stops[0].color;\n }\n var lastStop = colorInfo.stops[colorInfo.stops.length - 1];\n if(featureValue >= lastStop.value){\n return lastStop.color;\n }\n\n //go through the stops to find min and max\n for(var i=0; i featureValue){\n upperBoundColor = stopInfo.color;\n upperBound = stopInfo.value;\n break;\n }\n }\n\n //feature falls between two stops, interplate the colors\n if(!isNaN(lowerBound) && !isNaN(upperBound)){\n var range = upperBound - lowerBound;\n if(range > 0){\n //more weight the further it is from the lower bound\n var upperBoundColorWeight = (featureValue - lowerBound) / range;\n if(upperBoundColorWeight){\n //more weight the further it is from the upper bound\n var lowerBoundColorWeight = (upperBound - featureValue) / range;\n if(lowerBoundColorWeight){\n\n //interpolate the lower and upper bound color by applying the\n //weights to each of the rgba colors and adding them together\n var interpolatedColor = [];\n for(var j=0; j<4; j++){\n interpolatedColor[j] = Math.round(lowerBoundColor[j] * lowerBoundColorWeight + upperBoundColor[j] * upperBoundColorWeight); \n }\n return interpolatedColor;\n } else {\n //no difference between featureValue and upperBound, 100% of upperBoundColor\n return upperBoundColor;\n }\n } else {\n //no difference between featureValue and lowerBound, 100% of lowerBoundColor\n return lowerBoundColor;\n }\n }\n }\n //if we get to here, none of the cases apply so return null\n return null;\n }\n});\n","EsriLeafletRenderers.PointSymbol = EsriLeafletRenderers.Symbol.extend({\n statics: {\n MARKERTYPES: ['esriSMSCircle','esriSMSCross', 'esriSMSDiamond', 'esriSMSSquare', 'esriSMSX', 'esriPMS']\n },\n initialize: function(symbolJson, options){\n EsriLeafletRenderers.Symbol.prototype.initialize.call(this, symbolJson);\n if(options) {\n this.serviceUrl = options.url;\n }\n if(symbolJson){\n if(symbolJson.type === 'esriPMS'){\n var url = this.serviceUrl + 'images/' + this._symbolJson.url;\n this._iconUrl = options && options.token ? url + '?token=' + options.token : url;\n //leaflet does not allow resizing icons so keep a hash of different\n //icon sizes to try and keep down on the number of icons created\n this._icons = {};\n //create base icon\n this.icon = this._createIcon(this._symbolJson);\n } else {\n this._fillStyles();\n }\n }\n },\n\n _fillStyles: function(){\n if(this._symbolJson.outline && this._symbolJson.size > 0){\n this._styles.stroke = true;\n this._styles.weight = this.pixelValue(this._symbolJson.outline.width);\n this._styles.color = this.colorValue(this._symbolJson.outline.color);\n this._styles.opacity = this.alphaValue(this._symbolJson.outline.color);\n }else{\n this._styles.stroke = false;\n }\n if(this._symbolJson.color){\n this._styles.fillColor = this.colorValue(this._symbolJson.color);\n this._styles.fillOpacity = this.alphaValue(this._symbolJson.color);\n } else {\n this._styles.fillOpacity = 0;\n }\n\n if(this._symbolJson.style === 'esriSMSCircle'){\n this._styles.radius = this.pixelValue(this._symbolJson.size) / 2.0;\n }\n },\n\n _createIcon: function(options){\n var width = this.pixelValue(options.width);\n var height = width;\n if(options.height){\n height = this.pixelValue(options.height);\n }\n var xOffset = width / 2.0;\n var yOffset = height / 2.0;\n\n\n if(options.xoffset){\n xOffset += this.pixelValue(options.xoffset);\n }\n if(options.yoffset){\n yOffset += this.pixelValue(options.yoffset);\n }\n\n var icon = L.icon({\n iconUrl: this._iconUrl,\n iconSize: [width, height],\n iconAnchor: [xOffset, yOffset]\n });\n this._icons[options.width.toString()] = icon;\n return icon;\n },\n\n _getIcon: function(size) {\n //check to see if it is already created by size\n var icon = this._icons[size.toString()];\n if(!icon){\n icon = this._createIcon({width: size});\n }\n return icon;\n },\n\n pointToLayer: function(geojson, latlng, visualVariables){\n var size = this._symbolJson.size || this._symbolJson.width;\n if(!this._isDefault){\n if( visualVariables.sizeInfo) {\n var calculatedSize = this.getSize(geojson, visualVariables.sizeInfo);\n if (calculatedSize) {\n size = calculatedSize;\n }\n }\n if(visualVariables.colorInfo){\n var color = this.getColor(geojson, visualVariables.colorInfo);\n if(color){\n this._styles.fillColor = this.colorValue(color);\n this._styles.fillOpacity = this.alphaValue(color);\n }\n }\n }\n\n if (this._symbolJson.type === 'esriPMS'){\n return L.marker(latlng, {icon: this._getIcon(size)});\n }\n size = this.pixelValue(size);\n\n switch(this._symbolJson.style){\n case 'esriSMSSquare':\n return EsriLeafletRenderers.squareMarker(latlng, size, this._styles);\n case 'esriSMSDiamond':\n return EsriLeafletRenderers.diamondMarker(latlng, size, this._styles);\n case 'esriSMSCross':\n return EsriLeafletRenderers.crossMarker(latlng, size, this._styles);\n case 'esriSMSX':\n return EsriLeafletRenderers.xMarker(latlng, size, this._styles);\n }\n this._styles.radius = size / 2.0;\n return L.circleMarker(latlng, this._styles);\n }\n});\nEsriLeafletRenderers.pointSymbol = function(symbolJson, options){\n return new EsriLeafletRenderers.PointSymbol(symbolJson, options);\n};\n","EsriLeafletRenderers.LineSymbol = EsriLeafletRenderers.Symbol.extend({\n statics: {\n //Not implemented 'esriSLSNull'\n LINETYPES: ['esriSLSDash','esriSLSDot','esriSLSDashDotDot','esriSLSDashDot','esriSLSSolid']\n },\n initialize: function(symbolJson){\n EsriLeafletRenderers.Symbol.prototype.initialize.call(this, symbolJson);\n this._fillStyles();\n },\n\n _fillStyles: function(){\n //set the defaults that show up on arcgis online\n this._styles.lineCap = 'butt';\n this._styles.lineJoin = 'miter';\n this._styles.fill = false;\n\n if (!this._symbolJson){\n return;\n }\n\n if(this._symbolJson.color ){\n this._styles.color = this.colorValue(this._symbolJson.color);\n this._styles.opacity = this.alphaValue(this._symbolJson.color);\n }\n\n if(this._symbolJson.width){\n this._styles.weight = this.pixelValue(this._symbolJson.width);\n \n var dashValues = [];\n\n switch(this._symbolJson.style){\n case 'esriSLSDash':\n dashValues = [4,3];\n break;\n case 'esriSLSDot':\n dashValues = [1,3];\n break;\n case 'esriSLSDashDot':\n dashValues = [8,3,1,3];\n break;\n case 'esriSLSDashDotDot':\n dashValues = [8,3,1,3,1,3];\n break;\n }\n\n //use the dash values and the line weight to set dash array\n if (dashValues.length > 0) {\n for (var i = 0; i < dashValues.length; i++){\n dashValues[i] *= this._styles.weight;\n }\n\n this._styles.dashArray = dashValues.join(',');\n }\n }\n },\n\n style: function(feature, visualVariables){\n if(!this._isDefault && visualVariables){\n if(visualVariables.sizeInfo){\n var calculatedSize = this.pixelValue(this.getSize(feature, visualVariables.sizeInfo));\n if (calculatedSize) {\n this._styles.weight = calculatedSize;\n }\n }\n if(visualVariables.colorInfo){\n var color = this.getColor(feature, visualVariables.colorInfo);\n if(color){\n this._styles.color = this.colorValue(color);\n this._styles.opacity = this.alphaValue(color);\n }\n }\n }\n return this._styles;\n }\n});\nEsriLeafletRenderers.lineSymbol = function(symbolJson){\n return new EsriLeafletRenderers.LineSymbol(symbolJson);\n};\n","EsriLeafletRenderers.PolygonSymbol = EsriLeafletRenderers.Symbol.extend({\n statics: {\n //not implemented: 'esriSFSBackwardDiagonal','esriSFSCross','esriSFSDiagonalCross','esriSFSForwardDiagonal','esriSFSHorizontal','esriSFSNull','esriSFSVertical'\n POLYGONTYPES: ['esriSFSSolid']\n },\n initialize: function(symbolJson){\n EsriLeafletRenderers.Symbol.prototype.initialize.call(this, symbolJson);\n if (symbolJson){\n this._lineStyles = EsriLeafletRenderers.lineSymbol(symbolJson.outline).style();\n this._fillStyles();\n }\n },\n\n _fillStyles: function(){\n if (this._lineStyles) {\n if (this._lineStyles.weight === 0){\n //when weight is 0, setting the stroke to false can still look bad\n //(gaps between the polygons)\n this._styles.stroke = false;\n } else {\n //copy the line symbol styles into this symbol's styles\n for (var styleAttr in this._lineStyles){\n this._styles[styleAttr] = this._lineStyles[styleAttr];\n }\n }\n }\n\n //set the fill for the polygon\n if (this._symbolJson) {\n if (this._symbolJson.color &&\n //don't fill polygon if type is not supported\n EsriLeafletRenderers.PolygonSymbol.POLYGONTYPES.indexOf(this._symbolJson.style >= 0)) {\n\n this._styles.fill = true;\n this._styles.fillColor = this.colorValue(this._symbolJson.color);\n this._styles.fillOpacity = this.alphaValue(this._symbolJson.color);\n } else {\n this._styles.fill = false;\n this._styles.fillOpacity = 0;\n }\n }\n\n },\n\n style: function(feature, visualVariables) {\n if(!this._isDefault && visualVariables && visualVariables.colorInfo){\n var color = this.getColor(feature, visualVariables.colorInfo);\n if(color){\n this._styles.fillColor = this.colorValue(color);\n this._styles.fillOpacity = this.alphaValue(color);\n }\n }\n return this._styles;\n }\n});\nEsriLeafletRenderers.polygonSymbol = function(symbolJson){\n return new EsriLeafletRenderers.PolygonSymbol(symbolJson);\n};\n","EsriLeafletRenderers.Renderer = L.Class.extend({\n\n options: {\n proportionalPolygon: false,\n clickable: true\n },\n\n initialize: function(rendererJson, options){\n this._rendererJson = rendererJson;\n this._pointSymbols = false;\n this._symbols = [];\n this._visualVariables = this._parseVisualVariables(rendererJson.visualVariables);\n L.Util.setOptions(this, options);\n },\n\n _parseVisualVariables: function(visualVariables){\n var visVars = {};\n if (visualVariables) {\n for (var i = 0; i < visualVariables.length; i++){\n visVars[visualVariables[i].type] = visualVariables[i];\n }\n }\n return visVars;\n },\n\n _createDefaultSymbol: function(){\n if(this._rendererJson.defaultSymbol){\n this._defaultSymbol = this._newSymbol(this._rendererJson.defaultSymbol);\n this._defaultSymbol._isDefault = true;\n }\n },\n\n _newSymbol: function(symbolJson){\n if(symbolJson.type === 'esriSMS' || symbolJson.type === 'esriPMS'){\n this._pointSymbols = true;\n return EsriLeafletRenderers.pointSymbol(symbolJson, this.options);\n }\n if(symbolJson.type === 'esriSLS'){\n return EsriLeafletRenderers.lineSymbol(symbolJson);\n }\n if(symbolJson.type === 'esriSFS'){\n return EsriLeafletRenderers.polygonSymbol(symbolJson);\n }\n },\n\n _getSymbol: function(){\n //override\n },\n\n attachStylesToLayer: function(layer){\n if(this._pointSymbols){\n layer.options.pointToLayer = L.Util.bind(this.pointToLayer, this);\n } else {\n layer.options.style = L.Util.bind(this.style, this);\n }\n },\n\n pointToLayer: function(geojson, latlng){\n var sym = this._getSymbol(geojson);\n if(sym && sym.pointToLayer){\n return sym.pointToLayer(geojson, latlng, this._visualVariables);\n }\n //invisible symbology\n return L.circleMarker(latlng, {radius: 0, opacity: 0});\n },\n\n style: function(feature){\n //find the symbol to represent this feature\n var sym = this._getSymbol(feature);\n if(sym){\n return sym.style(feature, this._visualVariables);\n }else{\n //invisible symbology\n return {opacity: 0, fillOpacity: 0};\n }\n }\n});\n","EsriLeafletRenderers.SimpleRenderer = EsriLeafletRenderers.Renderer.extend({\n\n initialize: function(rendererJson, options){\n EsriLeafletRenderers.Renderer.prototype.initialize.call(this, rendererJson, options);\n this._createSymbol();\n },\n\n _createSymbol: function(){\n if(this._rendererJson.symbol){\n this._symbols.push(this._newSymbol(this._rendererJson.symbol));\n }\n },\n\n _getSymbol: function(){\n return this._symbols[0];\n }\n});\n\nEsriLeafletRenderers.simpleRenderer = function(rendererJson, options){\n return new EsriLeafletRenderers.SimpleRenderer(rendererJson, options);\n};\n","EsriLeafletRenderers.ClassBreaksRenderer = EsriLeafletRenderers.Renderer.extend({\n\n initialize: function(rendererJson, options){\n EsriLeafletRenderers.Renderer.prototype.initialize.call(this, rendererJson, options);\n this._field = this._rendererJson.field;\n if (this._rendererJson.normalizationType && this._rendererJson.normalizationType === 'esriNormalizeByField'){\n this._normalizationField = this._rendererJson.normalizationField;\n }\n this._createSymbols();\n },\n\n _createSymbols: function(){\n var symbol,\n classbreaks = this._rendererJson.classBreakInfos;\n\n this._symbols = [];\n\n //create a symbol for each class break\n for (var i = classbreaks.length - 1; i >= 0; i--){\n if(this.options.proportionalPolygon && this._rendererJson.backgroundFillSymbol){\n symbol = this._newSymbol(this._rendererJson.backgroundFillSymbol);\n } else {\n symbol = this._newSymbol(classbreaks[i].symbol);\n }\n symbol.val = classbreaks[i].classMaxValue;\n this._symbols.push(symbol);\n }\n //sort the symbols in ascending value\n this._symbols.sort(function(a, b){\n return a.val > b.val ? 1 : -1;\n });\n this._createDefaultSymbol();\n this._maxValue = this._symbols[this._symbols.length - 1].val;\n },\n\n _getSymbol: function(feature){\n var val = feature.properties[this._field];\n if (this._normalizationField){\n var normValue = feature.properties[this._normalizationField];\n if (!isNaN(normValue) && normValue !== 0) {\n val = val / normValue;\n } else {\n return this._defaultSymbol;\n }\n }\n\n if(val > this._maxValue){\n return this._defaultSymbol;\n }\n var symbol = this._symbols[0];\n for (var i = this._symbols.length - 1; i >= 0; i--){\n if(val > this._symbols[i].val){\n break;\n }\n symbol = this._symbols[i];\n }\n return symbol;\n }\n});\n\nEsriLeafletRenderers.classBreaksRenderer = function(rendererJson, options){\n return new EsriLeafletRenderers.ClassBreaksRenderer(rendererJson, options);\n};\n","EsriLeafletRenderers.UniqueValueRenderer = EsriLeafletRenderers.Renderer.extend({\n\n initialize: function(rendererJson, options){\n EsriLeafletRenderers.Renderer.prototype.initialize.call(this, rendererJson, options);\n\n //what to do when there are other fields?\n this._field = this._rendererJson.field1;\n this._createSymbols();\n },\n\n _createSymbols: function(){\n var symbol, uniques = this._rendererJson.uniqueValueInfos;\n\n //create a symbol for each unique value\n for (var i = uniques.length - 1; i >= 0; i--){\n symbol = this._newSymbol(uniques[i].symbol);\n symbol.val = uniques[i].value;\n this._symbols.push(symbol);\n }\n this._createDefaultSymbol();\n },\n\n /* jshint ignore:start */\n _getSymbol: function(feature){\n var val = feature.properties[this._field];\n var symbol = this._defaultSymbol;\n for (var i = this._symbols.length - 1; i >= 0; i--){\n //using the === operator does not work if the field\n //of the unique renderer is not a string\n if(this._symbols[i].val == val){\n symbol = this._symbols[i];\n }\n }\n return symbol;\n }\n /* jshint ignore:end */\n});\n\nEsriLeafletRenderers.uniqueValueRenderer = function(rendererJson, options){\n return new EsriLeafletRenderers.UniqueValueRenderer(rendererJson, options);\n};\n","EsriLeafletRenderers.SquareMarker = L.Path.extend({\n options: {\n fill: true\n },\n\n initialize: function(center, size, options){\n L.Path.prototype.initialize.call(this, options);\n this._size = size;\n this._center = center;\n },\n\n projectLatlngs: function(){\n this._point = this._map.latLngToLayerPoint(this._center);\n },\n\n getPathString: function(){\n if (!this._map){\n return '';\n }\n\n var center = this._point,\n offset = this._size / 2.0;\n\n if(L.Path.VML){\n center._round();\n offset = Math.round(offset);\n }\n\n var str = 'M' + (center.x + offset) + ',' + (center.y + offset) +\n 'L' + (center.x - offset) + ',' + (center.y + offset) +\n 'L' + (center.x - offset) + ',' + (center.y - offset) +\n 'L' + (center.x + offset) + ',' + (center.y - offset);\n\n return str + (L.Browser.svg ? 'z' : 'x');\n },\n\n setLatLng: function(latlng){\n this._center = latlng;\n return this.redraw();\n },\n\n getLatLng: function(){\n return L.latLng(this._center);\n },\n\n getSize: function(){\n return this._size;\n },\n\n setSize: function(size){\n this._size = size;\n return this.redraw();\n }\n});\n\nEsriLeafletRenderers.squareMarker = function(center, size, options){\n return new EsriLeafletRenderers.SquareMarker(center, size, options);\n};\n","EsriLeafletRenderers.DiamondMarker = L.Path.extend({\n options: {\n fill: true\n },\n\n initialize: function(center, size, options){\n L.Path.prototype.initialize.call(this, options);\n this._size = size;\n this._center = center;\n },\n\n projectLatlngs: function(){\n this._point = this._map.latLngToLayerPoint(this._center);\n },\n\n getPathString: function(){\n if (!this._map){\n return '';\n }\n\n var center = this._point,\n offset = this._size / 2.0;\n\n if(L.Path.VML){\n center._round();\n offset = Math.round(offset);\n }\n\n var str = 'M' + center.x + ',' + (center.y + offset) +\n 'L' + (center.x - offset) + ',' + center.y +\n 'L' + center.x + ',' + (center.y - offset) +\n 'L' + (center.x + offset) + ',' + center.y;\n\n return str + (L.Browser.svg ? 'z' : 'x');\n },\n\n setLatLng: function(latlng){\n this._center = latlng;\n return this.redraw();\n },\n\n getLatLng: function(){\n return L.latLng(this._center);\n },\n\n getSize: function(){\n return this._size;\n },\n\n setSize: function(size){\n this._size = size;\n return this.redraw();\n }\n});\n\nEsriLeafletRenderers.diamondMarker = function(center, size, options){\n return new EsriLeafletRenderers.DiamondMarker(center, size, options);\n};\n","EsriLeafletRenderers.CrossMarker = L.Path.extend({\n initialize: function (center, size, options){\n L.Path.prototype.initialize.call(this, options);\n this._size = size;\n this._center = center;\n },\n\n projectLatlngs: function(){\n this._point = this._map.latLngToLayerPoint(this._center);\n },\n\n getPathString: function(){\n if (!this._map){\n return '';\n }\n\n var center = this._point,\n offset = this._size / 2.0;\n\n if(L.Path.VML){\n center._round();\n offset = Math.round(offset);\n }\n\n return 'M' + center.x + ',' + (center.y + offset) +\n 'L' + center.x + ',' + (center.y - offset) +\n 'M' + (center.x - offset) + ',' + center.y +\n 'L' + (center.x + offset) + ',' + center.y;\n },\n\n setLatLng: function(latlng){\n this._center = latlng;\n return this.redraw();\n },\n\n getLatLng: function(){\n return L.latLng(this._center);\n },\n\n getSize: function(){\n return this._size;\n },\n\n setSize: function(size){\n this._size = size;\n return this.redraw();\n }\n});\n\nEsriLeafletRenderers.crossMarker = function(center, size, options){\n return new EsriLeafletRenderers.CrossMarker(center, size, options);\n};\n","EsriLeafletRenderers.XMarker = L.Path.extend({\n initialize: function(center, size, options){\n L.Path.prototype.initialize.call(this, options);\n this._size = size;\n this._center = center;\n },\n\n projectLatlngs: function(){\n this._point = this._map.latLngToLayerPoint(this._center);\n },\n\n getPathString: function(){\n if (!this._map){\n return '';\n }\n\n var center = this._point,\n offset = this._size / 2.0;\n\n if(L.Path.VML){\n center._round();\n offset = Math.round(offset);\n }\n\n return 'M' + (center.x + offset) + ',' + (center.y + offset) +\n 'L' + (center.x - offset) + ',' + (center.y - offset) +\n 'M' + (center.x - offset) + ',' + (center.y + offset) +\n 'L' + (center.x + offset) + ',' + (center.y - offset);\n },\n\n setLatLng: function(latlng){\n this._center = latlng;\n return this.redraw();\n },\n\n getLatLng: function(){\n return L.latLng(this._center);\n },\n\n getSize: function(){\n return this._size;\n },\n\n setSize: function(size){\n this._size = size;\n return this.redraw();\n }\n});\n\nEsriLeafletRenderers.xMarker = function(center, size, options){\n return new EsriLeafletRenderers.XMarker(center, size, options);\n};\n","Esri.FeatureLayer.addInitHook(function() {\n var oldOnAdd = L.Util.bind(this.onAdd, this);\n var oldUnbindPopup = L.Util.bind(this.unbindPopup, this);\n var oldOnRemove = L.Util.bind(this.onRemove, this);\n L.Util.bind(this.createNewLayer, this);\n\n this.metadata(function(error, response) {\n if(error) {\n return;\n }\n if(response && response.drawingInfo && !this.options.style){\n this._setRenderers(response);\n }\n\n this._metadataLoaded = true;\n if(this._loadedMap){\n oldOnAdd(this._loadedMap);\n this._addPointLayer(this._loadedMap);\n }\n }, this);\n\n this.onAdd = function(map){\n\n this._loadedMap = map;\n if(this._metadataLoaded){\n oldOnAdd(this._loadedMap);\n this._addPointLayer(this._loadedMap);\n }\n };\n\n this.onRemove = function(map){\n oldOnRemove(map);\n if(this._pointLayer){\n var pointLayers = this._pointLayer.getLayers();\n for(var i in pointLayers){\n map.removeLayer(pointLayers[i]);\n }\n }\n };\n\n this.unbindPopup = function(){\n oldUnbindPopup();\n if(this._pointLayer){\n var pointLayers = this._pointLayer.getLayers();\n for(var i in pointLayers){\n pointLayers[i].unbindPopup();\n }\n }\n };\n\n this._addPointLayer = function(map){\n if(this._pointLayer){\n this._pointLayer.addTo(map);\n this._pointLayer.bringToFront();\n }\n };\n\n this._createPointLayer = function(){\n if(!this._pointLayer){\n this._pointLayer = L.geoJson();\n //store the feature ids that have already been added to the map\n this._pointLayerIds = {};\n\n if(this._popup){\n var popupFunction = function (feature, layer) {\n layer.bindPopup(this._popup(feature, layer), this._popupOptions);\n };\n this._pointLayer.options.onEachFeature = L.Util.bind(popupFunction, this);\n }\n }\n };\n\n this.createNewLayer = function(geojson){\n\n var fLayer = L.GeoJSON.geometryToLayer(geojson, this.options.pointToLayer, L.GeoJSON.coordsToLatLng, this.options);\n\n //add a point layer when the polygon is represented as proportional marker symbols\n if(this._hasProportionalSymbols){\n var centroid = this.getPolygonCentroid(geojson.geometry.coordinates);\n if(!(isNaN(centroid[0]) || isNaN(centroid[0]))){\n this._createPointLayer();\n\n var featureId = geojson.id.toString();\n //only add the feature if it does not already exist on the map\n if(!this._pointLayerIds[featureId]){\n var pointjson = this.getPointJson(geojson, centroid);\n\n this._pointLayer.addData(pointjson);\n this._pointLayerIds[featureId] = true;\n }\n\n this._pointLayer.bringToFront();\n }\n }\n return fLayer;\n };\n\n this.getPolygonCentroid = function(coordinates){\n var pts = coordinates[0][0];\n if(pts.length === 2){\n pts = coordinates[0];\n }\n\n\n var twicearea=0,\n x=0, y=0,\n nPts = pts.length,\n p1, p2, f;\n\n for (var i=0, j=nPts-1 ;i