mapshaper 0.5.94 → 0.5.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/mapshaper.js +475 -392
- package/package.json +1 -1
- package/www/mapshaper-gui.js +134 -156
- package/www/mapshaper.js +475 -392
package/www/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.5.
|
|
3
|
+
var VERSION = "0.5.96";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -4993,7 +4993,7 @@
|
|
|
4993
4993
|
this._n = 0;
|
|
4994
4994
|
this.x = 0;
|
|
4995
4995
|
this.y = 0;
|
|
4996
|
-
this.i = -1;
|
|
4996
|
+
// this.i = -1;
|
|
4997
4997
|
}
|
|
4998
4998
|
|
|
4999
4999
|
ShapeIter.prototype.hasNext = function() {
|
|
@@ -5004,7 +5004,7 @@
|
|
|
5004
5004
|
if (arc.hasNext()) {
|
|
5005
5005
|
this.x = arc.x;
|
|
5006
5006
|
this.y = arc.y;
|
|
5007
|
-
this.i = arc.i;
|
|
5007
|
+
// this.i = arc.i;
|
|
5008
5008
|
return true;
|
|
5009
5009
|
}
|
|
5010
5010
|
this.nextArc();
|
|
@@ -8877,12 +8877,24 @@
|
|
|
8877
8877
|
arg = arg ? String(arg) : '';
|
|
8878
8878
|
var hexStr = hexRxp.test(arg) ? arg : lookupColorName(arg);
|
|
8879
8879
|
var rgb = null;
|
|
8880
|
-
if (hexStr)
|
|
8881
|
-
|
|
8882
|
-
if (
|
|
8880
|
+
if (hexStr) {
|
|
8881
|
+
rgb = parseHexColor(hexStr);
|
|
8882
|
+
} else if (rgbaRxp.test(arg)) {
|
|
8883
|
+
rgb = parseRGBA(arg);
|
|
8884
|
+
}
|
|
8885
|
+
if (rgb && !testRGB(rgb)) {
|
|
8886
|
+
rgb = null;
|
|
8887
|
+
}
|
|
8883
8888
|
return rgb;
|
|
8884
8889
|
}
|
|
8885
8890
|
|
|
8891
|
+
function validateColor(arg) {
|
|
8892
|
+
if (!parseColor(arg)) {
|
|
8893
|
+
stop("Unsupported color:", arg);
|
|
8894
|
+
}
|
|
8895
|
+
return true;
|
|
8896
|
+
}
|
|
8897
|
+
|
|
8886
8898
|
function testRGB(o) {
|
|
8887
8899
|
return !!o && testChannel(o.r) && testChannel(o.g) && testChannel(o.b) &&
|
|
8888
8900
|
testAlpha(o.a);
|
|
@@ -9028,7 +9040,7 @@
|
|
|
9028
9040
|
weights = normalizeWeights(weights);
|
|
9029
9041
|
if (!weights) return '#eee';
|
|
9030
9042
|
var blended = colors.reduce(function(memo, col, i) {
|
|
9031
|
-
var rgb = parseColor(col);
|
|
9043
|
+
var rgb = validateColor(col) && parseColor(col);
|
|
9032
9044
|
var w = +weights[i] || 0;
|
|
9033
9045
|
memo.r += rgb.r * w;
|
|
9034
9046
|
memo.g += rgb.g * w;
|
|
@@ -19152,7 +19164,7 @@ ${svg}
|
|
|
19152
19164
|
describe: 'value (or color) to use for invalid or missing data'
|
|
19153
19165
|
})
|
|
19154
19166
|
.option('method', {
|
|
19155
|
-
describe: '
|
|
19167
|
+
describe: 'quantile, nice, equal-interval, categorical, etc.'
|
|
19156
19168
|
})
|
|
19157
19169
|
.option('quantile', {
|
|
19158
19170
|
//describe: 'shortcut for method=quantile (the default)',
|
|
@@ -27734,217 +27746,6 @@ ${svg}
|
|
|
27734
27746
|
return [lyr2];
|
|
27735
27747
|
}
|
|
27736
27748
|
|
|
27737
|
-
// TODO: support three or more stops
|
|
27738
|
-
function getGradientFunction(stops) {
|
|
27739
|
-
var min = stops[0] / 100,
|
|
27740
|
-
max = stops[1] / 100;
|
|
27741
|
-
if (stops.length != 2) {
|
|
27742
|
-
stop('Only two stops are currently supported');
|
|
27743
|
-
}
|
|
27744
|
-
if (!(min >= 0 && max <= 1 && min < max)) {
|
|
27745
|
-
stop('Invalid gradient stops:', stops);
|
|
27746
|
-
}
|
|
27747
|
-
return function(t) {
|
|
27748
|
-
return t * (max - min) + min;
|
|
27749
|
-
};
|
|
27750
|
-
}
|
|
27751
|
-
|
|
27752
|
-
function getStoppedValues(values, stops) {
|
|
27753
|
-
var interpolate = getInterpolatedValueGetter(values, null);
|
|
27754
|
-
var n = values.length;
|
|
27755
|
-
var fstop = getGradientFunction(stops);
|
|
27756
|
-
var values2 = [];
|
|
27757
|
-
var t, val;
|
|
27758
|
-
for (var i=0; i<n; i++) {
|
|
27759
|
-
t = fstop(i / (n - 1));
|
|
27760
|
-
val = interpolate(t * (n - 1));
|
|
27761
|
-
values2.push(val);
|
|
27762
|
-
}
|
|
27763
|
-
return values2;
|
|
27764
|
-
}
|
|
27765
|
-
|
|
27766
|
-
// convert a continuous index ([0, n-1], -1) to a corresponding interpolated value
|
|
27767
|
-
function getInterpolatedValueGetter(values, nullValue) {
|
|
27768
|
-
var d3 = require('d3-interpolate');
|
|
27769
|
-
var interpolators = [];
|
|
27770
|
-
var tmax = values.length - 1;
|
|
27771
|
-
for (var i=1; i<values.length; i++) {
|
|
27772
|
-
interpolators.push(d3.interpolate(values[i-1], values[i]));
|
|
27773
|
-
}
|
|
27774
|
-
return function(t) {
|
|
27775
|
-
if (t == -1) return nullValue;
|
|
27776
|
-
if ((t >= 0 && t <= tmax) === false) {
|
|
27777
|
-
error('Range error');
|
|
27778
|
-
}
|
|
27779
|
-
var i = t == tmax ? tmax - 1 : Math.floor(t);
|
|
27780
|
-
var j = t == tmax ? 1 : t % 1;
|
|
27781
|
-
return interpolators[i](j);
|
|
27782
|
-
};
|
|
27783
|
-
}
|
|
27784
|
-
|
|
27785
|
-
// return an array of n values
|
|
27786
|
-
// assumes that values can be interpolated by d3-interpolate
|
|
27787
|
-
// (colors and numbers should work)
|
|
27788
|
-
function interpolateValuesToClasses(values, n, stops) {
|
|
27789
|
-
if (values.length == n && !stops) return values;
|
|
27790
|
-
var d3 = require('d3-interpolate');
|
|
27791
|
-
var numPairs = values.length - 1;
|
|
27792
|
-
var output = [values[0]];
|
|
27793
|
-
var k, j, t, intVal;
|
|
27794
|
-
for (var i=1; i<n-1; i++) {
|
|
27795
|
-
k = i / (n-1) * numPairs;
|
|
27796
|
-
j = Math.floor(k);
|
|
27797
|
-
t = k - j;
|
|
27798
|
-
// if (convert) t = convert(t);
|
|
27799
|
-
intVal = d3.interpolate(values[j], values[j+1])(t);
|
|
27800
|
-
output.push(intVal);
|
|
27801
|
-
}
|
|
27802
|
-
output.push(values[values.length - 1]);
|
|
27803
|
-
if (stops) {
|
|
27804
|
-
output = getStoppedValues(output, stops);
|
|
27805
|
-
}
|
|
27806
|
-
return output;
|
|
27807
|
-
}
|
|
27808
|
-
|
|
27809
|
-
var index = {
|
|
27810
|
-
categorical: [],
|
|
27811
|
-
sequential: [],
|
|
27812
|
-
rainbow: [],
|
|
27813
|
-
diverging: []
|
|
27814
|
-
};
|
|
27815
|
-
var ramps;
|
|
27816
|
-
|
|
27817
|
-
function initSchemes() {
|
|
27818
|
-
if (ramps) return;
|
|
27819
|
-
ramps = {};
|
|
27820
|
-
addSchemesFromD3('categorical', 'Category10,Accent,Dark2,Paired,Pastel1,Pastel2,Set1,Set2,Set3,Tableau10');
|
|
27821
|
-
addSchemesFromD3('sequential', 'Blues,Greens,Greys,Purples,Reds,Oranges,BuGn,BuPu,GnBu,OrRd,PuBuGn,PuBu,PuRd,RdPu,YlGnBu,YlGn,YlOrBr,YlOrRd');
|
|
27822
|
-
addSchemesFromD3('rainbow', 'Cividis,CubehelixDefault,Rainbow,Warm,Cool,Sinebow,Turbo,Viridis,Magma,Inferno,Plasma');
|
|
27823
|
-
addSchemesFromD3('diverging', 'BrBG,PRGn,PRGn,PiYG,PuOr,RdBu,RdGy,RdYlBu,RdYlGn,Spectral');
|
|
27824
|
-
testLib(); // make sure these schemes are all available
|
|
27825
|
-
addCategoricalScheme('Category20',
|
|
27826
|
-
'1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5');
|
|
27827
|
-
addCategoricalScheme('Category20b',
|
|
27828
|
-
'393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6');
|
|
27829
|
-
addCategoricalScheme('Category20c',
|
|
27830
|
-
'3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9');
|
|
27831
|
-
addCategoricalScheme('Tableau20',
|
|
27832
|
-
'4c78a89ecae9f58518ffbf7954a24b88d27ab79a20f2cf5b43989483bcb6e45756ff9d9879706ebab0acd67195fcbfd2b279a2d6a5c99e765fd8b5a5');
|
|
27833
|
-
}
|
|
27834
|
-
|
|
27835
|
-
function addSchemesFromD3(type, names) {
|
|
27836
|
-
index[type] = index[type].concat(names.split(','));
|
|
27837
|
-
}
|
|
27838
|
-
|
|
27839
|
-
function addCategoricalScheme(name, str) {
|
|
27840
|
-
index.categorical.push(name);
|
|
27841
|
-
ramps[name] = unpackRamp(str);
|
|
27842
|
-
}
|
|
27843
|
-
|
|
27844
|
-
function unpackRamp(str) {
|
|
27845
|
-
var colors = [];
|
|
27846
|
-
for (var i=0, n=str.length; i<n; i+=6) {
|
|
27847
|
-
colors.push('#' + str.substr(i, 6));
|
|
27848
|
-
}
|
|
27849
|
-
return colors;
|
|
27850
|
-
}
|
|
27851
|
-
|
|
27852
|
-
function testLib() {
|
|
27853
|
-
var lib = require('d3-scale-chromatic');
|
|
27854
|
-
schemes(index.categorical);
|
|
27855
|
-
schemes(index.sequential);
|
|
27856
|
-
schemes(index.diverging);
|
|
27857
|
-
interpolators(index.sequential);
|
|
27858
|
-
interpolators(index.rainbow);
|
|
27859
|
-
interpolators(index.diverging);
|
|
27860
|
-
|
|
27861
|
-
function schemes(arr) {
|
|
27862
|
-
arr.forEach(function(name) {
|
|
27863
|
-
if (!lib['scheme' + name]) {
|
|
27864
|
-
message('Warning: missing data for', name);
|
|
27865
|
-
}
|
|
27866
|
-
});
|
|
27867
|
-
}
|
|
27868
|
-
|
|
27869
|
-
function interpolators(arr) {
|
|
27870
|
-
arr.forEach(function(name) {
|
|
27871
|
-
if (!lib['interpolate' + name]) {
|
|
27872
|
-
message('Missing interpolator for', name);
|
|
27873
|
-
}
|
|
27874
|
-
});
|
|
27875
|
-
}
|
|
27876
|
-
}
|
|
27877
|
-
|
|
27878
|
-
function printColorSchemeNames() {
|
|
27879
|
-
initSchemes();
|
|
27880
|
-
print('Built-in color schemes (from d3):');
|
|
27881
|
-
print ('Categorical\n' + formatStringsAsGrid(index.categorical));
|
|
27882
|
-
print ('\nSequential\n' + formatStringsAsGrid(index.sequential));
|
|
27883
|
-
print ('\nDiverging\n' + formatStringsAsGrid(index.diverging));
|
|
27884
|
-
print ('\nMulti-hue/rainbow\n' + formatStringsAsGrid(index.rainbow));
|
|
27885
|
-
}
|
|
27886
|
-
|
|
27887
|
-
function getCategoricalColorScheme(name, n) {
|
|
27888
|
-
var colors;
|
|
27889
|
-
initSchemes();
|
|
27890
|
-
if (!isColorSchemeName(name)) {
|
|
27891
|
-
stop('Unknown color scheme name:', name);
|
|
27892
|
-
} else if (isCategoricalColorScheme(name)) {
|
|
27893
|
-
colors = ramps[name] || require('d3-scale-chromatic')['scheme' + name];
|
|
27894
|
-
} else {
|
|
27895
|
-
colors = getColorRamp(name, n);
|
|
27896
|
-
}
|
|
27897
|
-
if (n > colors.length) {
|
|
27898
|
-
stop(name, 'does not contain', n, 'colors');
|
|
27899
|
-
}
|
|
27900
|
-
return colors.slice(0, n);
|
|
27901
|
-
}
|
|
27902
|
-
|
|
27903
|
-
function isColorSchemeName(name) {
|
|
27904
|
-
initSchemes();
|
|
27905
|
-
return index.categorical.includes(name) || index.sequential.includes(name) ||
|
|
27906
|
-
index.diverging.includes(name) || index.rainbow.includes(name);
|
|
27907
|
-
}
|
|
27908
|
-
|
|
27909
|
-
function isCategoricalColorScheme(name) {
|
|
27910
|
-
initSchemes();
|
|
27911
|
-
return index.categorical.includes(name);
|
|
27912
|
-
}
|
|
27913
|
-
|
|
27914
|
-
function getColorRamp(name, n, stops) {
|
|
27915
|
-
initSchemes();
|
|
27916
|
-
var lib = require('d3-scale-chromatic');
|
|
27917
|
-
var ramps = lib['scheme' + name];
|
|
27918
|
-
var interpolate = lib['interpolate' + name];
|
|
27919
|
-
var ramp;
|
|
27920
|
-
if (!ramps && !interpolate) {
|
|
27921
|
-
stop('Unknown color scheme name:', name);
|
|
27922
|
-
}
|
|
27923
|
-
if (index.categorical.includes(name)) {
|
|
27924
|
-
stop(name, ' is a categorical color scheme (expected a sequential color scheme)');
|
|
27925
|
-
}
|
|
27926
|
-
if (ramps && ramps[n]) {
|
|
27927
|
-
ramp = ramps[n];
|
|
27928
|
-
} else {
|
|
27929
|
-
ramp = getInterpolatedRamp(interpolate, n);
|
|
27930
|
-
}
|
|
27931
|
-
if (stops) {
|
|
27932
|
-
ramp = getStoppedValues(ramp, stops);
|
|
27933
|
-
}
|
|
27934
|
-
return ramp;
|
|
27935
|
-
}
|
|
27936
|
-
|
|
27937
|
-
function getInterpolatedRamp(interpolate, n) {
|
|
27938
|
-
if (n > 0 === false || !utils.isInteger(n)) {
|
|
27939
|
-
error('Expected a positive integer');
|
|
27940
|
-
}
|
|
27941
|
-
var ramp = [];
|
|
27942
|
-
for (var i=0; i<n; i++) {
|
|
27943
|
-
ramp.push(interpolate(i / (n - 1)));
|
|
27944
|
-
}
|
|
27945
|
-
return ramp;
|
|
27946
|
-
}
|
|
27947
|
-
|
|
27948
27749
|
var scaledIntervals =
|
|
27949
27750
|
[10,12,15,18,20,22,25,30,35,40,45,50,60,70,80,90,100];
|
|
27950
27751
|
var precisions =
|
|
@@ -28074,6 +27875,78 @@ ${svg}
|
|
|
28074
27875
|
return s;
|
|
28075
27876
|
}
|
|
28076
27877
|
|
|
27878
|
+
// TODO: support three or more stops
|
|
27879
|
+
function getGradientFunction(stops) {
|
|
27880
|
+
var min = stops[0] / 100,
|
|
27881
|
+
max = stops[1] / 100;
|
|
27882
|
+
if (stops.length != 2) {
|
|
27883
|
+
stop('Only two stops are currently supported');
|
|
27884
|
+
}
|
|
27885
|
+
if (!(min >= 0 && max <= 1 && min < max)) {
|
|
27886
|
+
stop('Invalid gradient stops:', stops);
|
|
27887
|
+
}
|
|
27888
|
+
return function(t) {
|
|
27889
|
+
return t * (max - min) + min;
|
|
27890
|
+
};
|
|
27891
|
+
}
|
|
27892
|
+
|
|
27893
|
+
function getStoppedValues(values, stops) {
|
|
27894
|
+
var interpolate = getInterpolatedValueGetter(values, null);
|
|
27895
|
+
var n = values.length;
|
|
27896
|
+
var fstop = getGradientFunction(stops);
|
|
27897
|
+
var values2 = [];
|
|
27898
|
+
var t, val;
|
|
27899
|
+
for (var i=0; i<n; i++) {
|
|
27900
|
+
t = fstop(i / (n - 1));
|
|
27901
|
+
val = interpolate(t * (n - 1));
|
|
27902
|
+
values2.push(val);
|
|
27903
|
+
}
|
|
27904
|
+
return values2;
|
|
27905
|
+
}
|
|
27906
|
+
|
|
27907
|
+
// convert a continuous index ([0, n-1], -1) to a corresponding interpolated value
|
|
27908
|
+
function getInterpolatedValueGetter(values, nullValue) {
|
|
27909
|
+
var d3 = require('d3-interpolate');
|
|
27910
|
+
var interpolators = [];
|
|
27911
|
+
var tmax = values.length - 1;
|
|
27912
|
+
for (var i=1; i<values.length; i++) {
|
|
27913
|
+
interpolators.push(d3.interpolate(values[i-1], values[i]));
|
|
27914
|
+
}
|
|
27915
|
+
return function(t) {
|
|
27916
|
+
if (t == -1) return nullValue;
|
|
27917
|
+
if ((t >= 0 && t <= tmax) === false) {
|
|
27918
|
+
error('Range error');
|
|
27919
|
+
}
|
|
27920
|
+
var i = t == tmax ? tmax - 1 : Math.floor(t);
|
|
27921
|
+
var j = t == tmax ? 1 : t % 1;
|
|
27922
|
+
return interpolators[i](j);
|
|
27923
|
+
};
|
|
27924
|
+
}
|
|
27925
|
+
|
|
27926
|
+
// return an array of n values
|
|
27927
|
+
// assumes that values can be interpolated by d3-interpolate
|
|
27928
|
+
// (colors and numbers should work)
|
|
27929
|
+
function interpolateValuesToClasses(values, n, stops) {
|
|
27930
|
+
if (values.length == n && !stops) return values;
|
|
27931
|
+
var d3 = require('d3-interpolate');
|
|
27932
|
+
var numPairs = values.length - 1;
|
|
27933
|
+
var output = [values[0]];
|
|
27934
|
+
var k, j, t, intVal;
|
|
27935
|
+
for (var i=1; i<n-1; i++) {
|
|
27936
|
+
k = i / (n-1) * numPairs;
|
|
27937
|
+
j = Math.floor(k);
|
|
27938
|
+
t = k - j;
|
|
27939
|
+
// if (convert) t = convert(t);
|
|
27940
|
+
intVal = d3.interpolate(values[j], values[j+1])(t);
|
|
27941
|
+
output.push(intVal);
|
|
27942
|
+
}
|
|
27943
|
+
output.push(values[values.length - 1]);
|
|
27944
|
+
if (stops) {
|
|
27945
|
+
output = getStoppedValues(output, stops);
|
|
27946
|
+
}
|
|
27947
|
+
return output;
|
|
27948
|
+
}
|
|
27949
|
+
|
|
28077
27950
|
// convert an index (0 ... n-1, -1, -2) to a corresponding discreet value
|
|
28078
27951
|
function getDiscreteValueGetter(values, nullValue, otherValue) {
|
|
28079
27952
|
var n = values.length;
|
|
@@ -28680,35 +28553,6 @@ ${svg}
|
|
|
28680
28553
|
};
|
|
28681
28554
|
}
|
|
28682
28555
|
|
|
28683
|
-
function getIndexedClassifier(values, nullVal, opts) {
|
|
28684
|
-
// TODO: handle continuous classification
|
|
28685
|
-
var numBuckets = values.length;
|
|
28686
|
-
var classToValue = getOutputFunction(values, nullVal, opts);
|
|
28687
|
-
|
|
28688
|
-
return function(val) {
|
|
28689
|
-
var idx = utils.isInteger(val) && val >= 0 && val < numBuckets ? val : -1;
|
|
28690
|
-
return classToValue(idx);
|
|
28691
|
-
};
|
|
28692
|
-
}
|
|
28693
|
-
|
|
28694
|
-
// returns the number of classes, based on the largest class index found
|
|
28695
|
-
function validateClassIndexField(records, name) {
|
|
28696
|
-
var invalid = [];
|
|
28697
|
-
var maxId = -1;
|
|
28698
|
-
records.forEach(function(d) {
|
|
28699
|
-
var val = (d || {})[name];
|
|
28700
|
-
if (!utils.isInteger(val) || val < -2) {
|
|
28701
|
-
invalid.push(val);
|
|
28702
|
-
} else {
|
|
28703
|
-
maxId = Math.max(maxId, val);
|
|
28704
|
-
}
|
|
28705
|
-
});
|
|
28706
|
-
if (invalid.length > 0) {
|
|
28707
|
-
stop(`Class index field contains invalid value(s): ${invalid.slice(0, 5)}`);
|
|
28708
|
-
}
|
|
28709
|
-
return maxId + 1;
|
|
28710
|
-
}
|
|
28711
|
-
|
|
28712
28556
|
// Returns a function for constructing a query function that accepts an arc id and
|
|
28713
28557
|
// returns information about the polygon or polygons that use the given arc.
|
|
28714
28558
|
// TODO: explain this better.
|
|
@@ -29005,64 +28849,349 @@ ${svg}
|
|
|
29005
28849
|
};
|
|
29006
28850
|
}
|
|
29007
28851
|
|
|
28852
|
+
function getIndexedClassifier(values, nullVal, opts) {
|
|
28853
|
+
// TODO: handle continuous classification
|
|
28854
|
+
var numBuckets = values.length;
|
|
28855
|
+
var classToValue = getOutputFunction(values, nullVal, opts);
|
|
28856
|
+
|
|
28857
|
+
return function(val) {
|
|
28858
|
+
var idx = utils.isInteger(val) && val >= 0 && val < numBuckets ? val : -1;
|
|
28859
|
+
return classToValue(idx);
|
|
28860
|
+
};
|
|
28861
|
+
}
|
|
28862
|
+
|
|
28863
|
+
// returns the number of classes, based on the largest class index found
|
|
28864
|
+
function getIndexedClassCount(records, name) {
|
|
28865
|
+
var invalid = [];
|
|
28866
|
+
var maxId = -1;
|
|
28867
|
+
records.forEach(function(d) {
|
|
28868
|
+
var val = (d || {})[name];
|
|
28869
|
+
if (!utils.isInteger(val) || val < -2) {
|
|
28870
|
+
invalid.push(val);
|
|
28871
|
+
} else {
|
|
28872
|
+
maxId = Math.max(maxId, val);
|
|
28873
|
+
}
|
|
28874
|
+
});
|
|
28875
|
+
if (invalid.length > 0) {
|
|
28876
|
+
stop(`Class index field contains invalid value(s): ${invalid.slice(0, 5)}`);
|
|
28877
|
+
}
|
|
28878
|
+
return maxId + 1;
|
|
28879
|
+
}
|
|
28880
|
+
|
|
28881
|
+
var index = {
|
|
28882
|
+
categorical: [],
|
|
28883
|
+
sequential: [],
|
|
28884
|
+
rainbow: [],
|
|
28885
|
+
diverging: [],
|
|
28886
|
+
all: []
|
|
28887
|
+
};
|
|
28888
|
+
var ramps;
|
|
28889
|
+
|
|
28890
|
+
function initSchemes() {
|
|
28891
|
+
if (ramps) return;
|
|
28892
|
+
ramps = {};
|
|
28893
|
+
addSchemesFromD3('categorical', 'Category10,Accent,Dark2,Paired,Pastel1,Pastel2,Set1,Set2,Set3,Tableau10');
|
|
28894
|
+
addSchemesFromD3('sequential', 'Blues,Greens,Greys,Purples,Reds,Oranges,BuGn,BuPu,GnBu,OrRd,PuBuGn,PuBu,PuRd,RdPu,YlGnBu,YlGn,YlOrBr,YlOrRd');
|
|
28895
|
+
addSchemesFromD3('rainbow', 'Cividis,CubehelixDefault,Rainbow,Warm,Cool,Sinebow,Turbo,Viridis,Magma,Inferno,Plasma');
|
|
28896
|
+
addSchemesFromD3('diverging', 'BrBG,PRGn,PRGn,PiYG,PuOr,RdBu,RdGy,RdYlBu,RdYlGn,Spectral');
|
|
28897
|
+
testLib(); // make sure these schemes are all available
|
|
28898
|
+
addCategoricalScheme('Category20',
|
|
28899
|
+
'1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5');
|
|
28900
|
+
addCategoricalScheme('Category20b',
|
|
28901
|
+
'393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6');
|
|
28902
|
+
addCategoricalScheme('Category20c',
|
|
28903
|
+
'3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9');
|
|
28904
|
+
addCategoricalScheme('Tableau20',
|
|
28905
|
+
'4c78a89ecae9f58518ffbf7954a24b88d27ab79a20f2cf5b43989483bcb6e45756ff9d9879706ebab0acd67195fcbfd2b279a2d6a5c99e765fd8b5a5');
|
|
28906
|
+
index.all = [].concat(index.sequential, index.rainbow, index.diverging, index.categorical);
|
|
28907
|
+
|
|
28908
|
+
}
|
|
28909
|
+
|
|
28910
|
+
function standardName(name) {
|
|
28911
|
+
if (!name) return null;
|
|
28912
|
+
var lcname = name.toLowerCase();
|
|
28913
|
+
for (var i=0; i<index.all.length; i++) {
|
|
28914
|
+
if (index.all[i].toLowerCase() == lcname) {
|
|
28915
|
+
return index.all[i];
|
|
28916
|
+
}
|
|
28917
|
+
}
|
|
28918
|
+
return null;
|
|
28919
|
+
}
|
|
28920
|
+
|
|
28921
|
+
function addSchemesFromD3(type, names) {
|
|
28922
|
+
index[type] = index[type].concat(names.split(','));
|
|
28923
|
+
}
|
|
28924
|
+
|
|
28925
|
+
function addCategoricalScheme(name, str) {
|
|
28926
|
+
index.categorical.push(name);
|
|
28927
|
+
ramps[name] = unpackRamp(str);
|
|
28928
|
+
}
|
|
28929
|
+
|
|
28930
|
+
function unpackRamp(str) {
|
|
28931
|
+
var colors = [];
|
|
28932
|
+
for (var i=0, n=str.length; i<n; i+=6) {
|
|
28933
|
+
colors.push('#' + str.substr(i, 6));
|
|
28934
|
+
}
|
|
28935
|
+
return colors;
|
|
28936
|
+
}
|
|
28937
|
+
|
|
28938
|
+
function testLib() {
|
|
28939
|
+
var lib = require('d3-scale-chromatic');
|
|
28940
|
+
schemes(index.categorical);
|
|
28941
|
+
schemes(index.sequential);
|
|
28942
|
+
schemes(index.diverging);
|
|
28943
|
+
interpolators(index.sequential);
|
|
28944
|
+
interpolators(index.rainbow);
|
|
28945
|
+
interpolators(index.diverging);
|
|
28946
|
+
|
|
28947
|
+
function schemes(arr) {
|
|
28948
|
+
arr.forEach(function(name) {
|
|
28949
|
+
if (!lib['scheme' + name]) {
|
|
28950
|
+
message('Warning: missing data for', name);
|
|
28951
|
+
}
|
|
28952
|
+
});
|
|
28953
|
+
}
|
|
28954
|
+
|
|
28955
|
+
function interpolators(arr) {
|
|
28956
|
+
arr.forEach(function(name) {
|
|
28957
|
+
if (!lib['interpolate' + name]) {
|
|
28958
|
+
message('Missing interpolator for', name);
|
|
28959
|
+
}
|
|
28960
|
+
});
|
|
28961
|
+
}
|
|
28962
|
+
}
|
|
28963
|
+
|
|
28964
|
+
function printColorSchemeNames() {
|
|
28965
|
+
initSchemes();
|
|
28966
|
+
print('Built-in color schemes (from d3):');
|
|
28967
|
+
print ('Categorical\n' + formatStringsAsGrid(index.categorical));
|
|
28968
|
+
print ('\nSequential\n' + formatStringsAsGrid(index.sequential));
|
|
28969
|
+
print ('\nDiverging\n' + formatStringsAsGrid(index.diverging));
|
|
28970
|
+
print ('\nMulti-hue/rainbow\n' + formatStringsAsGrid(index.rainbow));
|
|
28971
|
+
}
|
|
28972
|
+
|
|
28973
|
+
function pickRandomColorScheme(type) {
|
|
28974
|
+
initSchemes();
|
|
28975
|
+
var names = index[type];
|
|
28976
|
+
if (!names) error('Unknown color scheme type:', type);
|
|
28977
|
+
var i = Math.floor(Math.random() * names.length);
|
|
28978
|
+
return names[i];
|
|
28979
|
+
}
|
|
28980
|
+
|
|
28981
|
+
function getRandomColors(n) {
|
|
28982
|
+
initSchemes();
|
|
28983
|
+
var colors = getCategoricalColorScheme('Tableau20', 20);
|
|
28984
|
+
utils.shuffle(colors);
|
|
28985
|
+
colors = wrapColors(colors, n);
|
|
28986
|
+
return colors.slice(0, n);
|
|
28987
|
+
}
|
|
28988
|
+
|
|
28989
|
+
function getCategoricalColorScheme(name, n) {
|
|
28990
|
+
var colors;
|
|
28991
|
+
initSchemes();
|
|
28992
|
+
name = standardName(name);
|
|
28993
|
+
if (!isColorSchemeName(name)) {
|
|
28994
|
+
stop('Unknown color scheme name:', name);
|
|
28995
|
+
} else if (isCategoricalColorScheme(name)) {
|
|
28996
|
+
colors = ramps[name] || require('d3-scale-chromatic')['scheme' + name];
|
|
28997
|
+
} else {
|
|
28998
|
+
colors = getColorRamp(name, n);
|
|
28999
|
+
}
|
|
29000
|
+
if (n > colors.length) {
|
|
29001
|
+
// stop(name, 'does not contain', n, 'colors');
|
|
29002
|
+
message('Color scheme has', colors.length, 'colors. Using duplication to match', n, 'categories.');
|
|
29003
|
+
colors = wrapColors(colors, n);
|
|
29004
|
+
} else {
|
|
29005
|
+
colors = colors.slice(0, n);
|
|
29006
|
+
}
|
|
29007
|
+
return colors;
|
|
29008
|
+
}
|
|
29009
|
+
|
|
29010
|
+
function wrapColors(colors, n) {
|
|
29011
|
+
while (colors.length > 0 && colors.length < n) {
|
|
29012
|
+
colors = colors.concat(colors.slice(0, n - colors.length));
|
|
29013
|
+
}
|
|
29014
|
+
return colors;
|
|
29015
|
+
}
|
|
29016
|
+
|
|
29017
|
+
function isColorSchemeName(name) {
|
|
29018
|
+
initSchemes();
|
|
29019
|
+
return index.all.includes(standardName(name));
|
|
29020
|
+
}
|
|
29021
|
+
|
|
29022
|
+
function isCategoricalColorScheme(name) {
|
|
29023
|
+
initSchemes();
|
|
29024
|
+
return index.categorical.includes(standardName(name));
|
|
29025
|
+
}
|
|
29026
|
+
|
|
29027
|
+
function getColorRamp(name, n, stops) {
|
|
29028
|
+
initSchemes();
|
|
29029
|
+
name = standardName(name);
|
|
29030
|
+
var lib = require('d3-scale-chromatic');
|
|
29031
|
+
var ramps = lib['scheme' + name];
|
|
29032
|
+
var interpolate = lib['interpolate' + name];
|
|
29033
|
+
var ramp;
|
|
29034
|
+
if (!ramps && !interpolate) {
|
|
29035
|
+
stop('Unknown color scheme name:', name);
|
|
29036
|
+
}
|
|
29037
|
+
if (index.categorical.includes(name)) {
|
|
29038
|
+
stop(name, ' is a categorical color scheme (expected a sequential color scheme)');
|
|
29039
|
+
}
|
|
29040
|
+
if (ramps && ramps[n]) {
|
|
29041
|
+
ramp = ramps[n];
|
|
29042
|
+
} else {
|
|
29043
|
+
ramp = getInterpolatedRamp(interpolate, n);
|
|
29044
|
+
}
|
|
29045
|
+
if (stops) {
|
|
29046
|
+
ramp = getStoppedValues(ramp, stops);
|
|
29047
|
+
}
|
|
29048
|
+
return ramp;
|
|
29049
|
+
}
|
|
29050
|
+
|
|
29051
|
+
function getInterpolatedRamp(interpolate, n) {
|
|
29052
|
+
if (n > 0 === false || !utils.isInteger(n)) {
|
|
29053
|
+
error('Expected a positive integer');
|
|
29054
|
+
}
|
|
29055
|
+
var ramp = [];
|
|
29056
|
+
for (var i=0; i<n; i++) {
|
|
29057
|
+
ramp.push(interpolate(i / (n - 1)));
|
|
29058
|
+
}
|
|
29059
|
+
return ramp;
|
|
29060
|
+
}
|
|
29061
|
+
|
|
29062
|
+
function getClassValues(method, n, opts) {
|
|
29063
|
+
var categorical = method == 'categorical' || method == 'non-adjacent';
|
|
29064
|
+
var colorArg = opts.colors && opts.colors.length == 1 ? opts.colors[0] : null;
|
|
29065
|
+
var colorScheme;
|
|
29066
|
+
|
|
29067
|
+
if (colorArg == 'random') {
|
|
29068
|
+
if (categorical) {
|
|
29069
|
+
return getRandomColors(n);
|
|
29070
|
+
}
|
|
29071
|
+
colorScheme = pickRandomColorScheme('sequential');
|
|
29072
|
+
message('Randomly selected color ramp:', colorScheme);
|
|
29073
|
+
} else if (isColorSchemeName(colorArg)) {
|
|
29074
|
+
colorScheme = colorArg;
|
|
29075
|
+
} else if (colorArg && !parseColor(colorArg)) {
|
|
29076
|
+
stop('Unrecognized color scheme name:', colorArg);
|
|
29077
|
+
} else if (opts.colors) {
|
|
29078
|
+
opts.colors.forEach(validateColor);
|
|
29079
|
+
}
|
|
29080
|
+
|
|
29081
|
+
if (colorScheme) {
|
|
29082
|
+
if (categorical && isCategoricalColorScheme(colorScheme)) {
|
|
29083
|
+
return getCategoricalColorScheme(colorScheme, n);
|
|
29084
|
+
} else {
|
|
29085
|
+
return getColorRamp(colorScheme, n, opts.stops);
|
|
29086
|
+
}
|
|
29087
|
+
} else if (opts.colors || opts.values) {
|
|
29088
|
+
if (categorical) {
|
|
29089
|
+
return getCategoricalValues(opts.colors || opts.values, n);
|
|
29090
|
+
} else {
|
|
29091
|
+
return getInterpolableValues(opts.colors || opts.values, n, opts);
|
|
29092
|
+
}
|
|
29093
|
+
} else {
|
|
29094
|
+
// use numerical class indexes (0, 1, ...) if no values are given
|
|
29095
|
+
return getIndexes(n);
|
|
29096
|
+
}
|
|
29097
|
+
}
|
|
29098
|
+
|
|
29099
|
+
function getCategoricalValues(values, n) {
|
|
29100
|
+
if (n != values.length) {
|
|
29101
|
+
stop('Mismatch in number of categories and number of values');
|
|
29102
|
+
}
|
|
29103
|
+
return values;
|
|
29104
|
+
}
|
|
29105
|
+
|
|
29106
|
+
function getIndexes(n) {
|
|
29107
|
+
var vals = [];
|
|
29108
|
+
for (var i=0; i<n; i++) {
|
|
29109
|
+
vals.push(i);
|
|
29110
|
+
}
|
|
29111
|
+
return vals;
|
|
29112
|
+
}
|
|
29113
|
+
|
|
29114
|
+
// TODO: check for non-interpolatable value types (e.g. boolean, text)
|
|
29115
|
+
function getInterpolableValues(arr, n, opts) {
|
|
29116
|
+
var values = parseValues(arr);
|
|
29117
|
+
if (n != values.length || opts.stops) {
|
|
29118
|
+
return interpolateValuesToClasses(values, n, opts.stops);
|
|
29119
|
+
}
|
|
29120
|
+
return values;
|
|
29121
|
+
}
|
|
29122
|
+
|
|
29123
|
+
// convert strings to numbers if they all parse as numbers
|
|
29124
|
+
// arr: an array of strings
|
|
29125
|
+
function parseValues(strings) {
|
|
29126
|
+
var values = strings;
|
|
29127
|
+
if (strings.every(utils.parseNumber)) {
|
|
29128
|
+
values = strings.map(function(str) {
|
|
29129
|
+
return +str;
|
|
29130
|
+
});
|
|
29131
|
+
}
|
|
29132
|
+
return values;
|
|
29133
|
+
}
|
|
29134
|
+
|
|
29135
|
+
var sequential = ['quantile', 'nice', 'equal-interval', 'hybrid'];
|
|
29136
|
+
var all = ['non-adjacent', 'indexed', 'categorical'].concat(sequential);
|
|
29137
|
+
|
|
29138
|
+
function getClassifyMethod(opts, dataFieldType) {
|
|
29139
|
+
var method;
|
|
29140
|
+
if (opts.method) {
|
|
29141
|
+
method = opts.method;
|
|
29142
|
+
} else if (opts.index_field) {
|
|
29143
|
+
method = 'indexed';
|
|
29144
|
+
} else if (opts.categories || dataFieldType == 'string') {
|
|
29145
|
+
method = 'categorical';
|
|
29146
|
+
} else if (dataFieldType == 'number') {
|
|
29147
|
+
method = 'quantile'; // TODO: validate data field
|
|
29148
|
+
} else {
|
|
29149
|
+
// stop('Unable to determine which classification method to use.');
|
|
29150
|
+
stop('Missing a data field and/or classification method');
|
|
29151
|
+
}
|
|
29152
|
+
if (!all.includes(method)) {
|
|
29153
|
+
stop('Not a recognized classification method:', method);
|
|
29154
|
+
}
|
|
29155
|
+
if (sequential.includes(method) && dataFieldType != 'number') {
|
|
29156
|
+
stop('The', method, 'method requires a numerical data field');
|
|
29157
|
+
}
|
|
29158
|
+
return method;
|
|
29159
|
+
}
|
|
29160
|
+
|
|
29008
29161
|
cmd.classify = function(lyr, dataset, optsArg) {
|
|
29009
29162
|
if (!lyr.data) {
|
|
29010
29163
|
initDataTable(lyr);
|
|
29011
29164
|
}
|
|
29012
29165
|
var opts = optsArg || {};
|
|
29013
29166
|
var records = lyr.data && lyr.data.getRecords();
|
|
29014
|
-
var
|
|
29015
|
-
var
|
|
29016
|
-
var
|
|
29017
|
-
var
|
|
29167
|
+
var valuesAreColors = !!opts.colors;
|
|
29168
|
+
var dataField, dataFieldType, outputField;
|
|
29169
|
+
var values, nullValue;
|
|
29170
|
+
var classifyByValue, classifyByRecordId;
|
|
29018
29171
|
var numClasses, numValues;
|
|
29019
|
-
var dataField, outputField;
|
|
29020
29172
|
var method;
|
|
29021
29173
|
|
|
29022
|
-
|
|
29023
|
-
|
|
29024
|
-
if (!utils.isInteger(opts.classes) || opts.classes > 1 === false) {
|
|
29025
|
-
stop('Invalid number of classes:', opts.classes, '(expected a value greater than 1)');
|
|
29026
|
-
}
|
|
29027
|
-
numClasses = opts.classes;
|
|
29028
|
-
}
|
|
29029
|
-
|
|
29030
|
-
// TODO: better validation of breaks values
|
|
29031
|
-
if (opts.breaks) {
|
|
29032
|
-
numClasses = opts.breaks.length + 1;
|
|
29174
|
+
if (opts.color_scheme) {
|
|
29175
|
+
stop('color-scheme is not a valid option, use colors instead');
|
|
29033
29176
|
}
|
|
29034
29177
|
|
|
29178
|
+
// get data field to use for classification
|
|
29179
|
+
//
|
|
29035
29180
|
if (opts.index_field) {
|
|
29036
29181
|
dataField = opts.index_field;
|
|
29037
|
-
if (numClasses > 0 === false) {
|
|
29038
|
-
stop('The index-field= option requires the classes= option to be set');
|
|
29039
|
-
}
|
|
29040
|
-
// You can't infer the number of classes by looking at index values;
|
|
29041
|
-
// this can cause unwanted interpolation if one or more values are
|
|
29042
|
-
// not present in the index field
|
|
29043
|
-
// numClasses = validateClassIndexField(records, opts.index_field);
|
|
29044
|
-
|
|
29045
29182
|
} else if (opts.field) {
|
|
29046
29183
|
dataField = opts.field;
|
|
29184
|
+
dataFieldType = getColumnType(opts.field, records);
|
|
29047
29185
|
}
|
|
29048
|
-
|
|
29049
|
-
|
|
29050
|
-
if (dataField && opts.categories && opts.categories.includes('*')) {
|
|
29051
|
-
opts.categories = getUniqFieldValues(records, dataField);
|
|
29186
|
+
if (dataField) {
|
|
29187
|
+
requireDataField(lyr.data, dataField);
|
|
29052
29188
|
}
|
|
29053
29189
|
|
|
29054
29190
|
// get classification method
|
|
29055
29191
|
//
|
|
29056
|
-
|
|
29057
|
-
method = opts.method;
|
|
29058
|
-
} else if (opts.categories) {
|
|
29059
|
-
method = 'categorical';
|
|
29060
|
-
} else if (opts.index_field) {
|
|
29061
|
-
method = 'indexed';
|
|
29062
|
-
} else {
|
|
29063
|
-
method = 'quantile'; // TODO: validate data field
|
|
29064
|
-
}
|
|
29192
|
+
method = getClassifyMethod(opts, dataFieldType);
|
|
29065
29193
|
|
|
29194
|
+
// validate classification method
|
|
29066
29195
|
if (method == 'non-adjacent') {
|
|
29067
29196
|
if (lyr.geometry_type != 'polygon') {
|
|
29068
29197
|
stop('The non-adjacent option requires a polygon layer');
|
|
@@ -29072,83 +29201,70 @@ ${svg}
|
|
|
29072
29201
|
}
|
|
29073
29202
|
} else if (!dataField) {
|
|
29074
29203
|
stop('Missing a data field to classify');
|
|
29075
|
-
} else {
|
|
29076
|
-
requireDataField(lyr.data, dataField);
|
|
29077
29204
|
}
|
|
29078
29205
|
|
|
29079
|
-
if (numClasses) {
|
|
29080
|
-
numValues = opts.continuous ? numClasses + 1 : numClasses;
|
|
29081
|
-
}
|
|
29082
29206
|
|
|
29083
|
-
//
|
|
29084
|
-
|
|
29085
|
-
|
|
29086
|
-
|
|
29207
|
+
// get the number of classes and the number of values
|
|
29208
|
+
//
|
|
29209
|
+
// expand categories if value is '*'
|
|
29210
|
+
if (method == 'categorical') {
|
|
29211
|
+
if ((!opts.categories || opts.categories.includes('*')) && dataField) {
|
|
29212
|
+
opts.categories = getUniqFieldValues(records, dataField);
|
|
29087
29213
|
}
|
|
29088
|
-
colorScheme = opts.color_scheme;
|
|
29089
|
-
} else if (opts.colors && isColorSchemeName(opts.colors[0])) {
|
|
29090
|
-
colorScheme = opts.colors[0];
|
|
29091
|
-
} else if (opts.colors) {
|
|
29092
|
-
opts.colors.forEach(parseColor); // validate colors -- error if unparsable
|
|
29093
29214
|
}
|
|
29094
29215
|
|
|
29095
|
-
|
|
29096
|
-
|
|
29097
|
-
|
|
29098
|
-
if (method == 'non-adjacent') {
|
|
29099
|
-
numClasses = numValues = numClasses || 5;
|
|
29100
|
-
values = getCategoricalColorScheme(colorScheme, numValues);
|
|
29101
|
-
|
|
29102
|
-
} else if (method == 'categorical') {
|
|
29103
|
-
values = getCategoricalColorScheme(colorScheme, opts.categories.length);
|
|
29104
|
-
numClasses = numValues = values.length;
|
|
29105
|
-
|
|
29106
|
-
} else {
|
|
29107
|
-
if (!numClasses) {
|
|
29108
|
-
// stop('color-scheme= option requires classes= or breaks=');
|
|
29109
|
-
numClasses = 4; // use a default number of classes
|
|
29110
|
-
numValues = opts.continuous ? numClasses + 1 : numClasses;
|
|
29111
|
-
}
|
|
29112
|
-
values = getColorRamp(colorScheme, numValues, opts.stops);
|
|
29113
|
-
}
|
|
29114
|
-
|
|
29115
|
-
} else if (opts.colors || opts.values) {
|
|
29116
|
-
values = opts.values ? parseValues(opts.values) : opts.colors;
|
|
29117
|
-
if (!numValues) {
|
|
29118
|
-
numValues = values.length;
|
|
29119
|
-
}
|
|
29120
|
-
if ((values.length != numValues || opts.stops) && numValues > 1) {
|
|
29121
|
-
// TODO: handle numValues == 1
|
|
29122
|
-
// TODO: check for non-interpolatable value types (e.g. boolean, text)
|
|
29123
|
-
values = interpolateValuesToClasses(values, numValues, opts.stops);
|
|
29216
|
+
if (opts.classes) {
|
|
29217
|
+
if (!utils.isInteger(opts.classes) || opts.classes > 1 === false) {
|
|
29218
|
+
stop('Invalid number of classes:', opts.classes, '(expected a value greater than 1)');
|
|
29124
29219
|
}
|
|
29125
|
-
|
|
29126
|
-
} else if (
|
|
29127
|
-
|
|
29128
|
-
|
|
29129
|
-
|
|
29130
|
-
}
|
|
29131
|
-
|
|
29132
|
-
if (
|
|
29133
|
-
|
|
29220
|
+
numClasses = opts.classes;
|
|
29221
|
+
} else if (method == 'indexed' && dataField) {
|
|
29222
|
+
numClasses = getIndexedClassCount(records, dataField);
|
|
29223
|
+
} else if (opts.breaks) {
|
|
29224
|
+
numClasses = opts.breaks.length + 1;
|
|
29225
|
+
} else if (method == 'categorical' && opts.categories) {
|
|
29226
|
+
numClasses = opts.categories.length;
|
|
29227
|
+
} else if (opts.colors && opts.colors.length > 1) {
|
|
29228
|
+
numClasses = opts.colors.length;
|
|
29229
|
+
} else if (opts.values && opts.values.length > 1) {
|
|
29230
|
+
numClasses = opts.values.length;
|
|
29231
|
+
} else if (method == 'non-adjacent') {
|
|
29232
|
+
numClasses = 5;
|
|
29233
|
+
} else {
|
|
29234
|
+
numClasses = 4;
|
|
29134
29235
|
}
|
|
29135
|
-
|
|
29236
|
+
numValues = opts.continuous ? numClasses + 1 : numClasses;
|
|
29136
29237
|
if (numValues > 1 === false) {
|
|
29137
|
-
stop('Missing a valid number of
|
|
29238
|
+
stop('Missing a valid number of values');
|
|
29138
29239
|
}
|
|
29139
29240
|
|
|
29241
|
+
// get colors or other values
|
|
29242
|
+
//
|
|
29243
|
+
values = getClassValues(method, numValues, opts);
|
|
29140
29244
|
if (opts.invert) {
|
|
29141
29245
|
values = values.concat().reverse();
|
|
29142
29246
|
}
|
|
29143
|
-
|
|
29144
29247
|
if (valuesAreColors) {
|
|
29145
29248
|
message('Colors:', formatValuesForLogging(values));
|
|
29146
29249
|
}
|
|
29147
29250
|
|
|
29251
|
+
// get null value
|
|
29252
|
+
//
|
|
29253
|
+
if ('null_value' in opts) {
|
|
29254
|
+
nullValue = opts.null_value;
|
|
29255
|
+
} else if (valuesAreColors) {
|
|
29256
|
+
nullValue = '#eee';
|
|
29257
|
+
} else if (opts.values) {
|
|
29258
|
+
nullValue = null;
|
|
29259
|
+
} else {
|
|
29260
|
+
nullValue = -1; // kludge, to match behavior of getClassValues()
|
|
29261
|
+
}
|
|
29262
|
+
|
|
29263
|
+
|
|
29148
29264
|
// get a function to convert input data to class indexes
|
|
29149
29265
|
//
|
|
29150
29266
|
if (method == 'non-adjacent') {
|
|
29151
|
-
|
|
29267
|
+
classifyByRecordId = getNonAdjacentClassifier(lyr, dataset, values);
|
|
29152
29268
|
} else if (opts.index_field) {
|
|
29153
29269
|
// data is pre-classified... just read the index from a field
|
|
29154
29270
|
classifyByValue = getIndexedClassifier(values, nullValue, opts);
|
|
@@ -29159,13 +29275,12 @@ ${svg}
|
|
|
29159
29275
|
}
|
|
29160
29276
|
|
|
29161
29277
|
if (classifyByValue) {
|
|
29162
|
-
|
|
29278
|
+
classifyByRecordId = function(id) {
|
|
29163
29279
|
var d = records[id] || {};
|
|
29164
29280
|
return classifyByValue(d[dataField]);
|
|
29165
29281
|
};
|
|
29166
29282
|
}
|
|
29167
29283
|
|
|
29168
|
-
|
|
29169
29284
|
// get the name of the output field
|
|
29170
29285
|
//
|
|
29171
29286
|
if (valuesAreColors) {
|
|
@@ -29181,23 +29296,10 @@ ${svg}
|
|
|
29181
29296
|
}
|
|
29182
29297
|
|
|
29183
29298
|
records.forEach(function(d, i) {
|
|
29184
|
-
d[outputField] =
|
|
29299
|
+
d[outputField] = classifyByRecordId(i);
|
|
29185
29300
|
});
|
|
29186
29301
|
};
|
|
29187
29302
|
|
|
29188
|
-
|
|
29189
|
-
// convert strings to numbers if they all parse as numbers
|
|
29190
|
-
// arr: an array of strings
|
|
29191
|
-
function parseValues(strings) {
|
|
29192
|
-
var values = strings;
|
|
29193
|
-
if (strings.every(utils.parseNumber)) {
|
|
29194
|
-
values = strings.map(function(str) {
|
|
29195
|
-
return +str;
|
|
29196
|
-
});
|
|
29197
|
-
}
|
|
29198
|
-
return values;
|
|
29199
|
-
}
|
|
29200
|
-
|
|
29201
29303
|
function formatValuesForLogging(arr) {
|
|
29202
29304
|
if (arr.some(val => utils.isString(val) && val.indexOf('rgb(') === 0)) {
|
|
29203
29305
|
return formatColorsAsHex(arr);
|
|
@@ -29214,15 +29316,6 @@ ${svg}
|
|
|
29214
29316
|
});
|
|
29215
29317
|
}
|
|
29216
29318
|
|
|
29217
|
-
|
|
29218
|
-
function getIndexValues(n) {
|
|
29219
|
-
var vals = [];
|
|
29220
|
-
for (var i=0; i<n; i++) {
|
|
29221
|
-
vals.push(i);
|
|
29222
|
-
}
|
|
29223
|
-
return vals;
|
|
29224
|
-
}
|
|
29225
|
-
|
|
29226
29319
|
// Remove small-area polygon rings (very simple implementation of sliver removal)
|
|
29227
29320
|
// TODO: more sophisticated sliver detection (e.g. could consider ratio of area to perimeter)
|
|
29228
29321
|
// TODO: consider merging slivers into adjacent polygons to prevent gaps from forming
|
|
@@ -31087,7 +31180,11 @@ ${svg}
|
|
|
31087
31180
|
if (!opts.force && !opts.prefix) {
|
|
31088
31181
|
// overwrite existing fields if the "force" option is set.
|
|
31089
31182
|
// prefix also overwrites... TODO: consider changing this
|
|
31090
|
-
|
|
31183
|
+
var duplicateFields = utils.intersection(joinFields, destFields);
|
|
31184
|
+
if (duplicateFields.length > 0) {
|
|
31185
|
+
message('Same-named fields not joined without the "force" flag:', duplicateFields);
|
|
31186
|
+
joinFields = utils.difference(joinFields, duplicateFields);
|
|
31187
|
+
}
|
|
31091
31188
|
}
|
|
31092
31189
|
return joinFields;
|
|
31093
31190
|
}
|
|
@@ -31819,7 +31916,7 @@ ${svg}
|
|
|
31819
31916
|
// stop("Missing required colors parameter");
|
|
31820
31917
|
// }
|
|
31821
31918
|
if (Array.isArray(opts.colors)) {
|
|
31822
|
-
opts.colors.forEach(
|
|
31919
|
+
opts.colors.forEach(validateColor);
|
|
31823
31920
|
}
|
|
31824
31921
|
|
|
31825
31922
|
var records = lyr.data ? lyr.data.getRecords() : [];
|
|
@@ -32058,7 +32155,7 @@ ${svg}
|
|
|
32058
32155
|
var name = cmdOpts.name;
|
|
32059
32156
|
var cmdDefn = externalCommands[name];
|
|
32060
32157
|
if (!cmdDefn) {
|
|
32061
|
-
stop('Unsupported command');
|
|
32158
|
+
stop('Unsupported command:', name);
|
|
32062
32159
|
}
|
|
32063
32160
|
var targetType = cmdDefn.target;
|
|
32064
32161
|
var opts = parseExternalCommand(name, cmdDefn, cmdOpts._);
|
|
@@ -35056,7 +35153,6 @@ ${svg}
|
|
|
35056
35153
|
}
|
|
35057
35154
|
|
|
35058
35155
|
|
|
35059
|
-
|
|
35060
35156
|
function snapVerticesToPoint(ids, p, arcs, final) {
|
|
35061
35157
|
ids.forEach(function(idx) {
|
|
35062
35158
|
setVertexCoords(p[0], p[1], idx, arcs);
|
|
@@ -35136,7 +35232,7 @@ ${svg}
|
|
|
35136
35232
|
function findNearestVertex(x, y, shp, arcs, spherical) {
|
|
35137
35233
|
var calcLen = spherical ? geom.greatCircleDistance : geom.distance2D,
|
|
35138
35234
|
minLen = Infinity,
|
|
35139
|
-
minX, minY,
|
|
35235
|
+
minX, minY, dist, iter;
|
|
35140
35236
|
for (var i=0; i<shp.length; i++) {
|
|
35141
35237
|
iter = arcs.getShapeIter(shp[i]);
|
|
35142
35238
|
while (iter.hasNext()) {
|
|
@@ -35145,26 +35241,10 @@ ${svg}
|
|
|
35145
35241
|
minLen = dist;
|
|
35146
35242
|
minX = iter.x;
|
|
35147
35243
|
minY = iter.y;
|
|
35148
|
-
vId = iter.i;
|
|
35149
35244
|
}
|
|
35150
35245
|
}
|
|
35151
35246
|
}
|
|
35152
|
-
return minLen < Infinity ? {x: minX, y: minY
|
|
35153
|
-
}
|
|
35154
|
-
|
|
35155
|
-
// v: vertex in {x, y, i} format
|
|
35156
|
-
function findAdjacentVertex(v, shp, arcs, offs) {
|
|
35157
|
-
var p, i;
|
|
35158
|
-
var arcEnd = offs == 1 && vertexIsArcEnd(v.i, arcs);
|
|
35159
|
-
var arcStart = offs == -1 && vertexIsArcStart(v.i, arcs);
|
|
35160
|
-
if (arcEnd || arcStart) return null;
|
|
35161
|
-
i = v.i + offs;
|
|
35162
|
-
p = getVertexCoords(i, arcs);
|
|
35163
|
-
return {
|
|
35164
|
-
i: i,
|
|
35165
|
-
x: p[0],
|
|
35166
|
-
y: p[1]
|
|
35167
|
-
};
|
|
35247
|
+
return minLen < Infinity ? {x: minX, y: minY} : null;
|
|
35168
35248
|
}
|
|
35169
35249
|
|
|
35170
35250
|
var VertexUtils = /*#__PURE__*/Object.freeze({
|
|
@@ -35177,8 +35257,7 @@ ${svg}
|
|
|
35177
35257
|
vertexIsArcEnd: vertexIsArcEnd,
|
|
35178
35258
|
vertexIsArcStart: vertexIsArcStart,
|
|
35179
35259
|
setVertexCoords: setVertexCoords,
|
|
35180
|
-
findNearestVertex: findNearestVertex
|
|
35181
|
-
findAdjacentVertex: findAdjacentVertex
|
|
35260
|
+
findNearestVertex: findNearestVertex
|
|
35182
35261
|
});
|
|
35183
35262
|
|
|
35184
35263
|
// Returns x,y coordinates of the point that is at the midpoint of each polyline feature
|
|
@@ -36856,8 +36935,12 @@ ${svg}
|
|
|
36856
36935
|
// support multiline string of commands pasted into console
|
|
36857
36936
|
str = str.split(/\n+/g).map(function(str) {
|
|
36858
36937
|
var match = /^[a-z][\w-]*/.exec(str = str.trim());
|
|
36859
|
-
if (match && parser.isCommandName(match[0])) {
|
|
36860
|
-
|
|
36938
|
+
//if (match && parser.isCommandName(match[0])) {
|
|
36939
|
+
if (match) {
|
|
36940
|
+
// add hyphen prefix to bare command
|
|
36941
|
+
// also add hyphen to non-command strings, for a better error message
|
|
36942
|
+
// ("unsupported command" instead of "The -i command cannot be run in the browser")
|
|
36943
|
+
str = '-' + str;
|
|
36861
36944
|
}
|
|
36862
36945
|
return str;
|
|
36863
36946
|
}).join(' ');
|