44 |
45 |
46 |
177 |
178 |
179 |
--------------------------------------------------------------------------------
/debug/reset-style.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/debug/sample.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/debug/script-tag.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
Geometry Type:
25 |
Renderer Type:
26 |
27 |
30 |
31 |
32 |
Leaflet
33 |
34 |
35 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Fri May 30 2014 15:44:45 GMT-0400 (EDT)
3 |
4 | module.exports = function (config) {
5 | var configuration = {
6 | // base path that will be used to resolve all patterns (eg. files, exclude)
7 | basePath: '',
8 |
9 | // frameworks to use
10 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
11 | frameworks: ['mocha', 'chai-sinon'],
12 |
13 | // list of files / patterns to load in the browser
14 | files: [
15 | 'node_modules/leaflet/dist/leaflet.css',
16 | 'node_modules/leaflet/dist/leaflet-src.js',
17 | 'node_modules/esri-leaflet/dist/esri-leaflet-debug.js',
18 | 'node_modules/leaflet-shape-markers/dist/leaflet-shape-markers.js',
19 | 'dist/esri-leaflet-renderers-debug.js',
20 | 'spec/**/*.js'
21 | ],
22 |
23 | // list of files to exclude
24 | exclude: [],
25 |
26 | // preprocess matching files before serving them to the browser
27 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
28 | preprocessors: {
29 | 'dist/**/*.js': ['sourcemap', 'coverage']
30 | },
31 |
32 | // test results reporter to use
33 | // possible values: 'dots', 'progress'
34 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
35 | reporters: ['progress'],
36 |
37 | // web server port
38 | port: 9876,
39 |
40 | // enable / disable colors in the output (reporters and logs)
41 | colors: true,
42 |
43 | // level of logging
44 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
45 | logLevel: config.LOG_INFO,
46 |
47 | // enable / disable watching file and executing tests whenever any file changes
48 | autoWatch: true,
49 |
50 | // start these browsers
51 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
52 | browsers: [
53 | 'Chrome'
54 | // 'ChromeCanary',
55 | // 'Firefox',
56 | // 'Safari',
57 | // 'PhantomJS'
58 | ],
59 |
60 | customLaunchers: {
61 | Chrome_travis_ci: {
62 | base: 'ChromeHeadless',
63 | flags: ['--no-sandbox']
64 | }
65 | },
66 |
67 | // Continuous Integration mode
68 | // if true, Karma captures browsers, runs the tests and exits
69 | singleRun: true,
70 |
71 | // Configure the coverage reporters
72 | coverageReporter: {
73 | reporters: [
74 | { type: 'html', dir: 'coverage/' },
75 | { type: 'text' }
76 | ]
77 | }
78 | };
79 |
80 | if (process.env.TRAVIS) {
81 | configuration.browsers = ['Chrome_travis_ci'];
82 | }
83 |
84 | config.set(configuration);
85 | };
86 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "esri-leaflet-renderers",
3 | "description": "esri-leaflet plugin for rendering",
4 | "version": "3.0.1",
5 | "author": "Rachel Nehmer",
6 | "bugs": {
7 | "url": "https://github.com/esri/esri-leaflet-renderers/issues"
8 | },
9 | "contributors": [
10 | "Rachel Nehmer",
11 | "John Gravois (https://johngravois.com)",
12 | "Gavin Rehkemper (https://gavinr.com)"
13 | ],
14 | "peerDependencies": {
15 | "esri-leaflet": "3.x",
16 | "leaflet": "1.x",
17 | "leaflet-shape-markers": "1.x"
18 | },
19 | "optionalDependencies": {
20 | "esri-leaflet-cluster": "^3.0.0"
21 | },
22 | "devDependencies": {
23 | "@rollup/plugin-json": "^4.1.0",
24 | "@rollup/plugin-node-resolve": "^13.1.3",
25 | "@rollup/plugin-terser": "^0.3.0",
26 | "chai": "4.3.6",
27 | "chokidar-cli": "^3.0.0",
28 | "esri-leaflet": "3.x",
29 | "gh-release": "^7.0.2",
30 | "http-server": "^14.1.1",
31 | "karma": "^6.3.16",
32 | "karma-chai-sinon": "^0.1.5",
33 | "karma-chrome-launcher": "^3.1.0",
34 | "karma-coverage": "^2.2.0",
35 | "karma-mocha": "^2.0.1",
36 | "karma-mocha-reporter": "^2.2.5",
37 | "karma-sourcemap-loader": "^0.3.8",
38 | "leaflet": "1.x",
39 | "leaflet-shape-markers": "^1.0.6",
40 | "mkdirp": "^1.0.4",
41 | "mocha": "^10.2.0",
42 | "npm-run-all": "^4.1.5",
43 | "rollup": "^2.79.1",
44 | "semistandard": "^14.2.3",
45 | "sinon": "^15.0.1",
46 | "sinon-chai": "3.7.0",
47 | "snazzy": "^9.0.0"
48 | },
49 | "files": [
50 | "src/**/*.js",
51 | "dist/*.js",
52 | "dist/*.js.map",
53 | "dist/*.json"
54 | ],
55 | "homepage": "http://developers.arcgis.com/esri-leaflet",
56 | "jsnext:main": "src/EsriLeafletRenderers.js",
57 | "jspm": {
58 | "registry": "npm",
59 | "format": "es6",
60 | "main": "src/EsriLeafletRenderers.js"
61 | },
62 | "keywords": [
63 | "arcgis",
64 | "esri",
65 | "esri leaflet",
66 | "gis",
67 | "leaflet plugin",
68 | "mapping",
69 | "renderers",
70 | "symbology"
71 | ],
72 | "license": "Apache-2.0",
73 | "main": "dist/esri-leaflet-renderers-debug.js",
74 | "module": "src/EsriLeafletRenderers.js",
75 | "browser": "dist/esri-leaflet-renderers-debug.js",
76 | "readmeFilename": "README.md",
77 | "repository": {
78 | "type": "git",
79 | "url": "git@github.com:Esri/esri-leaflet-renderers.git"
80 | },
81 | "scripts": {
82 | "prebuild": "mkdirp dist",
83 | "build": "rollup -c profiles/debug.js & rollup -c profiles/production.js",
84 | "lint": "semistandard src/**/*.js | snazzy",
85 | "fix": "semistandard --fix",
86 | "pretest": "npm run build",
87 | "release": "./scripts/release.sh",
88 | "start-watch": "chokidar src -c \"npm run build\"",
89 | "start": "run-p start-watch serve",
90 | "serve": "http-server -p 5000 -c-1 -o",
91 | "test": "npm run lint && karma start",
92 | "test:ci": "npm run lint && karma start --browsers Chrome_travis_ci"
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/profiles/base.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Esri/esri-leaflet/pull/1125
2 | // import config from '../node_modules/esri-leaflet/profiles/base.js';
3 |
4 | import json from '@rollup/plugin-json';
5 | import nodeResolve from '@rollup/plugin-node-resolve';
6 |
7 | var pkg = require('../package.json');
8 | var copyright = '/* ' + pkg.name + ' - v' + pkg.version + ' - ' + new Date().toString() + '\n' +
9 | ' * Copyright (c) ' + new Date().getFullYear() + ' Environmental Systems Research Institute, Inc.\n' +
10 | ' * ' + pkg.license + ' */';
11 |
12 | var config = {
13 | input: 'src/EsriLeaflet.js',
14 | external: [
15 | 'leaflet',
16 | 'esri-leaflet',
17 | 'esri-leaflet-cluster'
18 | ],
19 | plugins: [
20 | nodeResolve({
21 | jsnext: true,
22 | main: false,
23 | browser: false,
24 | extensions: [ '.js', '.json' ]
25 | }),
26 | json()
27 | ],
28 |
29 | output: {
30 | banner: copyright,
31 | format: 'umd',
32 | name: 'L.esri',
33 | globals: {
34 | 'leaflet': 'L',
35 | 'esri-leaflet': 'L.esri',
36 | 'esri-leaflet-cluster': 'L.esri.Cluster'
37 | },
38 | sourcemap: true
39 | }
40 | };
41 |
42 | // end needless duplication
43 | config.input = 'src/EsriLeafletRenderers.js';
44 | config.output.name = 'L.esri.Renderers';
45 | config.output.sourcemap = true;
46 |
47 | export default config;
48 |
--------------------------------------------------------------------------------
/profiles/debug.js:
--------------------------------------------------------------------------------
1 | import config from './base.js';
2 |
3 | config.output.file = 'dist/esri-leaflet-renderers-debug.js';
4 |
5 | export default config;
6 |
--------------------------------------------------------------------------------
/profiles/production.js:
--------------------------------------------------------------------------------
1 | import terser from "@rollup/plugin-terser";
2 | import config from "./base.js";
3 |
4 | config.output.file = "dist/esri-leaflet-renderers.js";
5 |
6 | // use a Regex to preserve copyright text
7 | config.plugins.push(terser({ format: { comments: /Institute, Inc/ } }));
8 |
9 | export default config;
10 |
--------------------------------------------------------------------------------
/scripts/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # config
4 | VERSION=$(node --eval "console.log(require('./package.json').version);")
5 | NAME=$(node --eval "console.log(require('./package.json').name);")
6 |
7 | # build and test
8 | npm test || exit 1
9 |
10 | # Integrity string and save to siteData.json
11 | JS_INTEGRITY=$(cat dist/esri-leaflet-renderers.js | openssl dgst -sha512 -binary | openssl base64 -A)
12 | echo "{\"name\": \"esri-leaflet-renderers\",\"version\": \"$VERSION\",\"lib\": {\"path\": \"dist/esri-leaflet-renderers.js\",\"integrity\": \"sha512-$JS_INTEGRITY\"}}" > dist/siteData.json
13 |
14 | # checkout temp branch for release
15 | git checkout -b gh-release
16 |
17 | # force add files
18 | git add dist -f
19 |
20 | # commit changes with a versioned commit message
21 | git commit -m "build $VERSION"
22 |
23 | # push commit so it exists on GitHub when we run gh-release
24 | git push git@github.com:Esri/esri-leaflet-renderers.git gh-release
25 |
26 | # create a ZIP archive of the dist files
27 | zip -r $NAME-v$VERSION.zip dist
28 |
29 | # run gh-release to create the tag and push release to github
30 | gh-release --assets $NAME-v$VERSION.zip
31 |
32 | # publish release on NPM
33 | npm publish
34 |
35 | # checkout master and delete release branch locally and on GitHub
36 | git checkout master
37 | git branch -D gh-release
38 | git push git@github.com:Esri/esri-leaflet-renderers.git :gh-release
39 |
--------------------------------------------------------------------------------
/spec/Markers/CrossMarkerSpec.js:
--------------------------------------------------------------------------------
1 | /* global L beforeEach describe expect it */
2 | describe('CrossMarker', function () {
3 | describe('#_size', function () {
4 | var map;
5 | beforeEach(function () {
6 | map = L.map(document.createElement('div'));
7 | map.setView([0, 0], 1);
8 | });
9 | describe('when were ready to get started ', function () {
10 | it('shapeMarkers should have been loaded successfully.', function () {
11 | var marker = L.shapeMarkers.crossMarker();
12 | expect(marker).to.not.eq(undefined);
13 | });
14 | });
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/spec/Renderers/ClassBreaksRendererSpec.js:
--------------------------------------------------------------------------------
1 | /* global L beforeEach describe expect it */
2 | describe('ClassBreaksRenderer', function () {
3 | describe('should create renderer from JSON', function () {
4 | var rendererJson;
5 |
6 | beforeEach(function () {
7 | rendererJson = {
8 | 'type': 'classBreaks',
9 | 'field': 'SHAPE_AREA',
10 | 'defaultSymbol': null,
11 | 'minValue': 41569,
12 | 'classBreakInfos': [
13 | {
14 | 'classMaxValue': 15327379,
15 | 'symbol': {
16 | 'type': 'esriSFS',
17 | 'style': 'esriSFSSolid',
18 | 'color': [237, 248, 233, 128],
19 | 'outline': {
20 | 'type': 'esriSLS',
21 | 'style': 'esriSLSSolid',
22 | 'color': [0, 0, 0, 255],
23 | 'width': 1.5
24 | }
25 | }
26 | },
27 | {
28 | 'classMaxValue': 64615118,
29 | 'symbol': {
30 | 'type': 'esriSFS',
31 | 'style': 'esriSFSSolid',
32 | 'color': [116, 196, 118, 128],
33 | 'outline': {
34 | 'type': 'esriSLS',
35 | 'style': 'esriSLSSolid',
36 | 'color': [0, 0, 0, 255],
37 | 'width': 1.5
38 | }
39 | }
40 | },
41 | {
42 | 'classMaxValue': 38231763,
43 | 'symbol': {
44 | 'type': 'esriSFS',
45 | 'style': 'esriSFSSolid',
46 | 'color': [177, 222, 176, 128],
47 | 'outline': {
48 | 'type': 'esriSLS',
49 | 'style': 'esriSLSSolid',
50 | 'color': [0, 0, 0, 255],
51 | 'width': 1.5
52 | }
53 | }
54 | }]
55 | };
56 | });
57 |
58 | it('should create three symbols', function () {
59 | var renderer = L.esri.Renderers.classBreaksRenderer(rendererJson);
60 | expect(renderer._symbols.length).to.be.eq(3);
61 | });
62 |
63 | it('should order the symbols', function () {
64 | var renderer = L.esri.Renderers.classBreaksRenderer(rendererJson);
65 |
66 | expect(renderer._symbols[0].val).to.be.eq(15327379);
67 | expect(renderer._symbols[1].val).to.be.eq(38231763);
68 | expect(renderer._symbols[2].val).to.be.eq(64615118);
69 | });
70 | it('should get symbol for a value that falls on a classbreak', function () {
71 | var renderer = L.esri.Renderers.classBreaksRenderer(rendererJson);
72 | var feature = { 'properties': { 'SHAPE_AREA': 38231763 } };
73 | var sym = renderer._getSymbol(feature);
74 | expect(sym.val).to.be.eq(38231763);
75 | });
76 | it('should get symbol for a value that falls within a classbreak range', function () {
77 | var renderer = L.esri.Renderers.classBreaksRenderer(rendererJson);
78 | var feature = { 'properties': { 'SHAPE_AREA': 50000000 } };
79 | var sym = renderer._getSymbol(feature);
80 | expect(sym.val).to.be.eq(64615118);
81 | });
82 |
83 | it('should merge symbol styles', function () {
84 | var options = {
85 | userDefinedStyle: function (feature) {
86 | return { opacity: 0.5 };
87 | }
88 | };
89 | var renderer = L.esri.Renderers.classBreaksRenderer(rendererJson, options);
90 | var feature = { 'properties': { 'SHAPE_AREA': 50000000 } };
91 | var style = renderer.style(feature);
92 | // user style
93 | expect(style.opacity).to.be.eq(0.5);
94 | // renderer style
95 | expect(style.weight).to.be.greaterThan(1);
96 | });
97 | });
98 | });
99 |
--------------------------------------------------------------------------------
/spec/Renderers/SimpleRendererSpec.js:
--------------------------------------------------------------------------------
1 | /* global L beforeEach describe expect it */
2 | describe('SimpleRenderer', function () {
3 | describe('should create renderer from JSON', function () {
4 | var rendererJson;
5 |
6 | beforeEach(function () {
7 | rendererJson = {
8 | 'type': 'simple',
9 | 'symbol': {
10 | 'type': 'esriSFS',
11 | 'style': 'esriSFSSolid',
12 | 'color': [255, 214, 180, 255],
13 | 'outline': {
14 | 'type': 'esriSLS',
15 | 'style': 'esriSLSSolid',
16 | 'color': [251, 164, 93, 255],
17 | 'width': 0.75
18 | }
19 | }
20 | };
21 | });
22 |
23 | it('should create one symbol', function () {
24 | var renderer = L.esri.Renderers.simpleRenderer(rendererJson);
25 | expect(renderer._symbols.length).to.be.eq(1);
26 | });
27 |
28 | it('should merge symbol styles', function () {
29 | var options = {
30 | userDefinedStyle: function (feature) {
31 | return { opacity: 0.5 };
32 | }
33 | };
34 | var renderer = L.esri.Renderers.simpleRenderer(rendererJson, options);
35 | var style = renderer.style();
36 | // user style
37 | expect(style.opacity).to.be.eq(0.5);
38 | // renderer style
39 | expect(style.weight).to.be.lessThan(1);
40 | });
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/spec/Renderers/SmartClassBreaksRendererSpec.js:
--------------------------------------------------------------------------------
1 | /* global L beforeEach describe expect it */
2 | describe('SmartClassbreaksRenderer', function () {
3 | describe('should create renderer with size variables from JSON', function () {
4 | var renderer, pointFeatureOne, pointFeatureTwo, sizeInfoJson;
5 |
6 | beforeEach(function () {
7 | sizeInfoJson = {
8 | 'visualVariables': [{
9 | 'type': 'sizeInfo',
10 | 'field': 'FIELD_ONE',
11 | 'minSize': 1,
12 | 'maxSize': 37.5,
13 | 'minDataValue': 0,
14 | 'maxDataValue': 113
15 | }],
16 | 'type': 'classBreaks',
17 | 'field': 'DIAMETER',
18 | 'minValue': -9007199254740991,
19 | 'classBreakInfos': [{
20 | 'symbol': {
21 | 'color': [227, 139, 79, 204],
22 | 'size': 9,
23 | 'angle': 0,
24 | 'xoffset': 0,
25 | 'yoffset': 0,
26 | 'type': 'esriSMS',
27 | 'style': 'esriSMSCircle',
28 | 'outline': {
29 | 'color': [255, 255, 255, 255],
30 | 'width': 0.75,
31 | 'type': 'esriSLS',
32 | 'style': 'esriSLSSolid'
33 | }
34 | },
35 | 'classMaxValue': 9007199254740991
36 | }]
37 | };
38 | pointFeatureOne = {
39 | 'type': 'Point',
40 | 'properties': {
41 | 'FID': 1,
42 | 'FIELD_ONE': 2,
43 | 'FIELD_TWO': 36
44 | }
45 | };
46 | pointFeatureTwo = {
47 | 'type': 'Point',
48 | 'properties': {
49 | 'FID': 2,
50 | 'FIELD_ONE': 50,
51 | 'FIELD_TWO': 36
52 | }
53 | };
54 | renderer = L.esri.Renderers.classBreaksRenderer(sizeInfoJson);
55 | });
56 |
57 | it('size info visual variables should create one base symbol', function () {
58 | expect(renderer._symbols.length).to.be.eq(1);
59 | expect(renderer._symbols[0].val).to.be.eq(9007199254740991);
60 | });
61 |
62 | it('should get different circle marker sizes for different feature values', function () {
63 | var sizeOne = renderer.pointToLayer(pointFeatureOne, [0, 0]).options.radius;
64 | var sizeTwo = renderer.pointToLayer(pointFeatureTwo, [0, 0]).options.radius;
65 | expect(sizeOne).not.to.be.eq(sizeTwo);
66 | });
67 | });
68 | describe('should create renderer with color variables from JSON', function () {
69 | var renderer, polygonFeatureOne, polygonFeatureTwo, colorInfoJson;
70 |
71 | beforeEach(function () {
72 | colorInfoJson = {
73 | 'visualVariables': [{
74 | 'type': 'colorInfo',
75 | 'field': 'FIELD_ONE',
76 | 'stops': [
77 | {
78 | 'value': 4.6,
79 | 'color': [255, 252, 212, 204]
80 | }, {
81 | 'value': 5.95,
82 | 'color': [224, 178, 193, 204]
83 | }, {
84 | 'value': 7.3,
85 | 'color': [193, 104, 173, 204]
86 | }, {
87 | 'value': 8.65,
88 | 'color': [123, 53, 120, 204]
89 | }, {
90 | 'value': 10,
91 | 'color': [53, 2, 66, 204]
92 | }
93 | ]
94 | }],
95 | 'type': 'classBreaks',
96 | 'field': 'FIELD_ONE',
97 | 'minValue': -9007199254740991,
98 | 'classBreakInfos': [{
99 | 'symbol': {
100 | 'color': [170, 170, 170, 204],
101 | 'outline': {
102 | 'color': [153, 153, 153, 255],
103 | 'width': 0.375,
104 | 'type': 'esriSLS',
105 | 'style': 'esriSLSSolid'
106 | },
107 | 'type': 'esriSFS',
108 | 'style': 'esriSFSSolid'
109 | },
110 | 'classMaxValue': 9007199254740991
111 | }]
112 | };
113 | polygonFeatureOne = {
114 | 'type': 'Polygon',
115 | 'properties': {
116 | 'FID': 1,
117 | 'FIELD_ONE': 6,
118 | 'FIELD_TWO': 10
119 | }
120 | };
121 | polygonFeatureTwo = {
122 | 'type': 'Polygon',
123 | 'properties': {
124 | 'FID': 2,
125 | 'FIELD_ONE': 8,
126 | 'FIELD_TWO': 36
127 | }
128 | };
129 | renderer = L.esri.Renderers.classBreaksRenderer(colorInfoJson);
130 | });
131 |
132 | it('color info visual variables should create one base symbol', function () {
133 | expect(renderer._symbols.length).to.be.eq(1);
134 | expect(renderer._symbols[0].val).to.be.eq(9007199254740991);
135 | });
136 |
137 | it('should get different polygon fills for different feature values', function () {
138 | var fillOne = renderer.style(polygonFeatureOne).fillColor;
139 | var fillTwo = renderer.style(polygonFeatureTwo).fillColor;
140 | expect(fillOne).not.to.be.eq(fillTwo);
141 | });
142 | });
143 | });
144 |
--------------------------------------------------------------------------------
/spec/Renderers/UniqueValueRendererSpec.js:
--------------------------------------------------------------------------------
1 | /* global L beforeEach describe expect it */
2 | describe('UniqueValueRenderer', function () {
3 | describe('should create renderer from JSON', function () {
4 | var rendererJson;
5 |
6 | beforeEach(function () {
7 | rendererJson = {
8 | 'type': 'uniqueValue',
9 | 'field1': 'ZONE',
10 | 'defaultSymbol': {
11 | 'type': 'esriSFS',
12 | 'style': 'esriSFSSolid',
13 | 'color': [0, 0, 0, 64],
14 | 'outline': {
15 | 'type': 'esriSLS',
16 | 'style': 'esriSLSSolid',
17 | 'color': [0, 0, 0, 51],
18 | 'width': 1
19 | }
20 | },
21 | 'uniqueValueInfos': [
22 | {
23 | 'value': '-12',
24 | 'symbol': {
25 | 'type': 'esriSFS',
26 | 'style': 'esriSFSSolid',
27 | 'color': [255, 255, 255, 128],
28 | 'outline': {
29 | 'type': 'esriSLS',
30 | 'style': 'esriSLSSolid',
31 | 'color': [128, 128, 128, 255],
32 | 'width': 1.5
33 | }
34 | }
35 | },
36 | {
37 | 'value': '-11',
38 | 'symbol': {
39 | 'type': 'esriSFS',
40 | 'style': 'esriSFSSolid',
41 | 'color': [192, 192, 192, 128],
42 | 'outline': {
43 | 'type': 'esriSLS',
44 | 'style': 'esriSLSSolid',
45 | 'color': [128, 128, 128, 255],
46 | 'width': 1.5
47 | }
48 | }
49 | },
50 | {
51 | 'value': '-10',
52 | 'symbol': {
53 | 'type': 'esriSFS',
54 | 'style': 'esriSFSSolid',
55 | 'color': [255, 255, 255, 128],
56 | 'outline': {
57 | 'type': 'esriSLS',
58 | 'style': 'esriSLSSolid',
59 | 'color': [128, 128, 128, 255],
60 | 'width': 1.5
61 | }
62 | }
63 | }
64 | ]
65 | };
66 | });
67 |
68 | it('should create three symbols', function () {
69 | var renderer = L.esri.Renderers.uniqueValueRenderer(rendererJson);
70 | expect(renderer._symbols.length).to.be.eq(3);
71 | });
72 |
73 | it('should merge symbol styles', function () {
74 | var options = {
75 | userDefinedStyle: function (feature) {
76 | return { opacity: 0.5 };
77 | }
78 | };
79 | var renderer = L.esri.Renderers.uniqueValueRenderer(rendererJson, options);
80 | var feature = { 'properties': { 'ZONE': -12, 'VALUE': '$25.00', 'MARKET': '2Z' } };
81 | var style = renderer.style(feature);
82 | // user style
83 | expect(style.opacity).to.be.eq(0.5);
84 | // renderer style
85 | expect(style.weight).to.be.greaterThan(1);
86 | });
87 |
88 | describe('symbol transparency', function () {
89 | it('should be equal to symbol value when no layer transparency defined', function () {
90 | var renderer = L.esri.Renderers.uniqueValueRenderer(rendererJson);
91 | expect(renderer._symbols[0]._styles.fillOpacity).to.be.eq(128 / 255.0);
92 | expect(renderer._symbols[0]._lineStyles.opacity).to.be.eq(1);
93 | expect(renderer._defaultSymbol._styles.fillOpacity).to.be.eq(64 / 255.0);
94 | expect(renderer._defaultSymbol._lineStyles.opacity).to.be.eq(51 / 255.0);
95 | });
96 |
97 | it('should be equal to symbol value with transparency applied when defined', function () {
98 | var renderer = L.esri.Renderers.uniqueValueRenderer(rendererJson, { layerTransparency: 75 });
99 | expect(renderer._symbols[0]._styles.fillOpacity).to.be.eq(128 / 255.0 * 0.25);
100 | expect(renderer._symbols[0]._lineStyles.opacity).to.be.eq(0.25);
101 | expect(renderer._defaultSymbol._styles.fillOpacity).to.be.eq(64 / 255.0 * 0.25);
102 | expect(renderer._defaultSymbol._lineStyles.opacity).to.be.eq(51 / 255.0 * 0.25);
103 | });
104 | });
105 |
106 | it('should create a default symbol', function () {
107 | var renderer = L.esri.Renderers.uniqueValueRenderer(rendererJson);
108 | expect(renderer._defaultSymbol).to.not.equal(undefined);
109 | });
110 |
111 | it('should get default symbol when no matching value', function () {
112 | var renderer = L.esri.Renderers.uniqueValueRenderer(rendererJson);
113 | var feature = { 'properties': { 'ZONE': 5 } };
114 | var sym = renderer._getSymbol(feature);
115 | expect(sym.val).to.be.equal(null);
116 | });
117 |
118 | it('should get symbol for that matches the value', function () {
119 | var renderer = L.esri.Renderers.uniqueValueRenderer(rendererJson);
120 | var feature = { 'properties': { 'ZONE': -10 } };
121 | var sym = renderer._getSymbol(feature);
122 | expect(sym.val).to.be.eq('-10');
123 | });
124 | });
125 |
126 | describe('should renderer based on multiple fields', function () {
127 | var multipleFieldRendererJson;
128 |
129 | beforeEach(function () {
130 | multipleFieldRendererJson = {
131 | 'type': 'uniqueValue',
132 | 'field1': 'ZONE',
133 | 'field2': 'MARKET',
134 | 'field3': 'VALUE',
135 | 'fieldDelimiter': ',',
136 | 'defaultSymbol': {
137 | 'type': 'esriSFS',
138 | 'style': 'esriSFSSolid',
139 | 'color': [0, 0, 0, 64],
140 | 'outline': {
141 | 'type': 'esriSLS',
142 | 'style': 'esriSLSSolid',
143 | 'color': [0, 0, 0, 51],
144 | 'width': 1
145 | }
146 | },
147 | 'uniqueValueInfos': [
148 | {
149 | 'value': '-12,2Z,$25.00',
150 | 'symbol': {
151 | 'type': 'esriSFS',
152 | 'style': 'esriSFSSolid',
153 | 'color': [255, 255, 255, 128],
154 | 'outline': {
155 | 'type': 'esriSLS',
156 | 'style': 'esriSLSSolid',
157 | 'color': [128, 128, 128, 255],
158 | 'width': 1.5
159 | }
160 | }
161 | }
162 | ]
163 | };
164 | });
165 | it('should get default symbol when not matching all fields', function () {
166 | var renderer = L.esri.Renderers.uniqueValueRenderer(multipleFieldRendererJson);
167 | var feature = { 'properties': { 'ZONE': -12, 'MARKET': '2Z' } };
168 | var sym = renderer._getSymbol(feature);
169 | expect(sym.val).to.be.eq(null);
170 | });
171 |
172 | it('should get symbol for that matches the value', function () {
173 | var renderer = L.esri.Renderers.uniqueValueRenderer(multipleFieldRendererJson);
174 | var feature = { 'properties': { 'ZONE': -12, 'VALUE': '$25.00', 'MARKET': '2Z' } };
175 | var sym = renderer._getSymbol(feature);
176 | expect(sym.val).to.be.eq('-12,2Z,$25.00');
177 | });
178 | });
179 | });
180 |
--------------------------------------------------------------------------------
/spec/Symbols/LineSymbolSpec.js:
--------------------------------------------------------------------------------
1 | /* global L beforeEach describe expect it */
2 | describe('LineSymbol', function () {
3 | describe('#_symbolJson', function () {
4 | var symbolHelper;
5 |
6 | beforeEach(function () {
7 | symbolHelper = new L.esri.Renderers.Symbol();
8 | });
9 |
10 | it('should set defaults', function () {
11 | var symbol = L.esri.Renderers.lineSymbol({});
12 | var styles = symbol.style();
13 | expect(styles.lineCap).to.be.eq('butt');
14 | expect(styles.lineJoin).to.be.eq('miter');
15 | expect(styles.weight).to.be.equal(0);
16 | expect(styles.color).to.be.equal(undefined);
17 | expect(styles.dashArray).to.be.equal(undefined);
18 | });
19 |
20 | describe('should set style from solid line symbol esriSLSSolid', function () {
21 | var solidLine;
22 |
23 | beforeEach(function () {
24 | solidLine = {
25 | 'type': 'esriSLS',
26 | 'style': 'esriSLSSolid',
27 | 'color': [255, 85, 0, 255],
28 | 'width': 1.4
29 | };
30 | });
31 |
32 | it('should set solid line parameters', function () {
33 | var symbol = L.esri.Renderers.lineSymbol(solidLine);
34 | var styles = symbol.style();
35 | var c = symbolHelper.colorValue(solidLine.color);
36 | var o = symbolHelper.alphaValue(solidLine.color);
37 | expect(styles.color).to.be.eq(c);
38 | expect(styles.opacity).to.be.eq(o);
39 | expect(styles.dashArray).to.be.equal(undefined);
40 | expect(styles.weight).to.be.eq(symbolHelper.pixelValue(solidLine.width));
41 | });
42 |
43 | it('should set weight to 0 if width is 0', function () {
44 | solidLine.width = 0;
45 | var symbol = L.esri.Renderers.lineSymbol(solidLine);
46 | var styles = symbol.style();
47 |
48 | expect(styles.weight).to.be.equal(0);
49 | });
50 | });
51 |
52 | describe('should set style from pattern line symbol', function () {
53 | var dashedLine;
54 |
55 | beforeEach(function () {
56 | dashedLine = {
57 | 'type': 'esriSLS',
58 | 'color': [0, 0, 0, 255],
59 | 'width': 2
60 | };
61 | });
62 | it('should set esriSLSDot parameters', function () {
63 | dashedLine.style = 'esriSLSDot';
64 | var symbol = L.esri.Renderers.lineSymbol(dashedLine);
65 | var styles = symbol.style();
66 | expect(styles.dashArray).not.to.be.equal(undefined);
67 | });
68 | it('should set esriSLSDash line parameters', function () {
69 | dashedLine.style = 'esriSLSDash';
70 | var symbol = L.esri.Renderers.lineSymbol(dashedLine);
71 | var styles = symbol.style();
72 | expect(styles.dashArray).not.to.be.equal(undefined);
73 | });
74 | it('should set esriSLSDashDot line parameters', function () {
75 | dashedLine.style = 'esriSLSDashDot';
76 | var symbol = L.esri.Renderers.lineSymbol(dashedLine);
77 | var styles = symbol.style();
78 | expect(styles.dashArray).not.to.be.equal(undefined);
79 | });
80 | it('should set esriSLSDashDotDot line parameters', function () {
81 | dashedLine.style = 'esriSLSDashDotDot';
82 | var symbol = L.esri.Renderers.lineSymbol(dashedLine);
83 | var styles = symbol.style();
84 | expect(styles.dashArray).not.to.be.equal(undefined);
85 | });
86 | });
87 | });
88 | });
89 |
--------------------------------------------------------------------------------
/spec/Symbols/PointSymbolSpec.js:
--------------------------------------------------------------------------------
1 | /* global L beforeEach describe expect it */
2 | describe('PointSymbol', function () {
3 | describe('#_symbolJson', function () {
4 | it('should set defaults', function () {
5 | var symbol = L.esri.Renderers.pointSymbol({});
6 | var styles = symbol._styles;
7 | expect(styles.stroke).to.be.eq(false);
8 | });
9 |
10 | describe('should set style from point symbol json', function () {
11 | var pointSymbolJson;
12 |
13 | beforeEach(function () {
14 | pointSymbolJson = {
15 | 'type': 'esriSMS',
16 | 'style': 'esriSMSquare',
17 | 'color': [0, 0, 128, 128],
18 | 'size': 15,
19 | 'angle': 0,
20 | 'xoffset': 0,
21 | 'yoffset': 0,
22 | 'outline': {
23 | 'color': [0, 0, 128, 255],
24 | 'width': 1
25 | }
26 | };
27 | });
28 | it('should set square parameters', function () {
29 | var symbol = L.esri.Renderers.pointSymbol(pointSymbolJson);
30 | var styles = symbol._styles;
31 |
32 | expect(symbol.icon).to.be.equal(undefined);
33 | expect(styles).not.to.be.equal(undefined);
34 | });
35 | });
36 |
37 | describe('should set style from icon symbol json', function () {
38 | var iconSymbolJson, fLayer;
39 |
40 | beforeEach(function () {
41 | iconSymbolJson = {
42 | 'type': 'esriPMS',
43 | 'url': '5661274d49834505d5815990f7696493',
44 | 'imageData': 'iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAAAXNSR0IB2cksfwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAP5JREFUKJGFkT1KxGAURc88nqmCbUqZ0kGEwc4thJhiygHdhI3YWFhPkUq0EBcQIX5bsLdw7I0L0P4jXGxGDUOCr7yXc9+fM1KLxeIoxrgXQnjs6z4GSLozs2fgf6AoikNJc0m3294g4O6nkkiS5K0XsnT3l18gz/MUSCVNJC038kee56mZZWZ2I+nYN/S9mZ0Bk36nruve3f+GcPfOAZIkuYoxvrr7LjCRdAHsAJeSortnks5',
45 | 'contentType': 'image/png',
46 | 'width': 9,
47 | 'height': 9,
48 | 'angle': 0,
49 | 'xoffset': 0,
50 | 'yoffset': 0
51 | };
52 | fLayer = 'http://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/USA_Airports/FeatureServer/0';
53 | });
54 |
55 | it('should set icon parameters', function () {
56 | var symbol = L.esri.Renderers.pointSymbol(iconSymbolJson, { url: fLayer });
57 | var styles = symbol._styles;
58 |
59 | expect(symbol.icon).not.to.be.equal(undefined);
60 | expect(symbol.serviceUrl).to.be.eq(fLayer);
61 | expect(styles.stroke).to.be.equal(undefined);
62 | });
63 | });
64 | });
65 | });
66 |
--------------------------------------------------------------------------------
/spec/Symbols/PolygonSymbolSpec.js:
--------------------------------------------------------------------------------
1 | /* global L beforeEach describe expect it */
2 | describe('PolygonSymbol', function () {
3 | describe('#_symbolJson', function () {
4 | var symbolHelper;
5 |
6 | beforeEach(function () {
7 | symbolHelper = new L.esri.Renderers.Symbol();
8 | });
9 |
10 | describe('should set style from solid polygon symbol esriFSSolid', function () {
11 | var solidPolygon;
12 |
13 | beforeEach(function () {
14 | solidPolygon = {
15 | 'type': 'esriSFS',
16 | 'style': 'esriSFSSolid',
17 | 'color': [237, 248, 233, 128],
18 | 'outline': {
19 | 'type': 'esriSLS',
20 | 'style': 'esriSLSSolid',
21 | 'color': [0, 0, 0, 255],
22 | 'width': 1.5
23 | }
24 | };
25 | });
26 |
27 | it('should set solid polygon parameters', function () {
28 | var symbol = L.esri.Renderers.polygonSymbol(solidPolygon);
29 | var styles = symbol.style();
30 |
31 | expect(styles.fill).to.be.eq(true);
32 | expect(styles.fillColor).to.be.eq(symbolHelper.colorValue(solidPolygon.color));
33 | expect(styles.fillOpacity).to.be.eq(symbolHelper.alphaValue(solidPolygon.color));
34 | expect(styles.color).to.be.eq(symbolHelper.colorValue(solidPolygon.outline.color));
35 | expect(styles.opacity).to.be.eq(symbolHelper.alphaValue(solidPolygon.outline.color));
36 | });
37 |
38 | it('should set line stroke to false if line width is 0', function () {
39 | solidPolygon.outline.width = 0;
40 | var symbol = L.esri.Renderers.polygonSymbol(solidPolygon);
41 | var styles = symbol.style();
42 |
43 | expect(styles.stroke).to.be.eq(false);
44 | });
45 |
46 | it('should set line stroke to false if outline is null', function () {
47 | solidPolygon.outline = null;
48 | var symbol = L.esri.Renderers.polygonSymbol(solidPolygon);
49 | var styles = symbol.style();
50 |
51 | expect(styles.stroke).to.be.eq(false);
52 | });
53 | });
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/src/EsriLeafletRenderers.js:
--------------------------------------------------------------------------------
1 | import './FeatureLayerHook';
2 |
3 | import packageInfo from '../package.json';
4 | var version = packageInfo.version;
5 | export { version as VERSION };
6 |
7 | export { Renderer } from './Renderers/Renderer';
8 | export { SimpleRenderer, simpleRenderer } from './Renderers/SimpleRenderer';
9 | export { ClassBreaksRenderer, classBreaksRenderer } from './Renderers/ClassBreaksRenderer';
10 | export { UniqueValueRenderer, uniqueValueRenderer } from './Renderers/UniqueValueRenderer';
11 |
12 | export { Symbol } from './Symbols/Symbol';
13 | export { PointSymbol, pointSymbol } from './Symbols/PointSymbol';
14 | export { LineSymbol, lineSymbol } from './Symbols/LineSymbol';
15 | export { PolygonSymbol, polygonSymbol } from './Symbols/PolygonSymbol';
16 |
--------------------------------------------------------------------------------
/src/FeatureLayerHook.js:
--------------------------------------------------------------------------------
1 | import { Util, GeoJSON, geoJson } from 'leaflet';
2 | import * as EsriLeaflet from 'esri-leaflet';
3 | import EsriLeafletCluster, { FeatureLayer as EsriLeafletClusterFeatureLayer } from 'esri-leaflet-cluster';
4 | import classBreaksRenderer from './Renderers/ClassBreaksRenderer';
5 | import uniqueValueRenderer from './Renderers/UniqueValueRenderer';
6 | import simpleRenderer from './Renderers/SimpleRenderer';
7 |
8 | function wireUpRenderers () {
9 | if (this.options.ignoreRenderer) {
10 | return;
11 | }
12 | var oldOnAdd = Util.bind(this.onAdd, this);
13 | var oldUnbindPopup = Util.bind(this.unbindPopup, this);
14 | var oldOnRemove = Util.bind(this.onRemove, this);
15 |
16 | Util.bind(this.createNewLayer, this);
17 |
18 | this.onAdd = function (map) {
19 | this.metadata(function (error, response) {
20 | if (error) {
21 | console.warn('failed to load metadata from the service.');
22 | return;
23 | } if (response && response.drawingInfo) {
24 | if (this.options.drawingInfo) {
25 | // allow L.esri.webmap (and others) to override service symbology with info provided in layer constructor
26 | response.drawingInfo = this.options.drawingInfo;
27 | }
28 |
29 | // the default pane for lines and polygons is 'overlayPane', for points it is 'markerPane'
30 | if (this.options.pane === 'overlayPane' && response.geometryType === 'esriGeometryPoint') {
31 | this.options.pane = 'markerPane';
32 | }
33 |
34 | this._setRenderers(response);
35 | oldOnAdd(map);
36 | this._addPointLayer(map);
37 | }
38 | }, this);
39 | };
40 |
41 | this.onRemove = function (map) {
42 | oldOnRemove(map);
43 | if (this._pointLayer) {
44 | var pointLayers = this._pointLayer.getLayers();
45 | for (var i in pointLayers) {
46 | map.removeLayer(pointLayers[i]);
47 | }
48 | }
49 | };
50 |
51 | this.unbindPopup = function () {
52 | oldUnbindPopup();
53 | if (this._pointLayer) {
54 | var pointLayers = this._pointLayer.getLayers();
55 | for (var i in pointLayers) {
56 | pointLayers[i].unbindPopup();
57 | }
58 | }
59 | };
60 |
61 | this._addPointLayer = function (map) {
62 | if (this._pointLayer) {
63 | this._pointLayer.addTo(map);
64 | this._pointLayer.bringToFront();
65 | }
66 | };
67 |
68 | this._createPointLayer = function () {
69 | if (!this._pointLayer) {
70 | this._pointLayer = geoJson();
71 | // store the feature ids that have already been added to the map
72 | this._pointLayerIds = {};
73 |
74 | if (this._popup) {
75 | var popupFunction = function (feature, layer) {
76 | layer.bindPopup(this._popup(feature, layer), this._popupOptions);
77 | };
78 | this._pointLayer.options.onEachFeature = Util.bind(popupFunction, this);
79 | }
80 | }
81 | };
82 |
83 | this.createNewLayer = function (geojson) {
84 | var fLayer = GeoJSON.geometryToLayer(geojson, this.options);
85 |
86 | // add a point layer when the polygon is represented as proportional marker symbols
87 | if (this._hasProportionalSymbols) {
88 | var centroid = this.getPolygonCentroid(geojson.geometry.coordinates);
89 | if (!(isNaN(centroid[0]) || isNaN(centroid[0]))) {
90 | this._createPointLayer();
91 |
92 | var featureId = geojson.id.toString();
93 | // only add the feature if it does not already exist on the map
94 | if (!this._pointLayerIds[featureId]) {
95 | var pointjson = this.getPointJson(geojson, centroid);
96 |
97 | this._pointLayer.addData(pointjson);
98 | this._pointLayerIds[featureId] = true;
99 | }
100 |
101 | this._pointLayer.bringToFront();
102 | }
103 | }
104 | return fLayer;
105 | };
106 |
107 | this.getPolygonCentroid = function (coordinates) {
108 | var pts = coordinates[0][0];
109 | if (pts.length === 2) {
110 | pts = coordinates[0];
111 | }
112 |
113 | var twicearea = 0;
114 | var x = 0;
115 | var y = 0;
116 | var nPts = pts.length;
117 | var p1;
118 | var p2;
119 | var f;
120 |
121 | for (var i = 0, j = nPts - 1; i < nPts; j = i++) {
122 | p1 = pts[i]; p2 = pts[j];
123 | twicearea += p1[0] * p2[1];
124 | twicearea -= p1[1] * p2[0];
125 | f = (p1[0] * p2[1]) - (p2[0] * p1[1]);
126 | x += (p1[0] + p2[0]) * f;
127 | y += (p1[1] + p2[1]) * f;
128 | }
129 | f = twicearea * 3;
130 | return [x / f, y / f];
131 | };
132 |
133 | this.getPointJson = function (geojson, centroid) {
134 | return {
135 | type: 'Feature',
136 | properties: geojson.properties,
137 | id: geojson.id,
138 | geometry: {
139 | type: 'Point',
140 | coordinates: [centroid[0], centroid[1]]
141 | }
142 | };
143 | };
144 |
145 | this._checkForProportionalSymbols = function (geometryType, renderer) {
146 | this._hasProportionalSymbols = false;
147 | if (geometryType === 'esriGeometryPolygon') {
148 | if (renderer.backgroundFillSymbol) {
149 | this._hasProportionalSymbols = true;
150 | }
151 | // check to see if the first symbol in the classbreaks is a marker symbol
152 | if (renderer.classBreakInfos && renderer.classBreakInfos.length) {
153 | var sym = renderer.classBreakInfos[0].symbol;
154 | if (sym && (sym.type === 'esriSMS' || sym.type === 'esriPMS')) {
155 | this._hasProportionalSymbols = true;
156 | }
157 | }
158 | }
159 | };
160 |
161 | this._setRenderers = function (serviceInfo) {
162 | var rend;
163 | var rendererInfo = serviceInfo.drawingInfo.renderer;
164 |
165 | var options = {
166 | url: this.options.url
167 | };
168 |
169 | if (this.options.token) {
170 | options.token = this.options.token;
171 | }
172 |
173 | if (this.options.pane) {
174 | options.pane = this.options.pane;
175 | }
176 |
177 | if (serviceInfo.drawingInfo.transparency) {
178 | options.layerTransparency = serviceInfo.drawingInfo.transparency;
179 | }
180 |
181 | if (this.options.style) {
182 | options.userDefinedStyle = this.options.style;
183 | }
184 |
185 | switch (rendererInfo.type) {
186 | case 'classBreaks':
187 | this._checkForProportionalSymbols(serviceInfo.geometryType, rendererInfo);
188 | if (this._hasProportionalSymbols) {
189 | this._createPointLayer();
190 | var pRend = classBreaksRenderer(rendererInfo, options);
191 | pRend.attachStylesToLayer(this._pointLayer);
192 | options.proportionalPolygon = true;
193 | }
194 | rend = classBreaksRenderer(rendererInfo, options);
195 | break;
196 | case 'uniqueValue':
197 | rend = uniqueValueRenderer(rendererInfo, options);
198 | break;
199 | default:
200 | rend = simpleRenderer(rendererInfo, options);
201 | }
202 | rend.attachStylesToLayer(this);
203 | };
204 | }
205 |
206 | EsriLeaflet.FeatureLayer.addInitHook(wireUpRenderers);
207 |
208 | if (typeof EsriLeafletCluster !== 'undefined' && EsriLeafletClusterFeatureLayer) {
209 | EsriLeafletClusterFeatureLayer.addInitHook(wireUpRenderers);
210 | }
211 |
--------------------------------------------------------------------------------
/src/Renderers/ClassBreaksRenderer.js:
--------------------------------------------------------------------------------
1 | import Renderer from './Renderer';
2 |
3 | export var ClassBreaksRenderer = Renderer.extend({
4 | initialize: function (rendererJson, options) {
5 | Renderer.prototype.initialize.call(this, rendererJson, options);
6 | this._field = this._rendererJson.field;
7 | if (this._rendererJson.normalizationType && this._rendererJson.normalizationType === 'esriNormalizeByField') {
8 | this._normalizationField = this._rendererJson.normalizationField;
9 | }
10 | this._createSymbols();
11 | },
12 |
13 | _createSymbols: function () {
14 | var symbol;
15 | var classbreaks = this._rendererJson.classBreakInfos;
16 |
17 | this._symbols = [];
18 |
19 | // create a symbol for each class break
20 | for (var i = classbreaks.length - 1; i >= 0; i--) {
21 | if (this.options.proportionalPolygon && this._rendererJson.backgroundFillSymbol) {
22 | symbol = this._newSymbol(this._rendererJson.backgroundFillSymbol);
23 | } else {
24 | symbol = this._newSymbol(classbreaks[i].symbol);
25 | }
26 | symbol.val = classbreaks[i].classMaxValue;
27 | this._symbols.push(symbol);
28 | }
29 | // sort the symbols in ascending value
30 | this._symbols.sort(function (a, b) {
31 | return a.val > b.val ? 1 : -1;
32 | });
33 | this._createDefaultSymbol();
34 | this._maxValue = this._symbols[this._symbols.length - 1].val;
35 | },
36 |
37 | _getSymbol: function (feature) {
38 | var val = feature.properties[this._field];
39 | if (this._normalizationField) {
40 | var normValue = feature.properties[this._normalizationField];
41 | if (!isNaN(normValue) && normValue !== 0) {
42 | val = val / normValue;
43 | } else {
44 | return this._defaultSymbol;
45 | }
46 | }
47 |
48 | if (val > this._maxValue) {
49 | return this._defaultSymbol;
50 | }
51 | var symbol = this._symbols[0];
52 | for (var i = this._symbols.length - 1; i >= 0; i--) {
53 | if (val > this._symbols[i].val) {
54 | break;
55 | }
56 | symbol = this._symbols[i];
57 | }
58 | return symbol;
59 | }
60 | });
61 |
62 | export function classBreaksRenderer (rendererJson, options) {
63 | return new ClassBreaksRenderer(rendererJson, options);
64 | }
65 |
66 | export default classBreaksRenderer;
67 |
--------------------------------------------------------------------------------
/src/Renderers/Renderer.js:
--------------------------------------------------------------------------------
1 | import { Class, Util, circleMarker } from 'leaflet';
2 |
3 | import pointSymbol from '../Symbols/PointSymbol';
4 | import lineSymbol from '../Symbols/LineSymbol';
5 | import polygonSymbol from '../Symbols/PolygonSymbol';
6 |
7 | export var Renderer = Class.extend({
8 | options: {
9 | proportionalPolygon: false,
10 | clickable: true
11 | },
12 |
13 | initialize: function (rendererJson, options) {
14 | this._rendererJson = rendererJson;
15 | this._pointSymbols = false;
16 | this._symbols = [];
17 | this._visualVariables = this._parseVisualVariables(rendererJson.visualVariables);
18 | Util.setOptions(this, options);
19 | },
20 |
21 | _parseVisualVariables: function (visualVariables) {
22 | var visVars = {};
23 | if (visualVariables) {
24 | for (var i = 0; i < visualVariables.length; i++) {
25 | visVars[visualVariables[i].type] = visualVariables[i];
26 | }
27 | }
28 | return visVars;
29 | },
30 |
31 | _createDefaultSymbol: function () {
32 | if (this._rendererJson.defaultSymbol) {
33 | this._defaultSymbol = this._newSymbol(this._rendererJson.defaultSymbol);
34 | this._defaultSymbol._isDefault = true;
35 | }
36 | },
37 |
38 | _newSymbol: function (symbolJson) {
39 | if (symbolJson.type === 'esriSMS' || symbolJson.type === 'esriPMS') {
40 | this._pointSymbols = true;
41 | return pointSymbol(symbolJson, this.options);
42 | }
43 | if (symbolJson.type === 'esriSLS') {
44 | return lineSymbol(symbolJson, this.options);
45 | }
46 | if (symbolJson.type === 'esriSFS') {
47 | return polygonSymbol(symbolJson, this.options);
48 | }
49 | },
50 |
51 | _getSymbol: function () {
52 | // override
53 | },
54 |
55 | attachStylesToLayer: function (layer) {
56 | if (this._pointSymbols) {
57 | layer.options.pointToLayer = Util.bind(this.pointToLayer, this);
58 | } else {
59 | layer.options.style = Util.bind(this.style, this);
60 | layer._originalStyle = layer.options.style;
61 | }
62 | },
63 |
64 | pointToLayer: function (geojson, latlng) {
65 | var sym = this._getSymbol(geojson);
66 | if (sym && sym.pointToLayer) {
67 | // right now custom panes are the only option pushed through
68 | return sym.pointToLayer(geojson, latlng, this._visualVariables, this.options);
69 | }
70 | // invisible symbology
71 | return circleMarker(latlng, { radius: 0, opacity: 0 });
72 | },
73 |
74 | style: function (feature) {
75 | var userStyles;
76 | if (this.options.userDefinedStyle) {
77 | userStyles = this.options.userDefinedStyle(feature);
78 | }
79 | // find the symbol to represent this feature
80 | var sym = this._getSymbol(feature);
81 | if (sym) {
82 | return this.mergeStyles(sym.style(feature, this._visualVariables), userStyles);
83 | } else {
84 | // invisible symbology
85 | return this.mergeStyles({ opacity: 0, fillOpacity: 0 }, userStyles);
86 | }
87 | },
88 |
89 | mergeStyles: function (styles, userStyles) {
90 | var mergedStyles = {};
91 | var attr;
92 | // copy renderer style attributes
93 | for (attr in styles) {
94 | if (Object.prototype.hasOwnProperty.call(styles, attr)) {
95 | mergedStyles[attr] = styles[attr];
96 | }
97 | }
98 | // override with user defined style attributes
99 | if (userStyles) {
100 | for (attr in userStyles) {
101 | if (Object.prototype.hasOwnProperty.call(userStyles, attr)) {
102 | mergedStyles[attr] = userStyles[attr];
103 | }
104 | }
105 | }
106 | return mergedStyles;
107 | }
108 | });
109 |
110 | export default Renderer;
111 |
--------------------------------------------------------------------------------
/src/Renderers/SimpleRenderer.js:
--------------------------------------------------------------------------------
1 | import Renderer from './Renderer';
2 |
3 | export var SimpleRenderer = Renderer.extend({
4 | initialize: function (rendererJson, options) {
5 | Renderer.prototype.initialize.call(this, rendererJson, options);
6 | this._createSymbol();
7 | },
8 |
9 | _createSymbol: function () {
10 | if (this._rendererJson.symbol) {
11 | this._symbols.push(this._newSymbol(this._rendererJson.symbol));
12 | }
13 | },
14 |
15 | _getSymbol: function () {
16 | return this._symbols[0];
17 | }
18 | });
19 |
20 | export function simpleRenderer (rendererJson, options) {
21 | return new SimpleRenderer(rendererJson, options);
22 | }
23 |
24 | export default simpleRenderer;
25 |
--------------------------------------------------------------------------------
/src/Renderers/UniqueValueRenderer.js:
--------------------------------------------------------------------------------
1 | import Renderer from './Renderer';
2 |
3 | export var UniqueValueRenderer = Renderer.extend({
4 | initialize: function (rendererJson, options) {
5 | Renderer.prototype.initialize.call(this, rendererJson, options);
6 | this._field = this._rendererJson.field1;
7 | this._createSymbols();
8 | },
9 |
10 | _createSymbols: function () {
11 | var symbol;
12 | var uniques = this._rendererJson.uniqueValueInfos;
13 |
14 | // create a symbol for each unique value
15 | for (var i = uniques.length - 1; i >= 0; i--) {
16 | symbol = this._newSymbol(uniques[i].symbol);
17 | symbol.val = uniques[i].value;
18 | this._symbols.push(symbol);
19 | }
20 | this._createDefaultSymbol();
21 | },
22 |
23 | _getSymbol: function (feature) {
24 | var val = feature.properties[this._field];
25 | // accumulate values if there is more than one field defined
26 | if (this._rendererJson.fieldDelimiter && this._rendererJson.field2) {
27 | var val2 = feature.properties[this._rendererJson.field2];
28 | if (val2) {
29 | val += this._rendererJson.fieldDelimiter + val2;
30 | var val3 = feature.properties[this._rendererJson.field3];
31 | if (val3) {
32 | val += this._rendererJson.fieldDelimiter + val3;
33 | }
34 | }
35 | }
36 |
37 | var symbol = this._defaultSymbol;
38 | for (var i = this._symbols.length - 1; i >= 0; i--) {
39 | // using the === operator does not work if the field
40 | // of the unique renderer is not a string
41 | /*eslint-disable */
42 | if (this._symbols[i].val == val) {
43 | symbol = this._symbols[i];
44 | }
45 | /* eslint-enable */
46 | }
47 | return symbol;
48 | }
49 | });
50 |
51 | export function uniqueValueRenderer (rendererJson, options) {
52 | return new UniqueValueRenderer(rendererJson, options);
53 | }
54 |
55 | export default uniqueValueRenderer;
56 |
--------------------------------------------------------------------------------
/src/Symbols/LineSymbol.js:
--------------------------------------------------------------------------------
1 | import Symbol from './Symbol';
2 |
3 | export var LineSymbol = Symbol.extend({
4 | statics: {
5 | // Not implemented 'esriSLSNull'
6 | LINETYPES: ['esriSLSDash', 'esriSLSDot', 'esriSLSDashDotDot', 'esriSLSDashDot', 'esriSLSSolid']
7 | },
8 | initialize: function (symbolJson, options) {
9 | Symbol.prototype.initialize.call(this, symbolJson, options);
10 | this._fillStyles();
11 | },
12 |
13 | _fillStyles: function () {
14 | // set the defaults that show up on arcgis online
15 | this._styles.lineCap = 'butt';
16 | this._styles.lineJoin = 'miter';
17 | this._styles.fill = false;
18 | this._styles.weight = 0;
19 |
20 | if (!this._symbolJson) {
21 | return this._styles;
22 | }
23 |
24 | if (this._symbolJson.color) {
25 | this._styles.color = this.colorValue(this._symbolJson.color);
26 | this._styles.opacity = this.alphaValue(this._symbolJson.color);
27 | }
28 |
29 | if (!isNaN(this._symbolJson.width)) {
30 | this._styles.weight = this.pixelValue(this._symbolJson.width);
31 |
32 | var dashValues = [];
33 |
34 | switch (this._symbolJson.style) {
35 | case 'esriSLSDash':
36 | dashValues = [4, 3];
37 | break;
38 | case 'esriSLSDot':
39 | dashValues = [1, 3];
40 | break;
41 | case 'esriSLSDashDot':
42 | dashValues = [8, 3, 1, 3];
43 | break;
44 | case 'esriSLSDashDotDot':
45 | dashValues = [8, 3, 1, 3, 1, 3];
46 | break;
47 | }
48 |
49 | // use the dash values and the line weight to set dash array
50 | if (dashValues.length > 0) {
51 | for (var i = 0; i < dashValues.length; i++) {
52 | dashValues[i] *= this._styles.weight;
53 | }
54 |
55 | this._styles.dashArray = dashValues.join(',');
56 | }
57 | }
58 | },
59 |
60 | style: function (feature, visualVariables) {
61 | if (!this._isDefault && visualVariables) {
62 | if (visualVariables.sizeInfo) {
63 | var calculatedSize = this.pixelValue(this.getSize(feature, visualVariables.sizeInfo));
64 | if (calculatedSize) {
65 | this._styles.weight = calculatedSize;
66 | }
67 | }
68 | if (visualVariables.colorInfo) {
69 | var color = this.getColor(feature, visualVariables.colorInfo);
70 | if (color) {
71 | this._styles.color = this.colorValue(color);
72 | this._styles.opacity = this.alphaValue(color);
73 | }
74 | }
75 | }
76 | return this._styles;
77 | }
78 | });
79 |
80 | export function lineSymbol (symbolJson, options) {
81 | return new LineSymbol(symbolJson, options);
82 | }
83 |
84 | export default lineSymbol;
85 |
--------------------------------------------------------------------------------
/src/Symbols/PointSymbol.js:
--------------------------------------------------------------------------------
1 | import {
2 | marker,
3 | icon as leafletIcon,
4 | extend,
5 | circleMarker
6 | } from 'leaflet';
7 | import Symbol from './Symbol';
8 | import { squareMarker, xMarker, crossMarker, diamondMarker } from 'leaflet-shape-markers';
9 |
10 | export var PointSymbol = Symbol.extend({
11 |
12 | statics: {
13 | MARKERTYPES: ['esriSMSCircle', 'esriSMSCross', 'esriSMSDiamond', 'esriSMSSquare', 'esriSMSX', 'esriPMS']
14 | },
15 |
16 | initialize: function (symbolJson, options) {
17 | var url;
18 | Symbol.prototype.initialize.call(this, symbolJson, options);
19 | if (options) {
20 | this.serviceUrl = options.url;
21 | }
22 | if (symbolJson) {
23 | if (symbolJson.type === 'esriPMS') {
24 | var imageUrl = this._symbolJson.url;
25 | if ((imageUrl && imageUrl.substr(0, 7) === 'http://') || (imageUrl.substr(0, 8) === 'https://')) {
26 | // web image
27 | url = this.sanitize(imageUrl);
28 | this._iconUrl = url;
29 | } else {
30 | url = this.serviceUrl + 'images/' + imageUrl;
31 | this._iconUrl = options && options.token ? url + '?token=' + options.token : url;
32 | }
33 | if (symbolJson.imageData) {
34 | this._iconUrl = 'data:' + symbolJson.contentType + ';base64,' + symbolJson.imageData;
35 | }
36 | // leaflet does not allow resizing icons so keep a hash of different
37 | // icon sizes to try and keep down on the number of icons created
38 | this._icons = {};
39 | // create base icon
40 | this.icon = this._createIcon(this._symbolJson);
41 | } else {
42 | this._fillStyles();
43 | }
44 | }
45 | },
46 |
47 | // prevent html injection in strings
48 | sanitize: function (str) {
49 | if (!str) {
50 | return '';
51 | }
52 | var text;
53 | try {
54 | // removes html but leaves url link text
55 | text = str.replace(/
/gi, '\n');
56 | text = text.replace(/
/gi, '\n');
57 | text = text.replace(/(.*?)<\/a>/gi, ' $2 ($1) ');
58 | text = text.replace(/<(?:.|\s)*?>/g, '');
59 | } catch (ex) {
60 | text = null;
61 | }
62 | return text;
63 | },
64 |
65 | _fillStyles: function () {
66 | if (this._symbolJson.outline && this._symbolJson.size > 0 && this._symbolJson.outline.style !== 'esriSLSNull') {
67 | this._styles.stroke = true;
68 | this._styles.weight = this.pixelValue(this._symbolJson.outline.width);
69 | this._styles.color = this.colorValue(this._symbolJson.outline.color);
70 | this._styles.opacity = this.alphaValue(this._symbolJson.outline.color);
71 | } else {
72 | this._styles.stroke = false;
73 | }
74 | if (this._symbolJson.color) {
75 | this._styles.fillColor = this.colorValue(this._symbolJson.color);
76 | this._styles.fillOpacity = this.alphaValue(this._symbolJson.color);
77 | } else {
78 | this._styles.fillOpacity = 0;
79 | }
80 |
81 | if (this._symbolJson.style === 'esriSMSCircle') {
82 | this._styles.radius = this.pixelValue(this._symbolJson.size) / 2.0;
83 | }
84 | },
85 |
86 | _createIcon: function (options) {
87 | var width = this.pixelValue(options.width);
88 | var height = width;
89 | if (options.height) {
90 | height = this.pixelValue(options.height);
91 | }
92 | var xOffset = width / 2.0;
93 | var yOffset = height / 2.0;
94 |
95 | if (options.xoffset) {
96 | xOffset += this.pixelValue(options.xoffset);
97 | }
98 | if (options.yoffset) {
99 | yOffset += this.pixelValue(options.yoffset);
100 | }
101 |
102 | var icon = leafletIcon({
103 | iconUrl: this._iconUrl,
104 | iconSize: [width, height],
105 | iconAnchor: [xOffset, yOffset]
106 | });
107 | this._icons[options.width.toString()] = icon;
108 | return icon;
109 | },
110 |
111 | _getIcon: function (size) {
112 | // check to see if it is already created by size
113 | var icon = this._icons[size.toString()];
114 | if (!icon) {
115 | icon = this._createIcon({ width: size });
116 | }
117 | return icon;
118 | },
119 |
120 | pointToLayer: function (geojson, latlng, visualVariables, options) {
121 | var size = this._symbolJson.size || this._symbolJson.width;
122 | if (!this._isDefault) {
123 | if (visualVariables.sizeInfo) {
124 | var calculatedSize = this.getSize(geojson, visualVariables.sizeInfo);
125 | if (calculatedSize) {
126 | size = calculatedSize;
127 | }
128 | }
129 | if (visualVariables.colorInfo) {
130 | var color = this.getColor(geojson, visualVariables.colorInfo);
131 | if (color) {
132 | this._styles.fillColor = this.colorValue(color);
133 | this._styles.fillOpacity = this.alphaValue(color);
134 | }
135 | }
136 | }
137 |
138 | if (this._symbolJson.type === 'esriPMS') {
139 | var layerOptions = extend({}, { icon: this._getIcon(size) }, options);
140 | return marker(latlng, layerOptions);
141 | }
142 | size = this.pixelValue(size);
143 |
144 | switch (this._symbolJson.style) {
145 | case 'esriSMSSquare':
146 | return squareMarker(latlng, size, extend({}, this._styles, options));
147 | case 'esriSMSDiamond':
148 | return diamondMarker(latlng, size, extend({}, this._styles, options));
149 | case 'esriSMSCross':
150 | return crossMarker(latlng, size, extend({}, this._styles, options));
151 | case 'esriSMSX':
152 | return xMarker(latlng, size, extend({}, this._styles, options));
153 | }
154 | this._styles.radius = size / 2.0;
155 | return circleMarker(latlng, extend({}, this._styles, options));
156 | }
157 | });
158 |
159 | export function pointSymbol (symbolJson, options) {
160 | return new PointSymbol(symbolJson, options);
161 | }
162 |
163 | export default pointSymbol;
164 |
--------------------------------------------------------------------------------
/src/Symbols/PolygonSymbol.js:
--------------------------------------------------------------------------------
1 | import Symbol from './Symbol';
2 | import lineSymbol from './LineSymbol';
3 |
4 | export var PolygonSymbol = Symbol.extend({
5 | statics: {
6 | // not implemented: 'esriSFSBackwardDiagonal','esriSFSCross','esriSFSDiagonalCross','esriSFSForwardDiagonal','esriSFSHorizontal','esriSFSNull','esriSFSVertical'
7 | POLYGONTYPES: ['esriSFSSolid']
8 | },
9 | initialize: function (symbolJson, options) {
10 | Symbol.prototype.initialize.call(this, symbolJson, options);
11 | if (symbolJson) {
12 | if (symbolJson.outline && symbolJson.outline.style === 'esriSLSNull') {
13 | this._lineStyles = { weight: 0 };
14 | } else {
15 | this._lineStyles = lineSymbol(symbolJson.outline, options).style();
16 | }
17 | this._fillStyles();
18 | }
19 | },
20 |
21 | _fillStyles: function () {
22 | if (this._lineStyles) {
23 | if (this._lineStyles.weight === 0) {
24 | // when weight is 0, setting the stroke to false can still look bad
25 | // (gaps between the polygons)
26 | this._styles.stroke = false;
27 | } else {
28 | // copy the line symbol styles into this symbol's styles
29 | for (var styleAttr in this._lineStyles) {
30 | this._styles[styleAttr] = this._lineStyles[styleAttr];
31 | }
32 | }
33 | }
34 |
35 | // set the fill for the polygon
36 | if (this._symbolJson) {
37 | if (this._symbolJson.color &&
38 | // don't fill polygon if type is not supported
39 | PolygonSymbol.POLYGONTYPES.indexOf(this._symbolJson.style >= 0)) {
40 | this._styles.fill = true;
41 | this._styles.fillColor = this.colorValue(this._symbolJson.color);
42 | this._styles.fillOpacity = this.alphaValue(this._symbolJson.color);
43 | } else {
44 | this._styles.fill = false;
45 | this._styles.fillOpacity = 0;
46 | }
47 | }
48 | },
49 |
50 | style: function (feature, visualVariables) {
51 | if (!this._isDefault && visualVariables && visualVariables.colorInfo) {
52 | var color = this.getColor(feature, visualVariables.colorInfo);
53 | if (color) {
54 | this._styles.fillColor = this.colorValue(color);
55 | this._styles.fillOpacity = this.alphaValue(color);
56 | }
57 | }
58 | return this._styles;
59 | }
60 | });
61 |
62 | export function polygonSymbol (symbolJson, options) {
63 | return new PolygonSymbol(symbolJson, options);
64 | }
65 |
66 | export default polygonSymbol;
67 |
--------------------------------------------------------------------------------
/src/Symbols/Symbol.js:
--------------------------------------------------------------------------------
1 | import { Class } from 'leaflet';
2 |
3 | export var Symbol = Class.extend({
4 | initialize: function (symbolJson, options) {
5 | this._symbolJson = symbolJson;
6 | this.val = null;
7 | this._styles = {};
8 | this._isDefault = false;
9 | this._layerTransparency = 1;
10 | if (options && options.layerTransparency) {
11 | this._layerTransparency = 1 - (options.layerTransparency / 100.0);
12 | }
13 | },
14 |
15 | // the geojson values returned are in points
16 | pixelValue: function (pointValue) {
17 | return pointValue * 1.333;
18 | },
19 |
20 | // color is an array [r,g,b,a]
21 | colorValue: function (color) {
22 | return 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
23 | },
24 |
25 | alphaValue: function (color) {
26 | var alpha = color[3] / 255.0;
27 | return alpha * this._layerTransparency;
28 | },
29 |
30 | getSize: function (feature, sizeInfo) {
31 | var attr = feature.properties;
32 | var field = sizeInfo.field;
33 | var size = 0;
34 | var featureValue = null;
35 |
36 | if (field) {
37 | featureValue = attr[field];
38 | var minSize = sizeInfo.minSize;
39 | var maxSize = sizeInfo.maxSize;
40 | var minDataValue = sizeInfo.minDataValue;
41 | var maxDataValue = sizeInfo.maxDataValue;
42 | var featureRatio;
43 | var normField = sizeInfo.normalizationField;
44 | var normValue = attr ? parseFloat(attr[normField]) : undefined;
45 |
46 | if (featureValue === null || (normField && ((isNaN(normValue) || normValue === 0)))) {
47 | return null;
48 | }
49 |
50 | if (!isNaN(normValue)) {
51 | featureValue /= normValue;
52 | }
53 |
54 | if (minSize !== null && maxSize !== null && minDataValue !== null && maxDataValue !== null) {
55 | if (featureValue <= minDataValue) {
56 | size = minSize;
57 | } else if (featureValue >= maxDataValue) {
58 | size = maxSize;
59 | } else {
60 | featureRatio = (featureValue - minDataValue) / (maxDataValue - minDataValue);
61 | size = minSize + (featureRatio * (maxSize - minSize));
62 | }
63 | }
64 | size = isNaN(size) ? 0 : size;
65 | }
66 | return size;
67 | },
68 |
69 | getColor: function (feature, colorInfo) {
70 | // required information to get color
71 | if (!(feature.properties && colorInfo && colorInfo.field && colorInfo.stops)) {
72 | return null;
73 | }
74 |
75 | var attr = feature.properties;
76 | var featureValue = attr[colorInfo.field];
77 | var lowerBoundColor, upperBoundColor, lowerBound, upperBound;
78 | var normField = colorInfo.normalizationField;
79 | var normValue = attr ? parseFloat(attr[normField]) : undefined;
80 | if (featureValue === null || (normField && ((isNaN(normValue) || normValue === 0)))) {
81 | return null;
82 | }
83 |
84 | if (!isNaN(normValue)) {
85 | featureValue /= normValue;
86 | }
87 |
88 | if (featureValue <= colorInfo.stops[0].value) {
89 | return colorInfo.stops[0].color;
90 | }
91 | var lastStop = colorInfo.stops[colorInfo.stops.length - 1];
92 | if (featureValue >= lastStop.value) {
93 | return lastStop.color;
94 | }
95 |
96 | // go through the stops to find min and max
97 | for (var i = 0; i < colorInfo.stops.length; i++) {
98 | var stopInfo = colorInfo.stops[i];
99 |
100 | if (stopInfo.value <= featureValue) {
101 | lowerBoundColor = stopInfo.color;
102 | lowerBound = stopInfo.value;
103 | } else if (stopInfo.value > featureValue) {
104 | upperBoundColor = stopInfo.color;
105 | upperBound = stopInfo.value;
106 | break;
107 | }
108 | }
109 |
110 | // feature falls between two stops, interplate the colors
111 | if (!isNaN(lowerBound) && !isNaN(upperBound)) {
112 | var range = upperBound - lowerBound;
113 | if (range > 0) {
114 | // more weight the further it is from the lower bound
115 | var upperBoundColorWeight = (featureValue - lowerBound) / range;
116 | if (upperBoundColorWeight) {
117 | // more weight the further it is from the upper bound
118 | var lowerBoundColorWeight = (upperBound - featureValue) / range;
119 | if (lowerBoundColorWeight) {
120 | // interpolate the lower and upper bound color by applying the
121 | // weights to each of the rgba colors and adding them together
122 | var interpolatedColor = [];
123 | for (var j = 0; j < 4; j++) {
124 | interpolatedColor[j] = Math.round((lowerBoundColor[j] * lowerBoundColorWeight) + (upperBoundColor[j] * upperBoundColorWeight));
125 | }
126 | return interpolatedColor;
127 | } else {
128 | // no difference between featureValue and upperBound, 100% of upperBoundColor
129 | return upperBoundColor;
130 | }
131 | } else {
132 | // no difference between featureValue and lowerBound, 100% of lowerBoundColor
133 | return lowerBoundColor;
134 | }
135 | }
136 | }
137 | // if we get to here, none of the cases apply so return null
138 | return null;
139 | }
140 | });
141 |
142 | // export function symbol (symbolJson) {
143 | // return new Symbol(symbolJson);
144 | // }
145 |
146 | export default Symbol;
147 |
--------------------------------------------------------------------------------