UNPKG

mapcraftjs

Version:

Web components and modules for mapping (React + Leaflet)

282 lines (211 loc) 8.92 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.Theme = undefined; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _d = require('d3'); var _d2 = _interopRequireDefault(_d); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _colorbrewer = require('colorbrewer'); var _colorbrewer2 = _interopRequireDefault(_colorbrewer); var _simpleStatistics = require('simple-statistics'); var _simpleStatistics2 = _interopRequireDefault(_simpleStatistics); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var hashStr = function hashStr(str, mod) { var hash = 0, i = void 0, chr = void 0; if (str === undefined || str.length === 0) return hash; for (i = 0; i < str.length; i++) { chr = str.charCodeAt(i); hash = (hash << 5) - hash + chr; hash |= 0; // Convert to 32bit integer } return hash % mod; }; var Theme = exports.Theme = function () { _createClass(Theme, [{ key: '_linear', value: function _linear(tc, vals) { // force to float vals = vals.map(function (v) { return +v; }); // get min and max var e = _d2.default.extent(vals); var min = e[0], max = e[1]; var colors = tc.interpolate || [_colorbrewer2.default[tc.colorScheme][3][0], _colorbrewer2.default[tc.colorScheme][3][2]]; if (tc.middleValue != undefined && colors.length == 2 || colors.length == 3 && tc.middleValue == undefined) throw Error('For 3-way interpolation, must include middle value attributes to add between min and max.'); // preparing for 3-way interpolation e = tc.middleValue != undefined ? [e[0], tc.middleValue, e[1]] : e; var scale = _d2.default.scale.linear().domain(e).range(colors); // build some intervals in the interpolation range for // use in the legend var legendDomain = _lodash2.default.range(min, max, (max - min) / 5.0); legendDomain.push(max); // push the max too this.legendParams = { grades: legendDomain, colors: legendDomain.map(function (a) { return scale(a); }) }; return scale; } }, { key: '_manual', value: function _manual(tc) { var breaks = tc.breaks, numBins = breaks.length + 1; numBins = Math.max(3, Math.min(numBins, 9)); var colors = _colorbrewer2.default[tc.colorScheme][numBins]; var scale = _d2.default.scale.threshold().domain(breaks).range(colors); var grades = scale.range().map(function (grade) { return scale.invertExtent(grade).join('-'); }); this.legendParams = { grades: grades, colors: colors }; return scale; } }, { key: '_jenks', value: function _jenks(tc, vals) { // force to float vals = vals.map(function (v) { return +v; }); var breaks = _simpleStatistics2.default.ckmeans(vals, tc.numBins); breaks = breaks.map(function (vals) { return vals[0]; }).splice(1); return this._manual(_lodash2.default.extend({}, tc, { breaks: breaks, numBins: breaks.length + 1 }), vals); } }, { key: '_quantile', value: function _quantile(tc, vals) { // force to float vals = vals.map(function (v) { return +v; }); var colors = _colorbrewer2.default[tc.colorScheme][tc.numBins]; var scale = _d2.default.scale.quantile().domain(vals).range(colors); var grades = scale.range().map(function (grade) { return scale.invertExtent(grade).join('-'); }); this.legendParams = { grades: grades, colors: colors }; return scale; } }, { key: '_categorical', value: function _categorical(tc) { var scale = function scale(v) { return _lodash2.default.get(tc.categories, v, tc.defaultColor); }; var keys = tc.legendKeys || _lodash2.default.keys(tc.categories); this.legendParams = { grades: keys, colors: keys.map(function (k) { return tc.categories[k]; }) }; return scale; } }, { key: '_autocategorical', value: function _autocategorical(tc, vals) { var keys = _lodash2.default.uniq(vals); // drop empties keys = _lodash2.default.without(keys, undefined, null, ''); var colors = _d2.default.scale.category20().domain(_lodash2.default.range(20)); // this gives a stable mapping of strings to one of the 20 colors // the string xyzABC will always map to the same color no matter which // other categories exist, which is useful for many cases. there can // be collisions now, even for fewer than 20 unique values var scale = function scale(val) { if (val == '') return '#FFFFFF'; if (_lodash2.default.size(keys) == 2) { // better colors for binary scale if (val == keys[0]) return '#33a02c'; if (val == keys[1]) return '#ff7f00'; } return colors(hashStr(val, 20)); }; this.legendParams = { grades: keys, colors: keys.map(function (k) { return scale(k); }) }; return scale; } // create theme object from a javascript config onject // and a vector of data - the return object is useful to // pass to getStyle below }]); function Theme(themeConfig, vals) { _classCallCheck(this, Theme); var tc = themeConfig; var scale; if (tc.scaleType == 'linear') { scale = this._linear(themeConfig, vals); } else if (tc.scaleType == 'manual') { scale = this._manual(themeConfig); } else if (tc.scaleType == 'quantile') { scale = this._quantile(themeConfig, vals); } else if (tc.scaleType == 'categorical') { scale = this._categorical(themeConfig); } else if (tc.scaleType == 'autocategorical') { scale = this._autocategorical(themeConfig, vals); } else if (tc.scaleType == 'jenks') { scale = this._jenks(themeConfig, vals); } else { throw Error('Theme type not supported'); } this.theme = tc; this.scale = scale; } _createClass(Theme, [{ key: 'getLegendParams', value: function getLegendParams() { return _lodash2.default.extend({}, this.legendParams, { heading: this.theme.legendName, dontFormatLegend: this.theme.dontFormatLegend }); } // for use e.g. with setting radius on a circle }, { key: 'getScaledVal', value: function getScaledVal(v) { return this.scale(v); } }, { key: 'getStyle', value: function getStyle(v) { var tc = this.theme; var scale = this.scale; function isNan(v) { return v == undefined || Number.isNaN(v) || !scale(v) || v == tc.setToNan; } // style object to return at the end var style = { weight: tc.weight, fillColor: scale(v), fillOpacity: isNan(v) ? 0 : tc.opacity, color: tc.outlineColor }; return style; } }]); return Theme; }();