mapshaper 0.6.25 → 0.6.27
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/mapshaper.js +127 -26
- package/package.json +2 -2
- package/www/index.html +6 -8
- package/www/mapshaper-gui.js +4 -0
- package/www/mapshaper.js +127 -26
- package/www/modules.js +4 -1
package/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.27";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -13728,6 +13728,28 @@
|
|
|
13728
13728
|
}});
|
|
13729
13729
|
}
|
|
13730
13730
|
|
|
13731
|
+
if (hasPaths || hasPoints) {
|
|
13732
|
+
addGetters(ctx, {
|
|
13733
|
+
// TODO: count hole/s + containing ring as one part
|
|
13734
|
+
partCount: function() {
|
|
13735
|
+
var shp = lyr.shapes[_id];
|
|
13736
|
+
return shp ? shp.length : 0;
|
|
13737
|
+
},
|
|
13738
|
+
isNull: function() {
|
|
13739
|
+
return ctx.partCount === 0;
|
|
13740
|
+
},
|
|
13741
|
+
bounds: function() {
|
|
13742
|
+
return shapeBounds().toArray();
|
|
13743
|
+
},
|
|
13744
|
+
height: function() {
|
|
13745
|
+
return shapeBounds().height();
|
|
13746
|
+
},
|
|
13747
|
+
width: function() {
|
|
13748
|
+
return shapeBounds().width();
|
|
13749
|
+
}
|
|
13750
|
+
});
|
|
13751
|
+
}
|
|
13752
|
+
|
|
13731
13753
|
if (hasPaths) {
|
|
13732
13754
|
|
|
13733
13755
|
ctx.bboxContainsPoint = function(x, y) {
|
|
@@ -13758,25 +13780,6 @@
|
|
|
13758
13780
|
// ctx.containsPoint = function(x, y) {}; // polygon only
|
|
13759
13781
|
// ctx.containedByRectangle(a, b, c, d); // paths and points... how do multipart points work?
|
|
13760
13782
|
|
|
13761
|
-
addGetters(ctx, {
|
|
13762
|
-
// TODO: count hole/s + containing ring as one part
|
|
13763
|
-
partCount: function() {
|
|
13764
|
-
return _ids ? _ids.length : 0;
|
|
13765
|
-
},
|
|
13766
|
-
isNull: function() {
|
|
13767
|
-
return ctx.partCount === 0;
|
|
13768
|
-
},
|
|
13769
|
-
bounds: function() {
|
|
13770
|
-
return shapeBounds().toArray();
|
|
13771
|
-
},
|
|
13772
|
-
height: function() {
|
|
13773
|
-
return shapeBounds().height();
|
|
13774
|
-
},
|
|
13775
|
-
width: function() {
|
|
13776
|
-
return shapeBounds().width();
|
|
13777
|
-
}
|
|
13778
|
-
});
|
|
13779
|
-
|
|
13780
13783
|
if (lyr.geometry_type == 'polyline') {
|
|
13781
13784
|
addGetters(ctx, {
|
|
13782
13785
|
'length': function() {
|
|
@@ -13838,7 +13841,7 @@
|
|
|
13838
13841
|
}
|
|
13839
13842
|
|
|
13840
13843
|
} else if (hasPoints) {
|
|
13841
|
-
|
|
13844
|
+
|
|
13842
13845
|
Object.defineProperty(ctx, 'coordinates',
|
|
13843
13846
|
{set: function(obj) {
|
|
13844
13847
|
if (!obj || utils.isArray(obj)) {
|
|
@@ -13877,8 +13880,13 @@
|
|
|
13877
13880
|
}
|
|
13878
13881
|
|
|
13879
13882
|
function shapeBounds() {
|
|
13880
|
-
if (
|
|
13883
|
+
if (_bounds) return _bounds;
|
|
13884
|
+
if (hasPaths) {
|
|
13881
13885
|
_bounds = arcs.getMultiShapeBounds(_ids);
|
|
13886
|
+
} else if (hasPoints) {
|
|
13887
|
+
_bounds = getPointFeatureBounds(lyr.shapes[_id]);
|
|
13888
|
+
} else {
|
|
13889
|
+
_bounds = new Bounds();
|
|
13882
13890
|
}
|
|
13883
13891
|
return _bounds;
|
|
13884
13892
|
}
|
|
@@ -13886,8 +13894,8 @@
|
|
|
13886
13894
|
return function(id) {
|
|
13887
13895
|
_id = id;
|
|
13888
13896
|
// reset stored values
|
|
13897
|
+
_bounds = null;
|
|
13889
13898
|
if (hasPaths) {
|
|
13890
|
-
_bounds = null;
|
|
13891
13899
|
_centroid = null;
|
|
13892
13900
|
_innerXY = null;
|
|
13893
13901
|
_ids = lyr.shapes[id];
|
|
@@ -14292,9 +14300,9 @@
|
|
|
14292
14300
|
}
|
|
14293
14301
|
|
|
14294
14302
|
function compileCalcExpression(lyr, arcs, exp) {
|
|
14295
|
-
var rowNo = 0, colNo = 0, cols = [];
|
|
14303
|
+
var rowNo = 0, colNo = 0, recId = -1, cols = [];
|
|
14296
14304
|
var ctx1 = { // context for first phase (capturing values for each feature)
|
|
14297
|
-
count: assign,
|
|
14305
|
+
count: assign, // dummy function - first pass does nothing
|
|
14298
14306
|
sum: captureNum,
|
|
14299
14307
|
sums: capture,
|
|
14300
14308
|
average: captureNum,
|
|
@@ -14309,6 +14317,7 @@
|
|
|
14309
14317
|
max: captureNum,
|
|
14310
14318
|
mode: capture,
|
|
14311
14319
|
collect: capture,
|
|
14320
|
+
collectIds: captureId,
|
|
14312
14321
|
first: assignOnce,
|
|
14313
14322
|
every: every,
|
|
14314
14323
|
some: some,
|
|
@@ -14332,6 +14341,7 @@
|
|
|
14332
14341
|
mean: wrap(utils.mean),
|
|
14333
14342
|
mode: wrap(getMode),
|
|
14334
14343
|
collect: wrap(pass),
|
|
14344
|
+
collectIds: wrap(pass),
|
|
14335
14345
|
first: wrap(pass),
|
|
14336
14346
|
every: wrap(pass, false),
|
|
14337
14347
|
some: wrap(pass, false),
|
|
@@ -14418,6 +14428,7 @@
|
|
|
14418
14428
|
|
|
14419
14429
|
function procRecord(i) {
|
|
14420
14430
|
if (i < 0 || i >= len) error("Invalid record index");
|
|
14431
|
+
recId = i;
|
|
14421
14432
|
calc1(i);
|
|
14422
14433
|
rowNo++;
|
|
14423
14434
|
colNo = 0;
|
|
@@ -14426,6 +14437,7 @@
|
|
|
14426
14437
|
function noop() {}
|
|
14427
14438
|
|
|
14428
14439
|
function reset() {
|
|
14440
|
+
recId = -1;
|
|
14429
14441
|
rowNo = 0;
|
|
14430
14442
|
colNo = 0;
|
|
14431
14443
|
cols = [];
|
|
@@ -14467,6 +14479,10 @@
|
|
|
14467
14479
|
}
|
|
14468
14480
|
*/
|
|
14469
14481
|
|
|
14482
|
+
function captureId() {
|
|
14483
|
+
capture(recId);
|
|
14484
|
+
}
|
|
14485
|
+
|
|
14470
14486
|
function capture(val) {
|
|
14471
14487
|
var col;
|
|
14472
14488
|
if (rowNo === 0) {
|
|
@@ -32896,6 +32912,8 @@ ${svg}
|
|
|
32896
32912
|
var colorArg = opts.colors && opts.colors.length == 1 ? opts.colors[0] : null;
|
|
32897
32913
|
var colorScheme;
|
|
32898
32914
|
|
|
32915
|
+
if (method == 'blacki') return [];
|
|
32916
|
+
|
|
32899
32917
|
if (colorArg == 'random') {
|
|
32900
32918
|
if (categorical) {
|
|
32901
32919
|
return getRandomColors(n);
|
|
@@ -32965,7 +32983,7 @@ ${svg}
|
|
|
32965
32983
|
}
|
|
32966
32984
|
|
|
32967
32985
|
var sequential = ['quantile', 'nice', 'equal-interval', 'hybrid', 'breaks'];
|
|
32968
|
-
var all = ['non-adjacent', 'indexed', 'categorical'].concat(sequential);
|
|
32986
|
+
var all = ['non-adjacent', 'indexed', 'categorical', 'blacki'].concat(sequential);
|
|
32969
32987
|
|
|
32970
32988
|
function getClassifyMethod(opts, dataType) {
|
|
32971
32989
|
var method;
|
|
@@ -32999,6 +33017,85 @@ ${svg}
|
|
|
32999
33017
|
return method;
|
|
33000
33018
|
}
|
|
33001
33019
|
|
|
33020
|
+
function getBlackiClassifier(lyr, dataField) {
|
|
33021
|
+
var records = lyr.data.getRecords();
|
|
33022
|
+
// classes are integers, dataIds can be any scalar
|
|
33023
|
+
var dataToClassIndex = {};
|
|
33024
|
+
var classToDataIndex = [];
|
|
33025
|
+
var classCount = 0;
|
|
33026
|
+
|
|
33027
|
+
records.forEach(function(rec, recId) {
|
|
33028
|
+
var dataIds = rec[dataField];
|
|
33029
|
+
var thisClass = -1;
|
|
33030
|
+
var thatClass, dataId;
|
|
33031
|
+
|
|
33032
|
+
if (!Array.isArray(dataIds)) return;
|
|
33033
|
+
|
|
33034
|
+
for (var i=0; i<dataIds.length; i++) {
|
|
33035
|
+
dataId = dataIds[i];
|
|
33036
|
+
thatClass = dataId in dataToClassIndex ? dataToClassIndex[dataId] : -1;
|
|
33037
|
+
if (thatClass == -1) {
|
|
33038
|
+
if (thisClass == -1) {
|
|
33039
|
+
thisClass = classCount++;
|
|
33040
|
+
}
|
|
33041
|
+
if (Array.isArray(classToDataIndex[thisClass])) {
|
|
33042
|
+
if (!classToDataIndex[thisClass].includes(dataId)) {
|
|
33043
|
+
classToDataIndex[thisClass].push(dataId);
|
|
33044
|
+
}
|
|
33045
|
+
} else {
|
|
33046
|
+
classToDataIndex[thisClass] = [dataId];
|
|
33047
|
+
}
|
|
33048
|
+
dataToClassIndex[dataId] = thisClass;
|
|
33049
|
+
|
|
33050
|
+
} else {
|
|
33051
|
+
|
|
33052
|
+
if (thisClass == -1) {
|
|
33053
|
+
thisClass = thatClass;
|
|
33054
|
+
} else if (thisClass > thatClass) {
|
|
33055
|
+
mergeClassIntoClass(thisClass, thatClass);
|
|
33056
|
+
thisClass = thatClass;
|
|
33057
|
+
} else if (thisClass < thatClass) {
|
|
33058
|
+
mergeClassIntoClass(thatClass, thisClass);
|
|
33059
|
+
}
|
|
33060
|
+
}
|
|
33061
|
+
}
|
|
33062
|
+
});
|
|
33063
|
+
|
|
33064
|
+
var remapTable = compressClassIds();
|
|
33065
|
+
var classIds = records.map(function(rec) {
|
|
33066
|
+
var ids = rec[dataField];
|
|
33067
|
+
if (!Array.isArray(ids) || ids.length === 0) return -1;
|
|
33068
|
+
// TODO: assert that ids all belong to the same class
|
|
33069
|
+
if (ids[0] in dataToClassIndex === false) {
|
|
33070
|
+
error('Internal error');
|
|
33071
|
+
}
|
|
33072
|
+
return remapTable[dataToClassIndex[ids[0]]];
|
|
33073
|
+
});
|
|
33074
|
+
|
|
33075
|
+
classToDataIndex = null;
|
|
33076
|
+
dataToClassIndex = null;
|
|
33077
|
+
|
|
33078
|
+
return function(recId) {
|
|
33079
|
+
return classIds[recId];
|
|
33080
|
+
};
|
|
33081
|
+
|
|
33082
|
+
function compressClassIds() {
|
|
33083
|
+
var newId = -1;
|
|
33084
|
+
return classToDataIndex.map(function(d, oldId) {
|
|
33085
|
+
if (d !== null) newId++;
|
|
33086
|
+
return newId;
|
|
33087
|
+
});
|
|
33088
|
+
}
|
|
33089
|
+
|
|
33090
|
+
function mergeClassIntoClass(fromId, toId) {
|
|
33091
|
+
classToDataIndex[fromId].forEach(function(dataId) {
|
|
33092
|
+
dataToClassIndex[dataId] = toId;
|
|
33093
|
+
});
|
|
33094
|
+
classToDataIndex[toId] = utils.uniq(classToDataIndex[toId].concat(classToDataIndex[fromId]));
|
|
33095
|
+
classToDataIndex[fromId] = null;
|
|
33096
|
+
}
|
|
33097
|
+
}
|
|
33098
|
+
|
|
33002
33099
|
cmd.classify = function(lyr, dataset, optsArg) {
|
|
33003
33100
|
if (!lyr.data) {
|
|
33004
33101
|
initDataTable(lyr);
|
|
@@ -33061,6 +33158,8 @@ ${svg}
|
|
|
33061
33158
|
stop('Invalid number of classes:', opts.classes, '(expected a value greater than 1)');
|
|
33062
33159
|
}
|
|
33063
33160
|
numClasses = opts.classes;
|
|
33161
|
+
} else if (method == 'blacki') {
|
|
33162
|
+
numClasses = 999; // dummy value
|
|
33064
33163
|
} else if (method == 'indexed' && dataField) {
|
|
33065
33164
|
numClasses = getIndexedClassCount(records, dataField);
|
|
33066
33165
|
} else if (opts.breaks) {
|
|
@@ -33098,6 +33197,8 @@ ${svg}
|
|
|
33098
33197
|
if (fieldType === null) {
|
|
33099
33198
|
// no valid data -- always return null value
|
|
33100
33199
|
classifyByRecordId = function() {return nullValue;};
|
|
33200
|
+
} else if (method == 'blacki') {
|
|
33201
|
+
classifyByRecordId = getBlackiClassifier(lyr, dataField);
|
|
33101
33202
|
} else if (method == 'non-adjacent') {
|
|
33102
33203
|
classifyByRecordId = getNonAdjacentClassifier(lyr, dataset, values);
|
|
33103
33204
|
} else if (method == 'indexed') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mapshaper",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.27",
|
|
4
4
|
"description": "A tool for editing vector datasets for mapping and GIS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shapefile",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"iconv-lite": "^0.6.3",
|
|
57
57
|
"idb-keyval": "^6.2.0",
|
|
58
58
|
"kdbush": "^3.0.0",
|
|
59
|
-
"mproj": "0.0.
|
|
59
|
+
"mproj": "0.0.36",
|
|
60
60
|
"msgpackr": "^1.8.5",
|
|
61
61
|
"opn": "^5.3.0",
|
|
62
62
|
"rw": "~1.3.3",
|
package/www/index.html
CHANGED
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
9
9
|
<link rel="stylesheet" href="page.css">
|
|
10
10
|
<link rel="stylesheet" href="elements.css">
|
|
11
|
-
<link rel="icon"
|
|
12
|
-
type="image/png"
|
|
13
|
-
href="images/icon.png">
|
|
11
|
+
<link rel="icon" type="image/png" href="images/icon.png">
|
|
14
12
|
</head>
|
|
15
13
|
<body>
|
|
16
14
|
<div class="hidden">
|
|
@@ -99,8 +97,8 @@
|
|
|
99
97
|
<h3>Layers</h3>
|
|
100
98
|
<div class="pin-all pinnable">
|
|
101
99
|
<img class="pin-btn unpinned" src="images/eye.png">
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
<img class="pin-btn pinned" src="images/eye2.png">
|
|
101
|
+
</div>
|
|
104
102
|
<div class="layer-list"></div>
|
|
105
103
|
<h4>Sources</h4>
|
|
106
104
|
<div class="file-list"></div>
|
|
@@ -119,9 +117,9 @@
|
|
|
119
117
|
<div class="select-btn btn dialog-btn">Select</div>
|
|
120
118
|
<div class="clip-btn btn dialog-btn">Clip</div>
|
|
121
119
|
<div class="erase-btn btn dialog-btn">Erase</div>
|
|
122
|
-
<div class="
|
|
123
|
-
|
|
124
|
-
<div class="
|
|
120
|
+
<div class="rect-btn btn dialog-btn">Rectangle</div>
|
|
121
|
+
<div class="info-btn btn dialog-btn">Coords</div>
|
|
122
|
+
<!-- <div class="zoom-btn btn dialog-btn">Zoom In</div> -->
|
|
125
123
|
<div class="cancel-btn btn dialog-btn">Cancel</div>
|
|
126
124
|
</div>
|
|
127
125
|
<div class="box-coords selectable"></div>
|
package/www/mapshaper-gui.js
CHANGED
|
@@ -10216,6 +10216,10 @@
|
|
|
10216
10216
|
runCommand('-erase bbox=' + box.getDataCoords().join(','));
|
|
10217
10217
|
});
|
|
10218
10218
|
|
|
10219
|
+
new SimpleButton(popup.findChild('.rect-btn')).on('click', function() {
|
|
10220
|
+
runCommand('-rectangle + bbox=' + box.getDataCoords().join(','));
|
|
10221
|
+
});
|
|
10222
|
+
|
|
10219
10223
|
gui.addMode('box_tool', turnOn, turnOff);
|
|
10220
10224
|
|
|
10221
10225
|
gui.on('interaction_mode_change', function(e) {
|
package/www/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.27";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -13728,6 +13728,28 @@
|
|
|
13728
13728
|
}});
|
|
13729
13729
|
}
|
|
13730
13730
|
|
|
13731
|
+
if (hasPaths || hasPoints) {
|
|
13732
|
+
addGetters(ctx, {
|
|
13733
|
+
// TODO: count hole/s + containing ring as one part
|
|
13734
|
+
partCount: function() {
|
|
13735
|
+
var shp = lyr.shapes[_id];
|
|
13736
|
+
return shp ? shp.length : 0;
|
|
13737
|
+
},
|
|
13738
|
+
isNull: function() {
|
|
13739
|
+
return ctx.partCount === 0;
|
|
13740
|
+
},
|
|
13741
|
+
bounds: function() {
|
|
13742
|
+
return shapeBounds().toArray();
|
|
13743
|
+
},
|
|
13744
|
+
height: function() {
|
|
13745
|
+
return shapeBounds().height();
|
|
13746
|
+
},
|
|
13747
|
+
width: function() {
|
|
13748
|
+
return shapeBounds().width();
|
|
13749
|
+
}
|
|
13750
|
+
});
|
|
13751
|
+
}
|
|
13752
|
+
|
|
13731
13753
|
if (hasPaths) {
|
|
13732
13754
|
|
|
13733
13755
|
ctx.bboxContainsPoint = function(x, y) {
|
|
@@ -13758,25 +13780,6 @@
|
|
|
13758
13780
|
// ctx.containsPoint = function(x, y) {}; // polygon only
|
|
13759
13781
|
// ctx.containedByRectangle(a, b, c, d); // paths and points... how do multipart points work?
|
|
13760
13782
|
|
|
13761
|
-
addGetters(ctx, {
|
|
13762
|
-
// TODO: count hole/s + containing ring as one part
|
|
13763
|
-
partCount: function() {
|
|
13764
|
-
return _ids ? _ids.length : 0;
|
|
13765
|
-
},
|
|
13766
|
-
isNull: function() {
|
|
13767
|
-
return ctx.partCount === 0;
|
|
13768
|
-
},
|
|
13769
|
-
bounds: function() {
|
|
13770
|
-
return shapeBounds().toArray();
|
|
13771
|
-
},
|
|
13772
|
-
height: function() {
|
|
13773
|
-
return shapeBounds().height();
|
|
13774
|
-
},
|
|
13775
|
-
width: function() {
|
|
13776
|
-
return shapeBounds().width();
|
|
13777
|
-
}
|
|
13778
|
-
});
|
|
13779
|
-
|
|
13780
13783
|
if (lyr.geometry_type == 'polyline') {
|
|
13781
13784
|
addGetters(ctx, {
|
|
13782
13785
|
'length': function() {
|
|
@@ -13838,7 +13841,7 @@
|
|
|
13838
13841
|
}
|
|
13839
13842
|
|
|
13840
13843
|
} else if (hasPoints) {
|
|
13841
|
-
|
|
13844
|
+
|
|
13842
13845
|
Object.defineProperty(ctx, 'coordinates',
|
|
13843
13846
|
{set: function(obj) {
|
|
13844
13847
|
if (!obj || utils.isArray(obj)) {
|
|
@@ -13877,8 +13880,13 @@
|
|
|
13877
13880
|
}
|
|
13878
13881
|
|
|
13879
13882
|
function shapeBounds() {
|
|
13880
|
-
if (
|
|
13883
|
+
if (_bounds) return _bounds;
|
|
13884
|
+
if (hasPaths) {
|
|
13881
13885
|
_bounds = arcs.getMultiShapeBounds(_ids);
|
|
13886
|
+
} else if (hasPoints) {
|
|
13887
|
+
_bounds = getPointFeatureBounds(lyr.shapes[_id]);
|
|
13888
|
+
} else {
|
|
13889
|
+
_bounds = new Bounds();
|
|
13882
13890
|
}
|
|
13883
13891
|
return _bounds;
|
|
13884
13892
|
}
|
|
@@ -13886,8 +13894,8 @@
|
|
|
13886
13894
|
return function(id) {
|
|
13887
13895
|
_id = id;
|
|
13888
13896
|
// reset stored values
|
|
13897
|
+
_bounds = null;
|
|
13889
13898
|
if (hasPaths) {
|
|
13890
|
-
_bounds = null;
|
|
13891
13899
|
_centroid = null;
|
|
13892
13900
|
_innerXY = null;
|
|
13893
13901
|
_ids = lyr.shapes[id];
|
|
@@ -14292,9 +14300,9 @@
|
|
|
14292
14300
|
}
|
|
14293
14301
|
|
|
14294
14302
|
function compileCalcExpression(lyr, arcs, exp) {
|
|
14295
|
-
var rowNo = 0, colNo = 0, cols = [];
|
|
14303
|
+
var rowNo = 0, colNo = 0, recId = -1, cols = [];
|
|
14296
14304
|
var ctx1 = { // context for first phase (capturing values for each feature)
|
|
14297
|
-
count: assign,
|
|
14305
|
+
count: assign, // dummy function - first pass does nothing
|
|
14298
14306
|
sum: captureNum,
|
|
14299
14307
|
sums: capture,
|
|
14300
14308
|
average: captureNum,
|
|
@@ -14309,6 +14317,7 @@
|
|
|
14309
14317
|
max: captureNum,
|
|
14310
14318
|
mode: capture,
|
|
14311
14319
|
collect: capture,
|
|
14320
|
+
collectIds: captureId,
|
|
14312
14321
|
first: assignOnce,
|
|
14313
14322
|
every: every,
|
|
14314
14323
|
some: some,
|
|
@@ -14332,6 +14341,7 @@
|
|
|
14332
14341
|
mean: wrap(utils.mean),
|
|
14333
14342
|
mode: wrap(getMode),
|
|
14334
14343
|
collect: wrap(pass),
|
|
14344
|
+
collectIds: wrap(pass),
|
|
14335
14345
|
first: wrap(pass),
|
|
14336
14346
|
every: wrap(pass, false),
|
|
14337
14347
|
some: wrap(pass, false),
|
|
@@ -14418,6 +14428,7 @@
|
|
|
14418
14428
|
|
|
14419
14429
|
function procRecord(i) {
|
|
14420
14430
|
if (i < 0 || i >= len) error("Invalid record index");
|
|
14431
|
+
recId = i;
|
|
14421
14432
|
calc1(i);
|
|
14422
14433
|
rowNo++;
|
|
14423
14434
|
colNo = 0;
|
|
@@ -14426,6 +14437,7 @@
|
|
|
14426
14437
|
function noop() {}
|
|
14427
14438
|
|
|
14428
14439
|
function reset() {
|
|
14440
|
+
recId = -1;
|
|
14429
14441
|
rowNo = 0;
|
|
14430
14442
|
colNo = 0;
|
|
14431
14443
|
cols = [];
|
|
@@ -14467,6 +14479,10 @@
|
|
|
14467
14479
|
}
|
|
14468
14480
|
*/
|
|
14469
14481
|
|
|
14482
|
+
function captureId() {
|
|
14483
|
+
capture(recId);
|
|
14484
|
+
}
|
|
14485
|
+
|
|
14470
14486
|
function capture(val) {
|
|
14471
14487
|
var col;
|
|
14472
14488
|
if (rowNo === 0) {
|
|
@@ -32896,6 +32912,8 @@ ${svg}
|
|
|
32896
32912
|
var colorArg = opts.colors && opts.colors.length == 1 ? opts.colors[0] : null;
|
|
32897
32913
|
var colorScheme;
|
|
32898
32914
|
|
|
32915
|
+
if (method == 'blacki') return [];
|
|
32916
|
+
|
|
32899
32917
|
if (colorArg == 'random') {
|
|
32900
32918
|
if (categorical) {
|
|
32901
32919
|
return getRandomColors(n);
|
|
@@ -32965,7 +32983,7 @@ ${svg}
|
|
|
32965
32983
|
}
|
|
32966
32984
|
|
|
32967
32985
|
var sequential = ['quantile', 'nice', 'equal-interval', 'hybrid', 'breaks'];
|
|
32968
|
-
var all = ['non-adjacent', 'indexed', 'categorical'].concat(sequential);
|
|
32986
|
+
var all = ['non-adjacent', 'indexed', 'categorical', 'blacki'].concat(sequential);
|
|
32969
32987
|
|
|
32970
32988
|
function getClassifyMethod(opts, dataType) {
|
|
32971
32989
|
var method;
|
|
@@ -32999,6 +33017,85 @@ ${svg}
|
|
|
32999
33017
|
return method;
|
|
33000
33018
|
}
|
|
33001
33019
|
|
|
33020
|
+
function getBlackiClassifier(lyr, dataField) {
|
|
33021
|
+
var records = lyr.data.getRecords();
|
|
33022
|
+
// classes are integers, dataIds can be any scalar
|
|
33023
|
+
var dataToClassIndex = {};
|
|
33024
|
+
var classToDataIndex = [];
|
|
33025
|
+
var classCount = 0;
|
|
33026
|
+
|
|
33027
|
+
records.forEach(function(rec, recId) {
|
|
33028
|
+
var dataIds = rec[dataField];
|
|
33029
|
+
var thisClass = -1;
|
|
33030
|
+
var thatClass, dataId;
|
|
33031
|
+
|
|
33032
|
+
if (!Array.isArray(dataIds)) return;
|
|
33033
|
+
|
|
33034
|
+
for (var i=0; i<dataIds.length; i++) {
|
|
33035
|
+
dataId = dataIds[i];
|
|
33036
|
+
thatClass = dataId in dataToClassIndex ? dataToClassIndex[dataId] : -1;
|
|
33037
|
+
if (thatClass == -1) {
|
|
33038
|
+
if (thisClass == -1) {
|
|
33039
|
+
thisClass = classCount++;
|
|
33040
|
+
}
|
|
33041
|
+
if (Array.isArray(classToDataIndex[thisClass])) {
|
|
33042
|
+
if (!classToDataIndex[thisClass].includes(dataId)) {
|
|
33043
|
+
classToDataIndex[thisClass].push(dataId);
|
|
33044
|
+
}
|
|
33045
|
+
} else {
|
|
33046
|
+
classToDataIndex[thisClass] = [dataId];
|
|
33047
|
+
}
|
|
33048
|
+
dataToClassIndex[dataId] = thisClass;
|
|
33049
|
+
|
|
33050
|
+
} else {
|
|
33051
|
+
|
|
33052
|
+
if (thisClass == -1) {
|
|
33053
|
+
thisClass = thatClass;
|
|
33054
|
+
} else if (thisClass > thatClass) {
|
|
33055
|
+
mergeClassIntoClass(thisClass, thatClass);
|
|
33056
|
+
thisClass = thatClass;
|
|
33057
|
+
} else if (thisClass < thatClass) {
|
|
33058
|
+
mergeClassIntoClass(thatClass, thisClass);
|
|
33059
|
+
}
|
|
33060
|
+
}
|
|
33061
|
+
}
|
|
33062
|
+
});
|
|
33063
|
+
|
|
33064
|
+
var remapTable = compressClassIds();
|
|
33065
|
+
var classIds = records.map(function(rec) {
|
|
33066
|
+
var ids = rec[dataField];
|
|
33067
|
+
if (!Array.isArray(ids) || ids.length === 0) return -1;
|
|
33068
|
+
// TODO: assert that ids all belong to the same class
|
|
33069
|
+
if (ids[0] in dataToClassIndex === false) {
|
|
33070
|
+
error('Internal error');
|
|
33071
|
+
}
|
|
33072
|
+
return remapTable[dataToClassIndex[ids[0]]];
|
|
33073
|
+
});
|
|
33074
|
+
|
|
33075
|
+
classToDataIndex = null;
|
|
33076
|
+
dataToClassIndex = null;
|
|
33077
|
+
|
|
33078
|
+
return function(recId) {
|
|
33079
|
+
return classIds[recId];
|
|
33080
|
+
};
|
|
33081
|
+
|
|
33082
|
+
function compressClassIds() {
|
|
33083
|
+
var newId = -1;
|
|
33084
|
+
return classToDataIndex.map(function(d, oldId) {
|
|
33085
|
+
if (d !== null) newId++;
|
|
33086
|
+
return newId;
|
|
33087
|
+
});
|
|
33088
|
+
}
|
|
33089
|
+
|
|
33090
|
+
function mergeClassIntoClass(fromId, toId) {
|
|
33091
|
+
classToDataIndex[fromId].forEach(function(dataId) {
|
|
33092
|
+
dataToClassIndex[dataId] = toId;
|
|
33093
|
+
});
|
|
33094
|
+
classToDataIndex[toId] = utils.uniq(classToDataIndex[toId].concat(classToDataIndex[fromId]));
|
|
33095
|
+
classToDataIndex[fromId] = null;
|
|
33096
|
+
}
|
|
33097
|
+
}
|
|
33098
|
+
|
|
33002
33099
|
cmd.classify = function(lyr, dataset, optsArg) {
|
|
33003
33100
|
if (!lyr.data) {
|
|
33004
33101
|
initDataTable(lyr);
|
|
@@ -33061,6 +33158,8 @@ ${svg}
|
|
|
33061
33158
|
stop('Invalid number of classes:', opts.classes, '(expected a value greater than 1)');
|
|
33062
33159
|
}
|
|
33063
33160
|
numClasses = opts.classes;
|
|
33161
|
+
} else if (method == 'blacki') {
|
|
33162
|
+
numClasses = 999; // dummy value
|
|
33064
33163
|
} else if (method == 'indexed' && dataField) {
|
|
33065
33164
|
numClasses = getIndexedClassCount(records, dataField);
|
|
33066
33165
|
} else if (opts.breaks) {
|
|
@@ -33098,6 +33197,8 @@ ${svg}
|
|
|
33098
33197
|
if (fieldType === null) {
|
|
33099
33198
|
// no valid data -- always return null value
|
|
33100
33199
|
classifyByRecordId = function() {return nullValue;};
|
|
33200
|
+
} else if (method == 'blacki') {
|
|
33201
|
+
classifyByRecordId = getBlackiClassifier(lyr, dataField);
|
|
33101
33202
|
} else if (method == 'non-adjacent') {
|
|
33102
33203
|
classifyByRecordId = getNonAdjacentClassifier(lyr, dataset, values);
|
|
33103
33204
|
} else if (method == 'indexed') {
|
package/www/modules.js
CHANGED
|
@@ -10047,6 +10047,9 @@ function get_geod_defn(P) {
|
|
|
10047
10047
|
if ('datum' in P.params) {
|
|
10048
10048
|
got_datum = true;
|
|
10049
10049
|
defn += get_param(P, 'datum');
|
|
10050
|
+
} else if ('R' in P.params) {
|
|
10051
|
+
// moving R above other params, to match sequence in pj_ell_set.js
|
|
10052
|
+
defn += get_param(P, 'R');
|
|
10050
10053
|
} else if ('ellps' in P.params) {
|
|
10051
10054
|
defn += get_param(P, 'ellps');
|
|
10052
10055
|
} else if ('a' in P.params) {
|
|
@@ -10067,7 +10070,7 @@ function get_geod_defn(P) {
|
|
|
10067
10070
|
defn += get_param(P, 'towgs84');
|
|
10068
10071
|
defn += get_param(P, 'nadgrids');
|
|
10069
10072
|
}
|
|
10070
|
-
defn += get_param(P, 'R');
|
|
10073
|
+
// defn += get_param(P, 'R'); // moved to above ellps
|
|
10071
10074
|
defn += get_param(P, 'R_A');
|
|
10072
10075
|
defn += get_param(P, 'R_V');
|
|
10073
10076
|
defn += get_param(P, 'R_a');
|