mapshaper 0.6.74 → 0.6.75
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 +118 -77
- package/package.json +1 -1
- package/www/mapshaper-gui.js +209 -107
- package/www/mapshaper.js +118 -77
- package/www/page.css +14 -0
package/mapshaper.js
CHANGED
|
@@ -749,7 +749,7 @@
|
|
|
749
749
|
}
|
|
750
750
|
|
|
751
751
|
function getGenericComparator(asc) {
|
|
752
|
-
asc = asc !== false;
|
|
752
|
+
asc = asc !== false && asc != 'descending'; // ascending is the default
|
|
753
753
|
return function(a, b) {
|
|
754
754
|
var retn = 0;
|
|
755
755
|
if (b == null) {
|
|
@@ -1362,13 +1362,13 @@
|
|
|
1362
1362
|
}
|
|
1363
1363
|
|
|
1364
1364
|
// Format an array of (preferably short) strings in columns for console logging.
|
|
1365
|
-
function formatStringsAsGrid(arr) {
|
|
1365
|
+
function formatStringsAsGrid(arr, width) {
|
|
1366
1366
|
// TODO: variable column width
|
|
1367
1367
|
var longest = arr.reduce(function(len, str) {
|
|
1368
1368
|
return Math.max(len, str.length);
|
|
1369
1369
|
}, 0),
|
|
1370
1370
|
colWidth = longest + 2,
|
|
1371
|
-
perLine = Math.floor(80 / colWidth) || 1;
|
|
1371
|
+
perLine = Math.floor((width || 80) / colWidth) || 1;
|
|
1372
1372
|
return arr.reduce(function(memo, name, i) {
|
|
1373
1373
|
var col = i % perLine;
|
|
1374
1374
|
if (i > 0 && col === 0) memo += '\n';
|
|
@@ -3720,8 +3720,6 @@
|
|
|
3720
3720
|
}
|
|
3721
3721
|
var require$1 = f;
|
|
3722
3722
|
|
|
3723
|
-
// import { createRequire } from "module";
|
|
3724
|
-
|
|
3725
3723
|
var iconv = require$1('iconv-lite');
|
|
3726
3724
|
|
|
3727
3725
|
// import iconv from 'iconv-lite';
|
|
@@ -4289,6 +4287,10 @@
|
|
|
4289
4287
|
return layerHasPaths(lyr) || layerHasPoints(lyr);
|
|
4290
4288
|
}
|
|
4291
4289
|
|
|
4290
|
+
function layerIsGeometric(lyr) {
|
|
4291
|
+
return !!lyr.geometry_type; // only checks type, includes empty layers
|
|
4292
|
+
}
|
|
4293
|
+
|
|
4292
4294
|
function layerHasPaths(lyr) {
|
|
4293
4295
|
return (lyr.geometry_type == 'polygon' || lyr.geometry_type == 'polyline') &&
|
|
4294
4296
|
layerHasNonNullShapes(lyr);
|
|
@@ -4552,6 +4554,7 @@
|
|
|
4552
4554
|
getLayerDataTable: getLayerDataTable,
|
|
4553
4555
|
layerHasNonNullData: layerHasNonNullData,
|
|
4554
4556
|
layerHasGeometry: layerHasGeometry,
|
|
4557
|
+
layerIsGeometric: layerIsGeometric,
|
|
4555
4558
|
layerHasPaths: layerHasPaths,
|
|
4556
4559
|
layerHasPoints: layerHasPoints,
|
|
4557
4560
|
layerIsRectangle: layerIsRectangle,
|
|
@@ -5493,6 +5496,8 @@
|
|
|
5493
5496
|
initLegacyArcs(arguments[0]); // want to phase this out
|
|
5494
5497
|
} else if (arguments.length == 3) {
|
|
5495
5498
|
initXYData.apply(this, arguments);
|
|
5499
|
+
} else if (arguments.length === 0) {
|
|
5500
|
+
initLegacyArcs([]); // empty collection
|
|
5496
5501
|
} else {
|
|
5497
5502
|
error("ArcCollection() Invalid arguments");
|
|
5498
5503
|
}
|
|
@@ -13184,7 +13189,6 @@
|
|
|
13184
13189
|
return findVertexIds(p2.x, p2.y, arcs);
|
|
13185
13190
|
}
|
|
13186
13191
|
|
|
13187
|
-
|
|
13188
13192
|
function snapVerticesToPoint(ids, p, arcs, final) {
|
|
13189
13193
|
var data = arcs.getVertexData();
|
|
13190
13194
|
ids.forEach(function(idx) {
|
|
@@ -23046,28 +23050,30 @@ ${svg}
|
|
|
23046
23050
|
// @samples Array of buffers containing sample text fields
|
|
23047
23051
|
// TODO: Improve reliability and number of detectable encodings.
|
|
23048
23052
|
function detectEncoding(samples) {
|
|
23049
|
-
|
|
23050
|
-
var
|
|
23051
|
-
|
|
23052
|
-
|
|
23053
|
-
encoding
|
|
23054
|
-
|
|
23055
|
-
|
|
23056
|
-
|
|
23057
|
-
|
|
23058
|
-
}
|
|
23059
|
-
|
|
23060
|
-
|
|
23061
|
-
|
|
23062
|
-
|
|
23063
|
-
|
|
23053
|
+
// score each encoding as 2 (high confidence) 1 (low confidence) or 0 (fail)
|
|
23054
|
+
var candidates = [{
|
|
23055
|
+
// latin1 is the original Shapefile encoding, using as an imperfect fallback
|
|
23056
|
+
// (sorts to the top only if all other encodings score 0)
|
|
23057
|
+
encoding: 'latin1',
|
|
23058
|
+
confidence: 0
|
|
23059
|
+
},{
|
|
23060
|
+
encoding: 'win1252',
|
|
23061
|
+
confidence: looksLikeWin1252(samples)
|
|
23062
|
+
}, {
|
|
23063
|
+
encoding: 'utf8',
|
|
23064
|
+
confidence: looksLikeUtf8(samples)
|
|
23065
|
+
}, {
|
|
23066
|
+
encoding: 'gb18030',
|
|
23067
|
+
confidence: looksLikeGB18030(samples)
|
|
23068
|
+
}];
|
|
23069
|
+
utils.sortOn(candidates, 'confidence', 'descending');
|
|
23070
|
+
return candidates[0];
|
|
23064
23071
|
}
|
|
23065
23072
|
|
|
23066
|
-
// Convert an array of text samples to a single string using a given encoding
|
|
23067
23073
|
function decodeSamples(enc, samples) {
|
|
23068
23074
|
return samples.map(function(buf) {
|
|
23069
23075
|
return decodeString(buf, enc).trim();
|
|
23070
|
-
})
|
|
23076
|
+
});
|
|
23071
23077
|
}
|
|
23072
23078
|
|
|
23073
23079
|
// Win1252 is the same as Latin1, except it replaces a block of control
|
|
@@ -23082,45 +23088,67 @@ ${svg}
|
|
|
23082
23088
|
//
|
|
23083
23089
|
function looksLikeWin1252(samples) {
|
|
23084
23090
|
//common l.c. ascii chars
|
|
23085
|
-
var
|
|
23086
|
-
// common extended + NBS (found in the wild)
|
|
23087
|
-
|
|
23088
|
-
str = decodeSamples('win1252', samples),
|
|
23089
|
-
|
|
23090
|
-
|
|
23091
|
-
|
|
23092
|
-
|
|
23091
|
+
var commonAscii = 'abcdefghijklmnopqrstuvwxyz0123456789.()\'"?+-\n,:;/|_$% ',
|
|
23092
|
+
// more common extended chars + NBS (found in the wild)
|
|
23093
|
+
moreChars = 'ßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿ°–±’‘' + '\xA0',
|
|
23094
|
+
str = decodeSamples('win1252', samples).join(''),
|
|
23095
|
+
commonAsciiPct = calcCharPct(str, commonAscii),
|
|
23096
|
+
expandedPct = calcCharPct(str, moreChars) + commonAsciiPct;
|
|
23097
|
+
var high = expandedPct > 0.98 && commonAsciiPct >= 0.8;
|
|
23098
|
+
var low = expandedPct > 0.97 && commonAsciiPct >= 0.6;
|
|
23099
|
+
return getScore(high, low);
|
|
23093
23100
|
}
|
|
23094
23101
|
|
|
23095
|
-
// Reject string if it contains the "replacement character" after decoding to UTF-8
|
|
23096
23102
|
function looksLikeUtf8(samples) {
|
|
23097
|
-
//
|
|
23098
|
-
//
|
|
23099
|
-
|
|
23100
|
-
var
|
|
23101
|
-
var
|
|
23102
|
-
var
|
|
23103
|
-
return
|
|
23104
|
-
}
|
|
23105
|
-
|
|
23106
|
-
|
|
23107
|
-
|
|
23108
|
-
|
|
23109
|
-
|
|
23110
|
-
|
|
23111
|
-
|
|
23112
|
-
|
|
23113
|
-
|
|
23114
|
-
|
|
23115
|
-
|
|
23116
|
-
|
|
23117
|
-
|
|
23118
|
-
|
|
23119
|
-
|
|
23103
|
+
// Reject string if it contains the "replacement character" after decoding
|
|
23104
|
+
// as utf-8
|
|
23105
|
+
var str = decodeSamples('utf8', samples).join('');
|
|
23106
|
+
var invalidPct = getInvalidPct(str);
|
|
23107
|
+
var high = invalidPct == 0;
|
|
23108
|
+
var low = invalidPct < 0.03;
|
|
23109
|
+
return getScore(high, low);
|
|
23110
|
+
}
|
|
23111
|
+
|
|
23112
|
+
function looksLikeGB18030(samples) {
|
|
23113
|
+
// from Jun Da's frequency table
|
|
23114
|
+
var commonHanZi = '的一了是不我他在人有这来个说上你们到地大着子那就也时道中出得为里下她要么去可以过和看之然后会自没小好生天而起对能还事想都心只家面样把国多又于头年手发如什开前当所无知老但见长已军从方声儿回意作话两点现很成身情十用些走经同进动己三行种向日明女正问此学太打间分因给本眼定二气力被门真法外听实其高先几笑再主将山战才口文最部第它西与全白者便相住公使东等边信像斯机光次感神却死理名重四做别叫王并水月果何位怎马常觉海张少处亲安特美呢色原直望命由候吧让应尔难关许车平师民夫书新接吗路利世比放活快总立队更花爱清五内金带工风克任至指往入空德吃表连解教思飞物电受今完林干代告兵加认通找远非性脸体轻记目令变似反南场跟必石拉士报李火且满该孩字红象即结言员房件万条提写或坐北早失离步陈乎请转近切黑深城办倒各父传音站官半男击合阿英决怕杀未形及算青黄落刚百论谁突交团度义罗始强紧敌八母钱极片化流管惊每题晚虽政兴答司妈夜越啊奇达谈武友数领朝保服曾拿则哪格尽根急语容喜求衣留双影刻制随冷九苦量备布照周故准客船江系姐争功怪星断句龙竟视界讲取古六静底精七河久绝阳识哈台确息期整伤忙娘终剑送计愿欢微您沉装敢云脚消若复收千木乐毛华集树弟皇响希诉号巴穿线汉攻呀警派刘酒雷停史阵错建足显丽另包势破亮首志观病热跑业治田冲运约暗待共院仍区害元哥围屋胡产室调类细议爷注易务众帝市摇乱密姑斗除式示睛楼造朋社持慢般皮京况块忽脑校甚查土怀福单联赶背统喝疑支血饭灵够章群威举兰游器察嘴痛铁掉宝历改推枪念参术帮党据品须居称旁退梦科岁低严引吉睡爸呼追局露维苏证村挥独节谢香亚波角案读图左掌假跳究楚余鬼钟座礼展玉肯既止守广考恩异料段尼画续米草胜存唐医程弹烟商顾招宗堂野初府激雨尚渐诗顿伯孙际沙雪板闻导致护春态基设耳简婚幸味右买演权卡继依恶庄炮亦虎州刀球需兄闪笔否烈玩啦逃排仅弄具散默景顶郑洋丝卫速侠差贵君习妇助恐救湖莫窗险顺封佛委旧印伙妹副宫洞永罪松责组防艺营班试鲁宋靠索灯介翻喊纪秘妻纸银略充戏担某杨射魔遇鱼陆级坏忘乡鲜哭费抓叶醒族纳床咱桌境列午振抱专毫店街怒托剧置秋藏赵划普岛较承脱革忍伸份免齐抗猛园临犯食架选歌按败良隐养属洛朱狂修坚压寻旅谋温探资端投泪阴换药麻施丈冰雄著绿职负短模荣遗农叹川毒吴蒋卖范禁杂富秀县祖梅谷凡刺登蓝奶缓姓牛价规篇劳质婆仙馆摆舞层狗占墙善熟验肉臣状呆圣懂袋唱值迷替归巨讨毕批镇吸森拍灭握伊杰勒卷偷奔省谓危付伦休厅预迎罢恨博亡欲悲宣标闹岸';
|
|
23115
|
+
var str = decodeSamples('gb18030', samples).join('');
|
|
23116
|
+
// Almost all the common Unicode Hanzi are in this range (along with many more uncommon ones)
|
|
23117
|
+
var chineseStr = str.replace(/[^\u4e00-\u9fa5]/g, '');
|
|
23118
|
+
var chinesePct = chineseStr.length / str.length;
|
|
23119
|
+
var commonAsciiStr = extractCommonAsciiChars(str);
|
|
23120
|
+
var commonAsciiPct = commonAsciiStr.length / str.length;
|
|
23121
|
+
// Some encodings get converted almost completely into valid (but mostly
|
|
23122
|
+
// uncommon) Chinese characters by the gb18030 converter.
|
|
23123
|
+
// To guard against this, we're requiring that a certain percentage of
|
|
23124
|
+
// characters be on a list of the most common characters.
|
|
23125
|
+
var commonHanZiPct = calcCharPct(chineseStr, commonHanZi);
|
|
23126
|
+
// check for non-convertible characters
|
|
23127
|
+
var invalidPct = getInvalidPct(str);
|
|
23128
|
+
var high = chinesePct > 0.5 && (chinesePct + commonAsciiPct) > 0.9 &&
|
|
23129
|
+
invalidPct === 0 && commonHanZiPct > 0.25;
|
|
23130
|
+
var low = chinesePct > 0.3 && (chinesePct + commonAsciiPct) > 0.8 &&
|
|
23131
|
+
commonHanZiPct > 0.15;
|
|
23132
|
+
return getScore(high, low);
|
|
23133
|
+
}
|
|
23134
|
+
|
|
23135
|
+
function getScore(high, low) {
|
|
23136
|
+
return high && 2 || low && 1 || 0;
|
|
23137
|
+
}
|
|
23138
|
+
|
|
23139
|
+
function getInvalidPct(str) {
|
|
23140
|
+
// count occurences of the "replacement" character
|
|
23141
|
+
var invalidCount = (str.match(/\ufffd/g) || []).length;
|
|
23142
|
+
return invalidCount / str.length;
|
|
23143
|
+
}
|
|
23144
|
+
|
|
23145
|
+
function extractCommonAsciiChars(str) {
|
|
23146
|
+
return str.replace(/[^a-zA-Z0-9.()'"?+\n,:;/|_$% -]/g, '');
|
|
23147
|
+
}
|
|
23120
23148
|
|
|
23121
23149
|
// Calc percentage of chars in a string that are present in a second string
|
|
23122
23150
|
// @chars String of chars to look for in @str
|
|
23123
|
-
function
|
|
23151
|
+
function calcCharPct(str, chars) {
|
|
23124
23152
|
var index = {},
|
|
23125
23153
|
count = 0;
|
|
23126
23154
|
str = str.toLowerCase();
|
|
@@ -23130,9 +23158,16 @@ ${svg}
|
|
|
23130
23158
|
for (i=0, n=str.length; i<n; i++) {
|
|
23131
23159
|
count += index[str[i]] || 0;
|
|
23132
23160
|
}
|
|
23133
|
-
return count / str.length;
|
|
23161
|
+
return count / str.length || 0;
|
|
23134
23162
|
}
|
|
23135
23163
|
|
|
23164
|
+
var EncodingDetection = /*#__PURE__*/Object.freeze({
|
|
23165
|
+
__proto__: null,
|
|
23166
|
+
detectEncodingFromBOM: detectEncodingFromBOM,
|
|
23167
|
+
detectEncoding: detectEncoding,
|
|
23168
|
+
decodeSamples: decodeSamples
|
|
23169
|
+
});
|
|
23170
|
+
|
|
23136
23171
|
// Convert a string containing delimited text data into a dataset object
|
|
23137
23172
|
function importDelim(str, opts) {
|
|
23138
23173
|
return importDelim2({content: str}, opts);
|
|
@@ -26644,25 +26679,19 @@ ${svg}
|
|
|
26644
26679
|
var info = detectEncoding(samples);
|
|
26645
26680
|
encoding = info.encoding;
|
|
26646
26681
|
if (info.confidence < 2) {
|
|
26647
|
-
msg = 'Warning: Unable to auto-detect the text encoding
|
|
26682
|
+
msg = 'Warning: Unable to auto-detect the DBF file text encoding with high confidence.';
|
|
26648
26683
|
msg += '\n\nDefaulting to: ' + encoding + (encoding in encodingNames ? ' (' + encodingNames[encoding] + ')' : '');
|
|
26649
|
-
msg += '\n\nSample of how non-ascii text was imported
|
|
26650
|
-
|
|
26651
|
-
|
|
26684
|
+
msg += '\n\nSample of how non-ascii text was imported:\n';
|
|
26685
|
+
if (runningInBrowser()) {
|
|
26686
|
+
msg += '<pre>' + formatStringsAsGrid(decodeSamples(encoding, samples), 50) + '</pre>';
|
|
26687
|
+
} else {
|
|
26688
|
+
msg += formatStringsAsGrid(decodeSamples(encoding, samples));
|
|
26689
|
+
}
|
|
26652
26690
|
msg += '\n\n' + ENCODING_PROMPT + '\n';
|
|
26653
26691
|
message(msg);
|
|
26654
26692
|
}
|
|
26655
26693
|
}
|
|
26656
26694
|
|
|
26657
|
-
// Show a sample of decoded text if non-ascii-range text has been found
|
|
26658
|
-
// if (encoding && samples.length > 0) {
|
|
26659
|
-
// msg = "Detected DBF text encoding: " + encoding + (encoding in encodingNames ? " (" + encodingNames[encoding] + ")" : "");
|
|
26660
|
-
// message(msg);
|
|
26661
|
-
// msg = decodeSamples(encoding, samples);
|
|
26662
|
-
// msg = formatStringsAsGrid(msg.split('\n'));
|
|
26663
|
-
// msg = "\nSample text containing non-ascii characters:" + (msg.length > 60 ? '\n' : '') + msg;
|
|
26664
|
-
// verbose(msg);
|
|
26665
|
-
// }
|
|
26666
26695
|
return encoding;
|
|
26667
26696
|
}
|
|
26668
26697
|
|
|
@@ -37783,7 +37812,7 @@ ${svg}
|
|
|
37783
37812
|
filteredLyr = copyLayer(filteredLyr);
|
|
37784
37813
|
}
|
|
37785
37814
|
|
|
37786
|
-
if (opts.verbose !== false) {
|
|
37815
|
+
if (opts.verbose !== false && !opts.quiet) {
|
|
37787
37816
|
message(utils.format('Retained %,d of %,d features', getFeatureCount(filteredLyr), n));
|
|
37788
37817
|
}
|
|
37789
37818
|
|
|
@@ -37833,14 +37862,15 @@ ${svg}
|
|
|
37833
37862
|
}
|
|
37834
37863
|
|
|
37835
37864
|
function combineFilters(a, b) {
|
|
37836
|
-
return
|
|
37865
|
+
return a && b ? function(id) {
|
|
37837
37866
|
return a(id) && b(id);
|
|
37838
|
-
}
|
|
37867
|
+
} : (a || b);
|
|
37839
37868
|
}
|
|
37840
37869
|
|
|
37841
|
-
cmd.evaluateEachFeature = function(lyr, dataset,
|
|
37870
|
+
cmd.evaluateEachFeature = function(lyr, dataset, expArg, opts) {
|
|
37842
37871
|
var n = getFeatureCount(lyr),
|
|
37843
37872
|
arcs = dataset.arcs,
|
|
37873
|
+
exp = expArg || '',
|
|
37844
37874
|
compiled, filter;
|
|
37845
37875
|
|
|
37846
37876
|
var exprOpts = {
|
|
@@ -42377,6 +42407,9 @@ ${svg}
|
|
|
42377
42407
|
candidates.forEach(function(candId) {
|
|
42378
42408
|
var hit;
|
|
42379
42409
|
if (candId == absId) return; // ignore self-intersections
|
|
42410
|
+
if (absArcId(candId) >= arcs.size()) {
|
|
42411
|
+
return;
|
|
42412
|
+
}
|
|
42380
42413
|
hit = geom.getPointToPathInfo(endpoint.point[0], endpoint.point[1], [candId], arcs);
|
|
42381
42414
|
if (hit && hit.distance <= maxGapLen && (!target || hit.distance < target.distance)) {
|
|
42382
42415
|
target = hit;
|
|
@@ -42462,7 +42495,9 @@ ${svg}
|
|
|
42462
42495
|
// if (opts.gap_tolerance) {
|
|
42463
42496
|
//opts = utils.defaults({snap_interval: opts.gap_tolerance * 0.1}, opts);
|
|
42464
42497
|
// }
|
|
42465
|
-
|
|
42498
|
+
if (!opts.no_cuts) {
|
|
42499
|
+
addIntersectionCuts(dataset, opts);
|
|
42500
|
+
}
|
|
42466
42501
|
return layers.map(function(lyr) {
|
|
42467
42502
|
if (lyr.geometry_type != 'polyline') stop("Expected a polyline layer");
|
|
42468
42503
|
if (opts.from_rings) {
|
|
@@ -42492,7 +42527,12 @@ ${svg}
|
|
|
42492
42527
|
}
|
|
42493
42528
|
|
|
42494
42529
|
function createPolygonLayer(lyr, dataset, opts) {
|
|
42495
|
-
var nodes
|
|
42530
|
+
var nodes;
|
|
42531
|
+
if (opts.no_cuts) {
|
|
42532
|
+
nodes = new NodeCollection(dataset.arcs);
|
|
42533
|
+
} else {
|
|
42534
|
+
nodes = closeUndershoots(lyr, dataset, opts);
|
|
42535
|
+
}
|
|
42496
42536
|
// ignore arcs that don't belong to this layer
|
|
42497
42537
|
nodes.setArcFilter(getArcPresenceTest(lyr.shapes, nodes.arcs));
|
|
42498
42538
|
var data = buildPolygonMosaic(nodes);
|
|
@@ -45485,7 +45525,7 @@ ${svg}
|
|
|
45485
45525
|
});
|
|
45486
45526
|
}
|
|
45487
45527
|
|
|
45488
|
-
var version = "0.6.
|
|
45528
|
+
var version = "0.6.75";
|
|
45489
45529
|
|
|
45490
45530
|
// Parse command line args into commands and run them
|
|
45491
45531
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
|
@@ -46162,6 +46202,7 @@ ${svg}
|
|
|
46162
46202
|
DelimExport,
|
|
46163
46203
|
DelimImport,
|
|
46164
46204
|
DelimReader,
|
|
46205
|
+
EncodingDetection,
|
|
46165
46206
|
Encodings,
|
|
46166
46207
|
Explode,
|
|
46167
46208
|
Export,
|
package/package.json
CHANGED
package/www/mapshaper-gui.js
CHANGED
|
@@ -1144,10 +1144,18 @@
|
|
|
1144
1144
|
return self;
|
|
1145
1145
|
};
|
|
1146
1146
|
|
|
1147
|
-
self.close = function() {
|
|
1148
|
-
|
|
1147
|
+
self.close = function(action) {
|
|
1148
|
+
var ms = 0;
|
|
1149
|
+
var _el = el;
|
|
1150
|
+
if (action == 'fade' && _el) {
|
|
1151
|
+
ms = 1000;
|
|
1152
|
+
_el.addClass('fade-out');
|
|
1153
|
+
}
|
|
1149
1154
|
if (_close) _close();
|
|
1150
1155
|
el = _cancel = _close = null;
|
|
1156
|
+
setTimeout(function() {
|
|
1157
|
+
if (_el) _el.remove();
|
|
1158
|
+
}, ms);
|
|
1151
1159
|
};
|
|
1152
1160
|
return self;
|
|
1153
1161
|
}
|
|
@@ -1753,6 +1761,9 @@
|
|
|
1753
1761
|
}],
|
|
1754
1762
|
info: {}
|
|
1755
1763
|
};
|
|
1764
|
+
if (type == 'polygon' || type == 'point') {
|
|
1765
|
+
dataset.arcs = new internal.ArcCollection();
|
|
1766
|
+
}
|
|
1756
1767
|
if (crsInfo) {
|
|
1757
1768
|
internal.setDatasetCrsInfo(dataset, crsInfo);
|
|
1758
1769
|
}
|
|
@@ -2426,7 +2437,10 @@
|
|
|
2426
2437
|
}
|
|
2427
2438
|
|
|
2428
2439
|
function error() {
|
|
2429
|
-
|
|
2440
|
+
var msg = GUI.formatMessageArgs(arguments);
|
|
2441
|
+
console.error(msg);
|
|
2442
|
+
gui.alert('An unkown error occured');
|
|
2443
|
+
throw new Error(msg);
|
|
2430
2444
|
}
|
|
2431
2445
|
|
|
2432
2446
|
function message() {
|
|
@@ -2807,7 +2821,7 @@
|
|
|
2807
2821
|
strokeWidth: 1.2,
|
|
2808
2822
|
vertices: true,
|
|
2809
2823
|
vertex_overlay_color: o.hit_type == 'vertex' ? violet : black,
|
|
2810
|
-
vertex_overlay_scale: o.hit_type == 'vertex' ? 2.
|
|
2824
|
+
vertex_overlay_scale: o.hit_type == 'vertex' ? 2.5 : 2,
|
|
2811
2825
|
vertex_overlay: o.hit_coordinates || null,
|
|
2812
2826
|
selected_points: o.selected_points || null,
|
|
2813
2827
|
fillColor: null
|
|
@@ -3025,6 +3039,11 @@
|
|
|
3025
3039
|
return internal.getUnfilteredArcCoords(arcId, target.source.dataset.arcs);
|
|
3026
3040
|
}
|
|
3027
3041
|
|
|
3042
|
+
function getLastVertexCoords(target) {
|
|
3043
|
+
var arcs = target.source.dataset.arcs;
|
|
3044
|
+
return internal.getVertexCoords(arcs.getPointCount() - 1, arcs);
|
|
3045
|
+
}
|
|
3046
|
+
|
|
3028
3047
|
function getLastArcLength(target) {
|
|
3029
3048
|
var arcId = target.source.dataset.arcs.size() - 1;
|
|
3030
3049
|
return internal.getUnfilteredArcLength(arcId, target.source.dataset.arcs);
|
|
@@ -4920,13 +4939,10 @@
|
|
|
4920
4939
|
return internal.getLayerSourceFile(lyr, dataset);
|
|
4921
4940
|
}
|
|
4922
4941
|
|
|
4923
|
-
|
|
4924
4942
|
function isPinnable(lyr) {
|
|
4925
|
-
return internal.
|
|
4943
|
+
return internal.layerIsGeometric(lyr) || internal.layerHasFurniture(lyr);
|
|
4926
4944
|
}
|
|
4927
4945
|
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
4946
|
function rowHTML(c1, c2, cname) {
|
|
4931
4947
|
return utils$1.format('<div class="row%s"><div class="col1">%s</div>' +
|
|
4932
4948
|
'<div class="col2">%s</div></div>', cname ? ' ' + cname : '', c1, c2);
|
|
@@ -5205,10 +5221,10 @@
|
|
|
5205
5221
|
|
|
5206
5222
|
gui.on('path_extend', function(e) {
|
|
5207
5223
|
var redo = function() {
|
|
5208
|
-
gui.dispatchEvent('redo_path_extend', {p: e.p});
|
|
5224
|
+
gui.dispatchEvent('redo_path_extend', {p: e.p, shapes: e.shapes2});
|
|
5209
5225
|
};
|
|
5210
5226
|
var undo = function() {
|
|
5211
|
-
gui.dispatchEvent('undo_path_extend');
|
|
5227
|
+
gui.dispatchEvent('undo_path_extend', {shapes: e.shapes1});
|
|
5212
5228
|
};
|
|
5213
5229
|
addHistoryState(undo, redo);
|
|
5214
5230
|
});
|
|
@@ -5543,22 +5559,23 @@
|
|
|
5543
5559
|
if (!o || !o.layer) {
|
|
5544
5560
|
return menus.standard; // TODO: more sensible handling of missing layer
|
|
5545
5561
|
}
|
|
5546
|
-
if (!
|
|
5562
|
+
if (!o.layer.geometry_type) {
|
|
5547
5563
|
return menus.table;
|
|
5548
5564
|
}
|
|
5549
5565
|
if (internal.layerHasLabels(o.layer)) {
|
|
5550
5566
|
return menus.labels;
|
|
5551
5567
|
}
|
|
5552
|
-
if (
|
|
5568
|
+
if (o.layer.geometry_type == 'point') {
|
|
5553
5569
|
return menus.points;
|
|
5554
5570
|
}
|
|
5555
|
-
if (
|
|
5571
|
+
if (o.layer.geometry_type == 'polyline') {
|
|
5556
5572
|
return menus.lines;
|
|
5557
5573
|
}
|
|
5558
|
-
if (
|
|
5574
|
+
if (o.layer.geometry_type == 'polygon') {
|
|
5559
5575
|
return internal.layerOnlyHasRectangles(o.layer, o.dataset.arcs) ?
|
|
5560
5576
|
menus.rectangles : menus.polygons;
|
|
5561
5577
|
}
|
|
5578
|
+
|
|
5562
5579
|
return menus.standard;
|
|
5563
5580
|
}
|
|
5564
5581
|
|
|
@@ -5908,13 +5925,13 @@
|
|
|
5908
5925
|
}
|
|
5909
5926
|
|
|
5910
5927
|
// Format an array of (preferably short) strings in columns for console logging.
|
|
5911
|
-
function formatStringsAsGrid(arr) {
|
|
5928
|
+
function formatStringsAsGrid(arr, width) {
|
|
5912
5929
|
// TODO: variable column width
|
|
5913
5930
|
var longest = arr.reduce(function(len, str) {
|
|
5914
5931
|
return Math.max(len, str.length);
|
|
5915
5932
|
}, 0),
|
|
5916
5933
|
colWidth = longest + 2,
|
|
5917
|
-
perLine = Math.floor(80 / colWidth) || 1;
|
|
5934
|
+
perLine = Math.floor((width || 80) / colWidth) || 1;
|
|
5918
5935
|
return arr.reduce(function(memo, name, i) {
|
|
5919
5936
|
var col = i % perLine;
|
|
5920
5937
|
if (i > 0 && col === 0) memo += '\n';
|
|
@@ -6575,7 +6592,7 @@
|
|
|
6575
6592
|
}
|
|
6576
6593
|
|
|
6577
6594
|
function getGenericComparator(asc) {
|
|
6578
|
-
asc = asc !== false;
|
|
6595
|
+
asc = asc !== false && asc != 'descending'; // ascending is the default
|
|
6579
6596
|
return function(a, b) {
|
|
6580
6597
|
var retn = 0;
|
|
6581
6598
|
if (b == null) {
|
|
@@ -9710,12 +9727,14 @@
|
|
|
9710
9727
|
var prevClickEvent;
|
|
9711
9728
|
var prevHoverEvent;
|
|
9712
9729
|
var initialArcCount = -1;
|
|
9730
|
+
var initialShapeCount = -1;
|
|
9713
9731
|
var drawingId = -1; // feature id of path being drawn
|
|
9732
|
+
var sessionCount = 0;
|
|
9714
9733
|
var alert;
|
|
9715
9734
|
var _dragging = false;
|
|
9716
9735
|
|
|
9717
9736
|
function active() {
|
|
9718
|
-
return
|
|
9737
|
+
return initialArcCount >= 0;
|
|
9719
9738
|
}
|
|
9720
9739
|
|
|
9721
9740
|
function dragging() {
|
|
@@ -9753,7 +9772,7 @@
|
|
|
9753
9772
|
appendNewPath(target, e.p1, e.p2);
|
|
9754
9773
|
deleteLastVertex(target); // second vertex is a placeholder
|
|
9755
9774
|
gui.undo.redo(); // add next vertex in the path
|
|
9756
|
-
|
|
9775
|
+
fullRedraw();
|
|
9757
9776
|
});
|
|
9758
9777
|
|
|
9759
9778
|
gui.on('undo_path_add', function(e) {
|
|
@@ -9769,8 +9788,28 @@
|
|
|
9769
9788
|
} else {
|
|
9770
9789
|
appendVertex$1(target, e.p);
|
|
9771
9790
|
}
|
|
9791
|
+
if (e.shapes) {
|
|
9792
|
+
replaceShapes(e.shapes);
|
|
9793
|
+
}
|
|
9772
9794
|
});
|
|
9773
9795
|
|
|
9796
|
+
function replaceShapes(shapes) {
|
|
9797
|
+
var target = hit.getHitTarget();
|
|
9798
|
+
var records = target.layer.data?.getRecords();
|
|
9799
|
+
var prevLen = target.layer.shapes.length;
|
|
9800
|
+
var newLen = initialShapeCount + shapes.length;
|
|
9801
|
+
var recordCount = records?.length || 0;
|
|
9802
|
+
target.layer.shapes = target.layer.shapes.slice(0, initialShapeCount).concat(shapes);
|
|
9803
|
+
while (records && records.length > newLen) {
|
|
9804
|
+
records.pop();
|
|
9805
|
+
}
|
|
9806
|
+
while (records && records.length < newLen) {
|
|
9807
|
+
appendNewDataRecord(target.layer);
|
|
9808
|
+
}
|
|
9809
|
+
}
|
|
9810
|
+
|
|
9811
|
+
|
|
9812
|
+
|
|
9774
9813
|
gui.on('undo_path_extend', function(e) {
|
|
9775
9814
|
var target = hit.getHitTarget();
|
|
9776
9815
|
if (drawing() && prevHoverEvent) {
|
|
@@ -9782,75 +9821,70 @@
|
|
|
9782
9821
|
if (getLastArcLength(target) < 2) {
|
|
9783
9822
|
gui.undo.undo(); // remove the path
|
|
9784
9823
|
}
|
|
9824
|
+
if (e.shapes) {
|
|
9825
|
+
replaceShapes(e.shapes);
|
|
9826
|
+
}
|
|
9785
9827
|
});
|
|
9786
9828
|
|
|
9787
9829
|
function turnOn() {
|
|
9788
9830
|
var target = hit.getHitTarget();
|
|
9789
|
-
|
|
9831
|
+
initialArcCount = target.arcs.size();
|
|
9832
|
+
initialShapeCount = target.layer.shapes.length;
|
|
9833
|
+
if (sessionCount === 0) {
|
|
9834
|
+
showInstructions();
|
|
9835
|
+
}
|
|
9836
|
+
sessionCount++;
|
|
9837
|
+
}
|
|
9838
|
+
|
|
9839
|
+
function showInstructions() {
|
|
9790
9840
|
var isMac = navigator.userAgent.includes('Mac');
|
|
9791
9841
|
var symbol = isMac ? '⌘' : '^';
|
|
9842
|
+
var pathStr = polygonMode() ? 'closed paths' : 'paths';
|
|
9792
9843
|
var msg = `Instructions: Click on the map to draw ${pathStr}. Drag vertices to reshape a path. Type ${symbol}Z/${symbol}Y to undo/redo.`;
|
|
9793
|
-
|
|
9794
|
-
|
|
9844
|
+
alert = showPopupAlert(msg, null, {
|
|
9845
|
+
non_blocking: true, max_width: '360px'});
|
|
9795
9846
|
}
|
|
9796
9847
|
|
|
9797
9848
|
function turnOff() {
|
|
9798
|
-
|
|
9849
|
+
var removed = 0;
|
|
9850
|
+
finishCurrentPath();
|
|
9799
9851
|
if (polygonMode()) {
|
|
9800
|
-
|
|
9852
|
+
removed = removeOpenPolygons();
|
|
9801
9853
|
}
|
|
9802
9854
|
clearDrawingInfo();
|
|
9803
|
-
alert
|
|
9804
|
-
|
|
9855
|
+
if (alert) {
|
|
9856
|
+
alert.close();
|
|
9857
|
+
alert = null;
|
|
9858
|
+
}
|
|
9805
9859
|
initialArcCount = -1;
|
|
9860
|
+
initialShapeCount = -1;
|
|
9806
9861
|
if (gui.interaction.getMode() == 'drawing') {
|
|
9807
9862
|
// mode change was not initiated by interactive menu -- turn off interactivity
|
|
9808
9863
|
gui.interaction.turnOff();
|
|
9809
9864
|
}
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
function finish() {
|
|
9813
|
-
if (polygonMode()) {
|
|
9814
|
-
finishPolygons();
|
|
9865
|
+
if (removed > 0) {
|
|
9866
|
+
fullRedraw();
|
|
9815
9867
|
}
|
|
9816
9868
|
}
|
|
9817
9869
|
|
|
9818
|
-
|
|
9819
|
-
|
|
9870
|
+
// returns number of removed shapes
|
|
9871
|
+
function removeOpenPolygons() {
|
|
9820
9872
|
var target = hit.getHitTarget();
|
|
9821
|
-
var
|
|
9822
|
-
|
|
9823
|
-
|
|
9824
|
-
var
|
|
9825
|
-
|
|
9826
|
-
|
|
9827
|
-
|
|
9828
|
-
// use one of the newly created records as a template (they should all be the same)
|
|
9829
|
-
templateRecord = polygonRecords.pop();
|
|
9830
|
-
polygonRecords.splice(initialShapeCount); // remove new records
|
|
9831
|
-
}
|
|
9832
|
-
var polylineLyr = {
|
|
9833
|
-
geometry_type: 'polyline',
|
|
9834
|
-
shapes: polygonLyr.shapes.splice(initialShapeCount) // move new shapes to polyline layer
|
|
9835
|
-
};
|
|
9836
|
-
|
|
9837
|
-
// step2: convert polylines to polygons
|
|
9838
|
-
//
|
|
9839
|
-
// create a temp dataset containing both layers (so original arcs are preserved)
|
|
9840
|
-
var tmp = Object.assign({}, target.source.dataset);
|
|
9841
|
-
tmp.layers = tmp.layers.concat(polylineLyr);
|
|
9842
|
-
var outputLayers = mapshaper.cmd.polygons([polylineLyr], tmp, {});
|
|
9843
|
-
|
|
9844
|
-
// step3: add new polygons to the original polygons
|
|
9845
|
-
outputLayers[0].shapes.forEach(function(shp) {
|
|
9846
|
-
var rec = polygonRecords ? internal.copyRecord(templateRecord) : null;
|
|
9847
|
-
polygonLyr.shapes.push(shp);
|
|
9848
|
-
if (polygonRecords) {
|
|
9849
|
-
polygonRecords.push(rec);
|
|
9873
|
+
var arcs = target.source.dataset.arcs;
|
|
9874
|
+
var n = target.layer.shapes.length;
|
|
9875
|
+
// delete open paths (should only occur on single-arc shapes)
|
|
9876
|
+
for (var i=initialShapeCount; i<n; i++) {
|
|
9877
|
+
var shp = target.layer.shapes[i];
|
|
9878
|
+
if (!geom.pathIsClosed(shp[0], arcs)) {
|
|
9879
|
+
target.layer.shapes[i] = null;
|
|
9850
9880
|
}
|
|
9851
|
-
}
|
|
9881
|
+
}
|
|
9882
|
+
// removes polygons with wrong winding order and null geometry
|
|
9883
|
+
mapshaper.cmd.filterFeatures(target.layer, arcs, {remove_empty: true, quiet: true});
|
|
9884
|
+
return n - target.layer.shapes.length;
|
|
9885
|
+
}
|
|
9852
9886
|
|
|
9853
|
-
|
|
9887
|
+
function fullRedraw() {
|
|
9854
9888
|
gui.model.updated({arc_count: true});
|
|
9855
9889
|
}
|
|
9856
9890
|
|
|
@@ -9863,6 +9897,9 @@
|
|
|
9863
9897
|
|
|
9864
9898
|
hit.on('dragstart', function(e) {
|
|
9865
9899
|
if (!active() || drawing() || !hoverVertexInfo) return;
|
|
9900
|
+
if (alert) {
|
|
9901
|
+
alert.close('fade');
|
|
9902
|
+
}
|
|
9866
9903
|
e.originalEvent.stopPropagation();
|
|
9867
9904
|
_dragging = true;
|
|
9868
9905
|
if (hoverVertexInfo.type == 'interpolated') {
|
|
@@ -9903,12 +9940,10 @@
|
|
|
9903
9940
|
// double-click finishes a path (when drawing)
|
|
9904
9941
|
hit.on('dblclick', function(e) {
|
|
9905
9942
|
if (!active()) return;
|
|
9943
|
+
// double click finishes a path
|
|
9944
|
+
// note: if the preceding 'click' finished the path, this does not fire
|
|
9906
9945
|
if (drawing()) {
|
|
9907
|
-
|
|
9908
|
-
// before: dblclick is preceded by two clicks, need another vertex delete
|
|
9909
|
-
// now: second click is suppressed
|
|
9910
|
-
// deleteLastVertex(hit.getHitTarget());
|
|
9911
|
-
finishPath();
|
|
9946
|
+
finishCurrentPath();
|
|
9912
9947
|
e.originalEvent.stopPropagation(); // prevent dblclick zoom
|
|
9913
9948
|
return;
|
|
9914
9949
|
}
|
|
@@ -9920,7 +9955,7 @@
|
|
|
9920
9955
|
if (!active() || dragging()) return;
|
|
9921
9956
|
if (drawing()) {
|
|
9922
9957
|
if (!e.overMap) {
|
|
9923
|
-
|
|
9958
|
+
finishCurrentPath();
|
|
9924
9959
|
return;
|
|
9925
9960
|
}
|
|
9926
9961
|
if (gui.keyboard.shiftIsPressed()) {
|
|
@@ -9948,27 +9983,27 @@
|
|
|
9948
9983
|
if (!active()) return;
|
|
9949
9984
|
if (detectDoubleClick(e)) return; // ignore second click of a dblclick
|
|
9950
9985
|
var p = pixToDataCoords(e.x, e.y);
|
|
9951
|
-
if (drawing()
|
|
9952
|
-
|
|
9953
|
-
p
|
|
9954
|
-
extendPath(p);
|
|
9955
|
-
finishPath();
|
|
9956
|
-
} else if (drawing()) {
|
|
9957
|
-
extendPath(p);
|
|
9986
|
+
if (drawing()) {
|
|
9987
|
+
extendCurrentPath(hoverVertexInfo?.point || p);
|
|
9988
|
+
// extendCurrentPath(p); // just extend to current mouse position (not hover vertex)
|
|
9958
9989
|
} else if (gui.keyboard.shiftIsPressed()) {
|
|
9959
9990
|
deleteActiveVertex(e);
|
|
9960
9991
|
} else {
|
|
9961
|
-
|
|
9992
|
+
startNewPath(p);
|
|
9993
|
+
if (alert) {
|
|
9994
|
+
alert.close('fade');
|
|
9995
|
+
}
|
|
9962
9996
|
}
|
|
9963
9997
|
prevClickEvent = e;
|
|
9964
9998
|
});
|
|
9965
9999
|
|
|
9966
10000
|
// esc key finishes a path
|
|
9967
10001
|
gui.keyboard.on('keydown', function(e) {
|
|
9968
|
-
if (active() && e.keyName == 'esc') {
|
|
9969
|
-
|
|
10002
|
+
if (active() && (e.keyName == 'esc' || e.keyName == 'enter')) {
|
|
10003
|
+
e.stopPropagation();
|
|
10004
|
+
finishCurrentPath();
|
|
9970
10005
|
}
|
|
9971
|
-
});
|
|
10006
|
+
}, null, 10);
|
|
9972
10007
|
|
|
9973
10008
|
// detect second 'click' event of a double-click action
|
|
9974
10009
|
function detectDoubleClick(evt) {
|
|
@@ -10036,7 +10071,7 @@
|
|
|
10036
10071
|
thisEvt.y = snapped.y;
|
|
10037
10072
|
}
|
|
10038
10073
|
|
|
10039
|
-
function
|
|
10074
|
+
function finishCurrentPath() {
|
|
10040
10075
|
if (!drawing()) return;
|
|
10041
10076
|
var target = hit.getHitTarget();
|
|
10042
10077
|
if (getLastArcLength(target) <= 2) { // includes hover point
|
|
@@ -10045,27 +10080,44 @@
|
|
|
10045
10080
|
deleteLastVertex(target);
|
|
10046
10081
|
}
|
|
10047
10082
|
clearDrawingInfo();
|
|
10048
|
-
|
|
10083
|
+
fullRedraw();
|
|
10049
10084
|
}
|
|
10050
10085
|
|
|
10051
10086
|
// p: [x, y] source data coordinates
|
|
10052
|
-
function
|
|
10087
|
+
function startNewPath(p2) {
|
|
10053
10088
|
var target = hit.getHitTarget();
|
|
10054
|
-
var p1 = hoverVertexInfo
|
|
10089
|
+
var p1 = hoverVertexInfo?.point || p2;
|
|
10055
10090
|
appendNewPath(target, p1, p2);
|
|
10056
10091
|
gui.dispatchEvent('path_add', {target, p1, p2});
|
|
10057
10092
|
drawingId = target.layer.shapes.length - 1;
|
|
10058
10093
|
hit.setDrawingId(drawingId);
|
|
10059
10094
|
}
|
|
10060
10095
|
|
|
10061
|
-
// p: [x, y] source data coordinates
|
|
10062
|
-
function
|
|
10096
|
+
// p: [x, y] source data coordinates of new point on path
|
|
10097
|
+
function extendCurrentPath(p) {
|
|
10063
10098
|
var target = hit.getHitTarget();
|
|
10064
|
-
|
|
10099
|
+
var shapes1, shapes2;
|
|
10100
|
+
// finish the path if a vertex is selected (but not an interpolated point)
|
|
10101
|
+
var finish = hoverVertexInfo?.type == 'vertex';
|
|
10102
|
+
if (getLastArcLength(target) < 2) {
|
|
10103
|
+
error$1('Defective path');
|
|
10104
|
+
}
|
|
10105
|
+
if (finish && polygonMode()) {
|
|
10106
|
+
shapes1 = target.layer.shapes.slice(initialShapeCount);
|
|
10107
|
+
shapes2 = tryToClosePath(shapes1);
|
|
10108
|
+
}
|
|
10109
|
+
if (shapes2) {
|
|
10110
|
+
replaceShapes(shapes2);
|
|
10111
|
+
gui.dispatchEvent('path_extend', {target, p, shapes1, shapes2});
|
|
10112
|
+
clearDrawingInfo();
|
|
10113
|
+
fullRedraw();
|
|
10114
|
+
|
|
10115
|
+
} else {
|
|
10116
|
+
appendVertex$1(target, p);
|
|
10065
10117
|
gui.dispatchEvent('path_extend', {target, p});
|
|
10118
|
+
hit.triggerChangeEvent(); // trigger overlay redraw
|
|
10066
10119
|
}
|
|
10067
|
-
|
|
10068
|
-
hit.triggerChangeEvent();
|
|
10120
|
+
|
|
10069
10121
|
}
|
|
10070
10122
|
|
|
10071
10123
|
// p: [x, y] source data coordinates
|
|
@@ -10160,6 +10212,55 @@
|
|
|
10160
10212
|
return closest;
|
|
10161
10213
|
}
|
|
10162
10214
|
|
|
10215
|
+
// shapes: shapes that have been drawn in the current session
|
|
10216
|
+
//
|
|
10217
|
+
function tryToClosePath(shapes) {
|
|
10218
|
+
var target = hit.getHitTarget();
|
|
10219
|
+
var tmpLyr = {
|
|
10220
|
+
geometry_type: 'polyline',
|
|
10221
|
+
shapes: shapes.concat()
|
|
10222
|
+
};
|
|
10223
|
+
// create a temp dataset containing tmp layer and original layers
|
|
10224
|
+
// (so original arcs are retained)
|
|
10225
|
+
var tmpDataset = Object.assign({}, target.source.dataset);
|
|
10226
|
+
tmpDataset.layers = tmpDataset.layers.concat(tmpLyr);
|
|
10227
|
+
// NOTE: added "no_cuts" option to prevent polygons function from modifying
|
|
10228
|
+
// arcs, which would break undo/redo and cause other problems
|
|
10229
|
+
var outputLyr = mapshaper.cmd.polygons([tmpLyr], tmpDataset, {no_cuts: true})[0];
|
|
10230
|
+
var isOpenPath = getOpenPathTest(outputLyr.shapes);
|
|
10231
|
+
var shapes2 = [];
|
|
10232
|
+
shapes.forEach(function(shp) {
|
|
10233
|
+
if (isOpenPath(shp)) {
|
|
10234
|
+
shapes2.push(shp);
|
|
10235
|
+
}
|
|
10236
|
+
});
|
|
10237
|
+
return shapes2.concat(outputLyr.shapes);
|
|
10238
|
+
}
|
|
10239
|
+
|
|
10240
|
+
// Returns a function for testing if a shape is an unclosed path, and doesn't
|
|
10241
|
+
// overlap with an array of polygon shapes
|
|
10242
|
+
// polygons: array of polygon shapes
|
|
10243
|
+
function getOpenPathTest(polygons) {
|
|
10244
|
+
var arcs = [];
|
|
10245
|
+
internal.forEachArcId(polygons, function(arcId) {
|
|
10246
|
+
if (arcId < 0) arcId = ~arcId;
|
|
10247
|
+
arcs.push(arcId);
|
|
10248
|
+
});
|
|
10249
|
+
return function(shp) {
|
|
10250
|
+
// assume that compound shapes are already polygons
|
|
10251
|
+
var isOpen = false;
|
|
10252
|
+
if (shapeHasOneFwdArc(shp)) {
|
|
10253
|
+
var arcId = shp[0][0];
|
|
10254
|
+
if (arcId < 0) arcId = ~arcId;
|
|
10255
|
+
isOpen = !arcs.includes(arcId);
|
|
10256
|
+
}
|
|
10257
|
+
return isOpen;
|
|
10258
|
+
};
|
|
10259
|
+
}
|
|
10260
|
+
|
|
10261
|
+
function shapeHasOneFwdArc(shp) {
|
|
10262
|
+
return shp.length == 1 && shp[0].length == 1 && shp[0][0] >= 0;
|
|
10263
|
+
}
|
|
10163
10264
|
}
|
|
10164
10265
|
|
|
10165
10266
|
function initPointDrawing(gui, ext, hit) {
|
|
@@ -10756,8 +10857,8 @@
|
|
|
10756
10857
|
function getArcsForRendering(obj, ext) {
|
|
10757
10858
|
var dataset = obj.source.dataset;
|
|
10758
10859
|
var sourceArcs = dataset.arcs;
|
|
10759
|
-
if (obj.geographic && dataset.displayArcs) {
|
|
10760
|
-
return dataset.displayArcs.getScaledArcs(ext);
|
|
10860
|
+
if (obj.geographic && dataset.gui?.displayArcs) {
|
|
10861
|
+
return dataset.gui.displayArcs.getScaledArcs(ext);
|
|
10761
10862
|
}
|
|
10762
10863
|
return obj.arcs;
|
|
10763
10864
|
}
|
|
@@ -11877,10 +11978,10 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
11877
11978
|
//if (!lyr.geographic || !sourceCRS) {
|
|
11878
11979
|
// let getDisplayLayer() handle case of unprojectable source
|
|
11879
11980
|
if (!lyr.geographic) {
|
|
11880
|
-
return
|
|
11981
|
+
return;
|
|
11881
11982
|
}
|
|
11882
11983
|
if (lyr.dynamic_crs && internal.crsAreEqual(sourceCRS, lyr.dynamic_crs)) {
|
|
11883
|
-
return
|
|
11984
|
+
return;
|
|
11884
11985
|
}
|
|
11885
11986
|
lyr2 = getDisplayLayer(lyr.source.layer, lyr.source.dataset, {crs: displayCRS});
|
|
11886
11987
|
// kludge: copy projection-related properties to original layer
|
|
@@ -11916,7 +12017,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
11916
12017
|
|
|
11917
12018
|
var displayCRS = opts.crs || null;
|
|
11918
12019
|
// display arcs may have been generated when another layer in the dataset was converted for display... re-use if available
|
|
11919
|
-
var displayArcs = dataset.displayArcs || null;
|
|
12020
|
+
var displayArcs = dataset.gui?.displayArcs || null;
|
|
11920
12021
|
var sourceCRS;
|
|
11921
12022
|
var emptyArcs;
|
|
11922
12023
|
|
|
@@ -11933,7 +12034,8 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
11933
12034
|
|
|
11934
12035
|
// Assume that dataset.displayArcs is in the display CRS
|
|
11935
12036
|
// (it must be deleted upstream if reprojection is needed)
|
|
11936
|
-
if (!obj.empty && dataset.arcs && !displayArcs) {
|
|
12037
|
+
// if (!obj.empty && dataset.arcs && !displayArcs) {
|
|
12038
|
+
if (dataset.arcs && !displayArcs) {
|
|
11937
12039
|
// project arcs, if needed
|
|
11938
12040
|
if (needReprojectionForDisplay(sourceCRS, displayCRS)) {
|
|
11939
12041
|
displayArcs = projectArcsForDisplay(dataset.arcs, sourceCRS, displayCRS);
|
|
@@ -11943,7 +12045,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
11943
12045
|
}
|
|
11944
12046
|
|
|
11945
12047
|
enhanceArcCollectionForDisplay(displayArcs);
|
|
11946
|
-
dataset.
|
|
12048
|
+
dataset.gui = {displayArcs}; // stash these in the dataset for other layers to use
|
|
11947
12049
|
}
|
|
11948
12050
|
|
|
11949
12051
|
if (internal.layerHasFurniture(layer)) {
|
|
@@ -11955,14 +12057,14 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
11955
12057
|
// treating furniture layers (other than frame) as tabular for now,
|
|
11956
12058
|
// so there is something to show if they are selected
|
|
11957
12059
|
// obj.tabular = obj.furniture_type != 'frame';
|
|
11958
|
-
} else if (
|
|
11959
|
-
obj.layer = {shapes: []}; // ideally we should avoid empty layers
|
|
11960
|
-
} else if (!layer.geometry_type) {
|
|
11961
|
-
obj.tabular = true;
|
|
11962
|
-
} else {
|
|
12060
|
+
} else if (layer.geometry_type) {
|
|
11963
12061
|
obj.geographic = true;
|
|
11964
12062
|
obj.layer = layer;
|
|
11965
12063
|
obj.arcs = displayArcs;
|
|
12064
|
+
} else if (!obj.empty) {
|
|
12065
|
+
obj.tabular = true;
|
|
12066
|
+
} else {
|
|
12067
|
+
obj.layer = {shapes: []}; // ideally we should avoid empty layers
|
|
11966
12068
|
}
|
|
11967
12069
|
|
|
11968
12070
|
if (obj.tabular) {
|
|
@@ -12387,13 +12489,13 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12387
12489
|
updateFullBounds();
|
|
12388
12490
|
};
|
|
12389
12491
|
|
|
12390
|
-
function getGlobalStyleOptions() {
|
|
12492
|
+
function getGlobalStyleOptions(opts) {
|
|
12391
12493
|
var mode = gui.state.interaction_mode;
|
|
12392
|
-
return {
|
|
12494
|
+
return Object.assign({
|
|
12393
12495
|
darkMode: !!gui.state.dark_basemap,
|
|
12394
12496
|
outlineMode: mode == 'vertices',
|
|
12395
12497
|
interactionMode: mode
|
|
12396
|
-
};
|
|
12498
|
+
}, opts);
|
|
12397
12499
|
}
|
|
12398
12500
|
|
|
12399
12501
|
// Refresh map display in response to data changes, layer selection, etc.
|
|
@@ -12408,7 +12510,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12408
12510
|
|
|
12409
12511
|
if (arcsMayHaveChanged(e.flags)) {
|
|
12410
12512
|
// regenerate filtered arcs the next time they are needed for rendering
|
|
12411
|
-
// delete e.dataset.displayArcs
|
|
12513
|
+
// delete e.dataset.gui.displayArcs
|
|
12412
12514
|
clearAllDisplayArcs();
|
|
12413
12515
|
|
|
12414
12516
|
// reset simplification after projection (thresholds have changed)
|
|
@@ -12585,7 +12687,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12585
12687
|
|
|
12586
12688
|
function clearAllDisplayArcs() {
|
|
12587
12689
|
model.getDatasets().forEach(function(o) {
|
|
12588
|
-
delete o.
|
|
12690
|
+
delete o.gui;
|
|
12589
12691
|
});
|
|
12590
12692
|
}
|
|
12591
12693
|
|
package/www/mapshaper.js
CHANGED
|
@@ -749,7 +749,7 @@
|
|
|
749
749
|
}
|
|
750
750
|
|
|
751
751
|
function getGenericComparator(asc) {
|
|
752
|
-
asc = asc !== false;
|
|
752
|
+
asc = asc !== false && asc != 'descending'; // ascending is the default
|
|
753
753
|
return function(a, b) {
|
|
754
754
|
var retn = 0;
|
|
755
755
|
if (b == null) {
|
|
@@ -1362,13 +1362,13 @@
|
|
|
1362
1362
|
}
|
|
1363
1363
|
|
|
1364
1364
|
// Format an array of (preferably short) strings in columns for console logging.
|
|
1365
|
-
function formatStringsAsGrid(arr) {
|
|
1365
|
+
function formatStringsAsGrid(arr, width) {
|
|
1366
1366
|
// TODO: variable column width
|
|
1367
1367
|
var longest = arr.reduce(function(len, str) {
|
|
1368
1368
|
return Math.max(len, str.length);
|
|
1369
1369
|
}, 0),
|
|
1370
1370
|
colWidth = longest + 2,
|
|
1371
|
-
perLine = Math.floor(80 / colWidth) || 1;
|
|
1371
|
+
perLine = Math.floor((width || 80) / colWidth) || 1;
|
|
1372
1372
|
return arr.reduce(function(memo, name, i) {
|
|
1373
1373
|
var col = i % perLine;
|
|
1374
1374
|
if (i > 0 && col === 0) memo += '\n';
|
|
@@ -3720,8 +3720,6 @@
|
|
|
3720
3720
|
}
|
|
3721
3721
|
var require$1 = f;
|
|
3722
3722
|
|
|
3723
|
-
// import { createRequire } from "module";
|
|
3724
|
-
|
|
3725
3723
|
var iconv = require$1('iconv-lite');
|
|
3726
3724
|
|
|
3727
3725
|
// import iconv from 'iconv-lite';
|
|
@@ -4289,6 +4287,10 @@
|
|
|
4289
4287
|
return layerHasPaths(lyr) || layerHasPoints(lyr);
|
|
4290
4288
|
}
|
|
4291
4289
|
|
|
4290
|
+
function layerIsGeometric(lyr) {
|
|
4291
|
+
return !!lyr.geometry_type; // only checks type, includes empty layers
|
|
4292
|
+
}
|
|
4293
|
+
|
|
4292
4294
|
function layerHasPaths(lyr) {
|
|
4293
4295
|
return (lyr.geometry_type == 'polygon' || lyr.geometry_type == 'polyline') &&
|
|
4294
4296
|
layerHasNonNullShapes(lyr);
|
|
@@ -4552,6 +4554,7 @@
|
|
|
4552
4554
|
getLayerDataTable: getLayerDataTable,
|
|
4553
4555
|
layerHasNonNullData: layerHasNonNullData,
|
|
4554
4556
|
layerHasGeometry: layerHasGeometry,
|
|
4557
|
+
layerIsGeometric: layerIsGeometric,
|
|
4555
4558
|
layerHasPaths: layerHasPaths,
|
|
4556
4559
|
layerHasPoints: layerHasPoints,
|
|
4557
4560
|
layerIsRectangle: layerIsRectangle,
|
|
@@ -5493,6 +5496,8 @@
|
|
|
5493
5496
|
initLegacyArcs(arguments[0]); // want to phase this out
|
|
5494
5497
|
} else if (arguments.length == 3) {
|
|
5495
5498
|
initXYData.apply(this, arguments);
|
|
5499
|
+
} else if (arguments.length === 0) {
|
|
5500
|
+
initLegacyArcs([]); // empty collection
|
|
5496
5501
|
} else {
|
|
5497
5502
|
error("ArcCollection() Invalid arguments");
|
|
5498
5503
|
}
|
|
@@ -13184,7 +13189,6 @@
|
|
|
13184
13189
|
return findVertexIds(p2.x, p2.y, arcs);
|
|
13185
13190
|
}
|
|
13186
13191
|
|
|
13187
|
-
|
|
13188
13192
|
function snapVerticesToPoint(ids, p, arcs, final) {
|
|
13189
13193
|
var data = arcs.getVertexData();
|
|
13190
13194
|
ids.forEach(function(idx) {
|
|
@@ -23046,28 +23050,30 @@ ${svg}
|
|
|
23046
23050
|
// @samples Array of buffers containing sample text fields
|
|
23047
23051
|
// TODO: Improve reliability and number of detectable encodings.
|
|
23048
23052
|
function detectEncoding(samples) {
|
|
23049
|
-
|
|
23050
|
-
var
|
|
23051
|
-
|
|
23052
|
-
|
|
23053
|
-
encoding
|
|
23054
|
-
|
|
23055
|
-
|
|
23056
|
-
|
|
23057
|
-
|
|
23058
|
-
}
|
|
23059
|
-
|
|
23060
|
-
|
|
23061
|
-
|
|
23062
|
-
|
|
23063
|
-
|
|
23053
|
+
// score each encoding as 2 (high confidence) 1 (low confidence) or 0 (fail)
|
|
23054
|
+
var candidates = [{
|
|
23055
|
+
// latin1 is the original Shapefile encoding, using as an imperfect fallback
|
|
23056
|
+
// (sorts to the top only if all other encodings score 0)
|
|
23057
|
+
encoding: 'latin1',
|
|
23058
|
+
confidence: 0
|
|
23059
|
+
},{
|
|
23060
|
+
encoding: 'win1252',
|
|
23061
|
+
confidence: looksLikeWin1252(samples)
|
|
23062
|
+
}, {
|
|
23063
|
+
encoding: 'utf8',
|
|
23064
|
+
confidence: looksLikeUtf8(samples)
|
|
23065
|
+
}, {
|
|
23066
|
+
encoding: 'gb18030',
|
|
23067
|
+
confidence: looksLikeGB18030(samples)
|
|
23068
|
+
}];
|
|
23069
|
+
utils.sortOn(candidates, 'confidence', 'descending');
|
|
23070
|
+
return candidates[0];
|
|
23064
23071
|
}
|
|
23065
23072
|
|
|
23066
|
-
// Convert an array of text samples to a single string using a given encoding
|
|
23067
23073
|
function decodeSamples(enc, samples) {
|
|
23068
23074
|
return samples.map(function(buf) {
|
|
23069
23075
|
return decodeString(buf, enc).trim();
|
|
23070
|
-
})
|
|
23076
|
+
});
|
|
23071
23077
|
}
|
|
23072
23078
|
|
|
23073
23079
|
// Win1252 is the same as Latin1, except it replaces a block of control
|
|
@@ -23082,45 +23088,67 @@ ${svg}
|
|
|
23082
23088
|
//
|
|
23083
23089
|
function looksLikeWin1252(samples) {
|
|
23084
23090
|
//common l.c. ascii chars
|
|
23085
|
-
var
|
|
23086
|
-
// common extended + NBS (found in the wild)
|
|
23087
|
-
|
|
23088
|
-
str = decodeSamples('win1252', samples),
|
|
23089
|
-
|
|
23090
|
-
|
|
23091
|
-
|
|
23092
|
-
|
|
23091
|
+
var commonAscii = 'abcdefghijklmnopqrstuvwxyz0123456789.()\'"?+-\n,:;/|_$% ',
|
|
23092
|
+
// more common extended chars + NBS (found in the wild)
|
|
23093
|
+
moreChars = 'ßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿ°–±’‘' + '\xA0',
|
|
23094
|
+
str = decodeSamples('win1252', samples).join(''),
|
|
23095
|
+
commonAsciiPct = calcCharPct(str, commonAscii),
|
|
23096
|
+
expandedPct = calcCharPct(str, moreChars) + commonAsciiPct;
|
|
23097
|
+
var high = expandedPct > 0.98 && commonAsciiPct >= 0.8;
|
|
23098
|
+
var low = expandedPct > 0.97 && commonAsciiPct >= 0.6;
|
|
23099
|
+
return getScore(high, low);
|
|
23093
23100
|
}
|
|
23094
23101
|
|
|
23095
|
-
// Reject string if it contains the "replacement character" after decoding to UTF-8
|
|
23096
23102
|
function looksLikeUtf8(samples) {
|
|
23097
|
-
//
|
|
23098
|
-
//
|
|
23099
|
-
|
|
23100
|
-
var
|
|
23101
|
-
var
|
|
23102
|
-
var
|
|
23103
|
-
return
|
|
23104
|
-
}
|
|
23105
|
-
|
|
23106
|
-
|
|
23107
|
-
|
|
23108
|
-
|
|
23109
|
-
|
|
23110
|
-
|
|
23111
|
-
|
|
23112
|
-
|
|
23113
|
-
|
|
23114
|
-
|
|
23115
|
-
|
|
23116
|
-
|
|
23117
|
-
|
|
23118
|
-
|
|
23119
|
-
|
|
23103
|
+
// Reject string if it contains the "replacement character" after decoding
|
|
23104
|
+
// as utf-8
|
|
23105
|
+
var str = decodeSamples('utf8', samples).join('');
|
|
23106
|
+
var invalidPct = getInvalidPct(str);
|
|
23107
|
+
var high = invalidPct == 0;
|
|
23108
|
+
var low = invalidPct < 0.03;
|
|
23109
|
+
return getScore(high, low);
|
|
23110
|
+
}
|
|
23111
|
+
|
|
23112
|
+
function looksLikeGB18030(samples) {
|
|
23113
|
+
// from Jun Da's frequency table
|
|
23114
|
+
var commonHanZi = '的一了是不我他在人有这来个说上你们到地大着子那就也时道中出得为里下她要么去可以过和看之然后会自没小好生天而起对能还事想都心只家面样把国多又于头年手发如什开前当所无知老但见长已军从方声儿回意作话两点现很成身情十用些走经同进动己三行种向日明女正问此学太打间分因给本眼定二气力被门真法外听实其高先几笑再主将山战才口文最部第它西与全白者便相住公使东等边信像斯机光次感神却死理名重四做别叫王并水月果何位怎马常觉海张少处亲安特美呢色原直望命由候吧让应尔难关许车平师民夫书新接吗路利世比放活快总立队更花爱清五内金带工风克任至指往入空德吃表连解教思飞物电受今完林干代告兵加认通找远非性脸体轻记目令变似反南场跟必石拉士报李火且满该孩字红象即结言员房件万条提写或坐北早失离步陈乎请转近切黑深城办倒各父传音站官半男击合阿英决怕杀未形及算青黄落刚百论谁突交团度义罗始强紧敌八母钱极片化流管惊每题晚虽政兴答司妈夜越啊奇达谈武友数领朝保服曾拿则哪格尽根急语容喜求衣留双影刻制随冷九苦量备布照周故准客船江系姐争功怪星断句龙竟视界讲取古六静底精七河久绝阳识哈台确息期整伤忙娘终剑送计愿欢微您沉装敢云脚消若复收千木乐毛华集树弟皇响希诉号巴穿线汉攻呀警派刘酒雷停史阵错建足显丽另包势破亮首志观病热跑业治田冲运约暗待共院仍区害元哥围屋胡产室调类细议爷注易务众帝市摇乱密姑斗除式示睛楼造朋社持慢般皮京况块忽脑校甚查土怀福单联赶背统喝疑支血饭灵够章群威举兰游器察嘴痛铁掉宝历改推枪念参术帮党据品须居称旁退梦科岁低严引吉睡爸呼追局露维苏证村挥独节谢香亚波角案读图左掌假跳究楚余鬼钟座礼展玉肯既止守广考恩异料段尼画续米草胜存唐医程弹烟商顾招宗堂野初府激雨尚渐诗顿伯孙际沙雪板闻导致护春态基设耳简婚幸味右买演权卡继依恶庄炮亦虎州刀球需兄闪笔否烈玩啦逃排仅弄具散默景顶郑洋丝卫速侠差贵君习妇助恐救湖莫窗险顺封佛委旧印伙妹副宫洞永罪松责组防艺营班试鲁宋靠索灯介翻喊纪秘妻纸银略充戏担某杨射魔遇鱼陆级坏忘乡鲜哭费抓叶醒族纳床咱桌境列午振抱专毫店街怒托剧置秋藏赵划普岛较承脱革忍伸份免齐抗猛园临犯食架选歌按败良隐养属洛朱狂修坚压寻旅谋温探资端投泪阴换药麻施丈冰雄著绿职负短模荣遗农叹川毒吴蒋卖范禁杂富秀县祖梅谷凡刺登蓝奶缓姓牛价规篇劳质婆仙馆摆舞层狗占墙善熟验肉臣状呆圣懂袋唱值迷替归巨讨毕批镇吸森拍灭握伊杰勒卷偷奔省谓危付伦休厅预迎罢恨博亡欲悲宣标闹岸';
|
|
23115
|
+
var str = decodeSamples('gb18030', samples).join('');
|
|
23116
|
+
// Almost all the common Unicode Hanzi are in this range (along with many more uncommon ones)
|
|
23117
|
+
var chineseStr = str.replace(/[^\u4e00-\u9fa5]/g, '');
|
|
23118
|
+
var chinesePct = chineseStr.length / str.length;
|
|
23119
|
+
var commonAsciiStr = extractCommonAsciiChars(str);
|
|
23120
|
+
var commonAsciiPct = commonAsciiStr.length / str.length;
|
|
23121
|
+
// Some encodings get converted almost completely into valid (but mostly
|
|
23122
|
+
// uncommon) Chinese characters by the gb18030 converter.
|
|
23123
|
+
// To guard against this, we're requiring that a certain percentage of
|
|
23124
|
+
// characters be on a list of the most common characters.
|
|
23125
|
+
var commonHanZiPct = calcCharPct(chineseStr, commonHanZi);
|
|
23126
|
+
// check for non-convertible characters
|
|
23127
|
+
var invalidPct = getInvalidPct(str);
|
|
23128
|
+
var high = chinesePct > 0.5 && (chinesePct + commonAsciiPct) > 0.9 &&
|
|
23129
|
+
invalidPct === 0 && commonHanZiPct > 0.25;
|
|
23130
|
+
var low = chinesePct > 0.3 && (chinesePct + commonAsciiPct) > 0.8 &&
|
|
23131
|
+
commonHanZiPct > 0.15;
|
|
23132
|
+
return getScore(high, low);
|
|
23133
|
+
}
|
|
23134
|
+
|
|
23135
|
+
function getScore(high, low) {
|
|
23136
|
+
return high && 2 || low && 1 || 0;
|
|
23137
|
+
}
|
|
23138
|
+
|
|
23139
|
+
function getInvalidPct(str) {
|
|
23140
|
+
// count occurences of the "replacement" character
|
|
23141
|
+
var invalidCount = (str.match(/\ufffd/g) || []).length;
|
|
23142
|
+
return invalidCount / str.length;
|
|
23143
|
+
}
|
|
23144
|
+
|
|
23145
|
+
function extractCommonAsciiChars(str) {
|
|
23146
|
+
return str.replace(/[^a-zA-Z0-9.()'"?+\n,:;/|_$% -]/g, '');
|
|
23147
|
+
}
|
|
23120
23148
|
|
|
23121
23149
|
// Calc percentage of chars in a string that are present in a second string
|
|
23122
23150
|
// @chars String of chars to look for in @str
|
|
23123
|
-
function
|
|
23151
|
+
function calcCharPct(str, chars) {
|
|
23124
23152
|
var index = {},
|
|
23125
23153
|
count = 0;
|
|
23126
23154
|
str = str.toLowerCase();
|
|
@@ -23130,9 +23158,16 @@ ${svg}
|
|
|
23130
23158
|
for (i=0, n=str.length; i<n; i++) {
|
|
23131
23159
|
count += index[str[i]] || 0;
|
|
23132
23160
|
}
|
|
23133
|
-
return count / str.length;
|
|
23161
|
+
return count / str.length || 0;
|
|
23134
23162
|
}
|
|
23135
23163
|
|
|
23164
|
+
var EncodingDetection = /*#__PURE__*/Object.freeze({
|
|
23165
|
+
__proto__: null,
|
|
23166
|
+
detectEncodingFromBOM: detectEncodingFromBOM,
|
|
23167
|
+
detectEncoding: detectEncoding,
|
|
23168
|
+
decodeSamples: decodeSamples
|
|
23169
|
+
});
|
|
23170
|
+
|
|
23136
23171
|
// Convert a string containing delimited text data into a dataset object
|
|
23137
23172
|
function importDelim(str, opts) {
|
|
23138
23173
|
return importDelim2({content: str}, opts);
|
|
@@ -26644,25 +26679,19 @@ ${svg}
|
|
|
26644
26679
|
var info = detectEncoding(samples);
|
|
26645
26680
|
encoding = info.encoding;
|
|
26646
26681
|
if (info.confidence < 2) {
|
|
26647
|
-
msg = 'Warning: Unable to auto-detect the text encoding
|
|
26682
|
+
msg = 'Warning: Unable to auto-detect the DBF file text encoding with high confidence.';
|
|
26648
26683
|
msg += '\n\nDefaulting to: ' + encoding + (encoding in encodingNames ? ' (' + encodingNames[encoding] + ')' : '');
|
|
26649
|
-
msg += '\n\nSample of how non-ascii text was imported
|
|
26650
|
-
|
|
26651
|
-
|
|
26684
|
+
msg += '\n\nSample of how non-ascii text was imported:\n';
|
|
26685
|
+
if (runningInBrowser()) {
|
|
26686
|
+
msg += '<pre>' + formatStringsAsGrid(decodeSamples(encoding, samples), 50) + '</pre>';
|
|
26687
|
+
} else {
|
|
26688
|
+
msg += formatStringsAsGrid(decodeSamples(encoding, samples));
|
|
26689
|
+
}
|
|
26652
26690
|
msg += '\n\n' + ENCODING_PROMPT + '\n';
|
|
26653
26691
|
message(msg);
|
|
26654
26692
|
}
|
|
26655
26693
|
}
|
|
26656
26694
|
|
|
26657
|
-
// Show a sample of decoded text if non-ascii-range text has been found
|
|
26658
|
-
// if (encoding && samples.length > 0) {
|
|
26659
|
-
// msg = "Detected DBF text encoding: " + encoding + (encoding in encodingNames ? " (" + encodingNames[encoding] + ")" : "");
|
|
26660
|
-
// message(msg);
|
|
26661
|
-
// msg = decodeSamples(encoding, samples);
|
|
26662
|
-
// msg = formatStringsAsGrid(msg.split('\n'));
|
|
26663
|
-
// msg = "\nSample text containing non-ascii characters:" + (msg.length > 60 ? '\n' : '') + msg;
|
|
26664
|
-
// verbose(msg);
|
|
26665
|
-
// }
|
|
26666
26695
|
return encoding;
|
|
26667
26696
|
}
|
|
26668
26697
|
|
|
@@ -37783,7 +37812,7 @@ ${svg}
|
|
|
37783
37812
|
filteredLyr = copyLayer(filteredLyr);
|
|
37784
37813
|
}
|
|
37785
37814
|
|
|
37786
|
-
if (opts.verbose !== false) {
|
|
37815
|
+
if (opts.verbose !== false && !opts.quiet) {
|
|
37787
37816
|
message(utils.format('Retained %,d of %,d features', getFeatureCount(filteredLyr), n));
|
|
37788
37817
|
}
|
|
37789
37818
|
|
|
@@ -37833,14 +37862,15 @@ ${svg}
|
|
|
37833
37862
|
}
|
|
37834
37863
|
|
|
37835
37864
|
function combineFilters(a, b) {
|
|
37836
|
-
return
|
|
37865
|
+
return a && b ? function(id) {
|
|
37837
37866
|
return a(id) && b(id);
|
|
37838
|
-
}
|
|
37867
|
+
} : (a || b);
|
|
37839
37868
|
}
|
|
37840
37869
|
|
|
37841
|
-
cmd.evaluateEachFeature = function(lyr, dataset,
|
|
37870
|
+
cmd.evaluateEachFeature = function(lyr, dataset, expArg, opts) {
|
|
37842
37871
|
var n = getFeatureCount(lyr),
|
|
37843
37872
|
arcs = dataset.arcs,
|
|
37873
|
+
exp = expArg || '',
|
|
37844
37874
|
compiled, filter;
|
|
37845
37875
|
|
|
37846
37876
|
var exprOpts = {
|
|
@@ -42377,6 +42407,9 @@ ${svg}
|
|
|
42377
42407
|
candidates.forEach(function(candId) {
|
|
42378
42408
|
var hit;
|
|
42379
42409
|
if (candId == absId) return; // ignore self-intersections
|
|
42410
|
+
if (absArcId(candId) >= arcs.size()) {
|
|
42411
|
+
return;
|
|
42412
|
+
}
|
|
42380
42413
|
hit = geom.getPointToPathInfo(endpoint.point[0], endpoint.point[1], [candId], arcs);
|
|
42381
42414
|
if (hit && hit.distance <= maxGapLen && (!target || hit.distance < target.distance)) {
|
|
42382
42415
|
target = hit;
|
|
@@ -42462,7 +42495,9 @@ ${svg}
|
|
|
42462
42495
|
// if (opts.gap_tolerance) {
|
|
42463
42496
|
//opts = utils.defaults({snap_interval: opts.gap_tolerance * 0.1}, opts);
|
|
42464
42497
|
// }
|
|
42465
|
-
|
|
42498
|
+
if (!opts.no_cuts) {
|
|
42499
|
+
addIntersectionCuts(dataset, opts);
|
|
42500
|
+
}
|
|
42466
42501
|
return layers.map(function(lyr) {
|
|
42467
42502
|
if (lyr.geometry_type != 'polyline') stop("Expected a polyline layer");
|
|
42468
42503
|
if (opts.from_rings) {
|
|
@@ -42492,7 +42527,12 @@ ${svg}
|
|
|
42492
42527
|
}
|
|
42493
42528
|
|
|
42494
42529
|
function createPolygonLayer(lyr, dataset, opts) {
|
|
42495
|
-
var nodes
|
|
42530
|
+
var nodes;
|
|
42531
|
+
if (opts.no_cuts) {
|
|
42532
|
+
nodes = new NodeCollection(dataset.arcs);
|
|
42533
|
+
} else {
|
|
42534
|
+
nodes = closeUndershoots(lyr, dataset, opts);
|
|
42535
|
+
}
|
|
42496
42536
|
// ignore arcs that don't belong to this layer
|
|
42497
42537
|
nodes.setArcFilter(getArcPresenceTest(lyr.shapes, nodes.arcs));
|
|
42498
42538
|
var data = buildPolygonMosaic(nodes);
|
|
@@ -45485,7 +45525,7 @@ ${svg}
|
|
|
45485
45525
|
});
|
|
45486
45526
|
}
|
|
45487
45527
|
|
|
45488
|
-
var version = "0.6.
|
|
45528
|
+
var version = "0.6.75";
|
|
45489
45529
|
|
|
45490
45530
|
// Parse command line args into commands and run them
|
|
45491
45531
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
|
@@ -46162,6 +46202,7 @@ ${svg}
|
|
|
46162
46202
|
DelimExport,
|
|
46163
46203
|
DelimImport,
|
|
46164
46204
|
DelimReader,
|
|
46205
|
+
EncodingDetection,
|
|
46165
46206
|
Encodings,
|
|
46166
46207
|
Explode,
|
|
46167
46208
|
Export,
|
package/www/page.css
CHANGED
|
@@ -40,6 +40,20 @@ body {
|
|
|
40
40
|
cursor: default;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
.fade-out {
|
|
44
|
+
animation: fadeOut ease forwards 0.6s;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@keyframes fadeOut {
|
|
48
|
+
0% {
|
|
49
|
+
opacity: 1;
|
|
50
|
+
}
|
|
51
|
+
100% {
|
|
52
|
+
opacity: 0;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
43
57
|
.selectable,.selectable * {
|
|
44
58
|
user-select: default;
|
|
45
59
|
-webkit-user-select: text;
|