mapshaper 0.7.17 → 0.7.19
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 +110 -28
- package/package.json +2 -2
- package/www/index.html +3 -3
- package/www/mapshaper-gui.js +2650 -1301
- package/www/mapshaper.js +110 -28
- package/www/page.css +250 -8
package/www/mapshaper-gui.js
CHANGED
|
@@ -2422,232 +2422,6 @@
|
|
|
2422
2422
|
return bytes;
|
|
2423
2423
|
}
|
|
2424
2424
|
|
|
2425
|
-
var PAYLOAD_FIELDS = {
|
|
2426
|
-
table: ['records'],
|
|
2427
|
-
'table-records': ['records'],
|
|
2428
|
-
'table-fields': ['columns'],
|
|
2429
|
-
'table-schema': ['fields'],
|
|
2430
|
-
arcs: ['nn', 'xx', 'yy', 'zz', 'zlimit'],
|
|
2431
|
-
'arcs-simplification': ['zz'],
|
|
2432
|
-
layer: ['shapes', 'raster']
|
|
2433
|
-
};
|
|
2434
|
-
|
|
2435
|
-
async function storeUndoUnits(units, store, entryId, role) {
|
|
2436
|
-
var stored = [];
|
|
2437
|
-
try {
|
|
2438
|
-
for (var i = 0; i < units.length; i++) {
|
|
2439
|
-
stored.push(await storeUndoUnit(units[i], store, entryId, role));
|
|
2440
|
-
}
|
|
2441
|
-
} catch(e) {
|
|
2442
|
-
await store.delMany(getStoredUndoPayloadRefs(stored));
|
|
2443
|
-
throw e;
|
|
2444
|
-
}
|
|
2445
|
-
return stored;
|
|
2446
|
-
}
|
|
2447
|
-
|
|
2448
|
-
async function restoreStoredUndoUnits(units, store) {
|
|
2449
|
-
var hydrated = await hydrateStoredUndoUnits(units, store);
|
|
2450
|
-
internal.restoreCapturedUnits(hydrated);
|
|
2451
|
-
}
|
|
2452
|
-
|
|
2453
|
-
async function hydrateStoredUndoUnits(units, store) {
|
|
2454
|
-
var hydrated = [];
|
|
2455
|
-
for (var i = 0; i < units.length; i++) {
|
|
2456
|
-
hydrated.push(await hydrateStoredUndoUnit(units[i], store));
|
|
2457
|
-
}
|
|
2458
|
-
return hydrated;
|
|
2459
|
-
}
|
|
2460
|
-
|
|
2461
|
-
function getStoredUndoPayloadRefs(units) {
|
|
2462
|
-
var refs = [];
|
|
2463
|
-
units.forEach(function(unit) {
|
|
2464
|
-
if (unit.payloadRef) refs.push(unit.payloadRef);
|
|
2465
|
-
});
|
|
2466
|
-
return refs;
|
|
2467
|
-
}
|
|
2468
|
-
|
|
2469
|
-
function getUndoRestoreFlags(units, baseFlags) {
|
|
2470
|
-
var flags = Object.assign({}, baseFlags || {}, {undo_restore: true});
|
|
2471
|
-
units.forEach(function(unit) {
|
|
2472
|
-
if (unit.type == 'changed') return;
|
|
2473
|
-
if (unit.type == 'arcs') {
|
|
2474
|
-
flags.arc_count = true;
|
|
2475
|
-
} else if (unit.type == 'arcs-simplification') {
|
|
2476
|
-
flags.simplify = true;
|
|
2477
|
-
} else if (unit.type == 'table' ||
|
|
2478
|
-
unit.type == 'table-records' ||
|
|
2479
|
-
unit.type == 'table-fields' ||
|
|
2480
|
-
unit.type == 'table-order' ||
|
|
2481
|
-
unit.type == 'table-schema') {
|
|
2482
|
-
flags.same_table = false;
|
|
2483
|
-
} else if (unit.type == 'catalog' || unit.type == 'dataset') {
|
|
2484
|
-
flags.select = true;
|
|
2485
|
-
flags.arc_count = true;
|
|
2486
|
-
} else if (unit.type == 'dataset-info') {
|
|
2487
|
-
flags.info = true;
|
|
2488
|
-
} else if (unit.type == 'layer' ||
|
|
2489
|
-
unit.type == 'layer-metadata' ||
|
|
2490
|
-
unit.type == 'layer-order') {
|
|
2491
|
-
flags.select = true;
|
|
2492
|
-
}
|
|
2493
|
-
});
|
|
2494
|
-
return flags;
|
|
2495
|
-
}
|
|
2496
|
-
|
|
2497
|
-
async function storeUndoUnit(unit, store, entryId, role) {
|
|
2498
|
-
var payload = await getUnitPayload(unit);
|
|
2499
|
-
var stored = stripPayload(unit);
|
|
2500
|
-
if (payload) {
|
|
2501
|
-
stored.payloadRef = await store.put(payload, {
|
|
2502
|
-
entryId: entryId,
|
|
2503
|
-
role: role,
|
|
2504
|
-
unitType: unit.type
|
|
2505
|
-
});
|
|
2506
|
-
}
|
|
2507
|
-
return stored;
|
|
2508
|
-
}
|
|
2509
|
-
|
|
2510
|
-
async function hydrateStoredUndoUnit(unit, store) {
|
|
2511
|
-
var hydrated = Object.assign({}, unit);
|
|
2512
|
-
var payload;
|
|
2513
|
-
if (unit.payloadRef) {
|
|
2514
|
-
payload = await store.get(unit.payloadRef);
|
|
2515
|
-
if (!payload) {
|
|
2516
|
-
throw new Error('Missing undo payload: ' + unit.payloadRef.key);
|
|
2517
|
-
}
|
|
2518
|
-
payload = unpackPayload(unit, payload);
|
|
2519
|
-
Object.assign(hydrated, payload);
|
|
2520
|
-
}
|
|
2521
|
-
delete hydrated.payloadRef;
|
|
2522
|
-
return hydrated;
|
|
2523
|
-
}
|
|
2524
|
-
|
|
2525
|
-
async function getUnitPayload(unit) {
|
|
2526
|
-
var fields = PAYLOAD_FIELDS[unit.type];
|
|
2527
|
-
var payload, hasPayload;
|
|
2528
|
-
if (!fields) return null;
|
|
2529
|
-
payload = {};
|
|
2530
|
-
fields.forEach(function(field) {
|
|
2531
|
-
if (field in unit) {
|
|
2532
|
-
payload[field] = unit[field];
|
|
2533
|
-
hasPayload = true;
|
|
2534
|
-
}
|
|
2535
|
-
});
|
|
2536
|
-
if (!hasPayload) return null;
|
|
2537
|
-
if (unit.type == 'layer') return packLayerPayload(payload);
|
|
2538
|
-
return unit.type == 'table' ? packTablePayload(payload) : payload;
|
|
2539
|
-
}
|
|
2540
|
-
|
|
2541
|
-
async function packLayerPayload(payload) {
|
|
2542
|
-
if (payload.raster) {
|
|
2543
|
-
payload = Object.assign({}, payload, {
|
|
2544
|
-
raster: packRasterUndoPayload(payload.raster)
|
|
2545
|
-
});
|
|
2546
|
-
}
|
|
2547
|
-
return payload;
|
|
2548
|
-
}
|
|
2549
|
-
|
|
2550
|
-
async function packTablePayload(payload) {
|
|
2551
|
-
return {
|
|
2552
|
-
packedRecords: packRecordsAsColumns(payload.records)
|
|
2553
|
-
};
|
|
2554
|
-
}
|
|
2555
|
-
|
|
2556
|
-
function unpackPayload(unit, payload) {
|
|
2557
|
-
if (unit.type == 'table' && payload.packedRecords) {
|
|
2558
|
-
return {
|
|
2559
|
-
records: unpackRecordsFromColumns(payload.packedRecords)
|
|
2560
|
-
};
|
|
2561
|
-
}
|
|
2562
|
-
if (unit.type == 'layer' && payload.raster) {
|
|
2563
|
-
return Object.assign({}, payload, {
|
|
2564
|
-
raster: unpackRasterUndoPayload(payload.raster)
|
|
2565
|
-
});
|
|
2566
|
-
}
|
|
2567
|
-
return payload;
|
|
2568
|
-
}
|
|
2569
|
-
|
|
2570
|
-
function packRasterUndoPayload(raster) {
|
|
2571
|
-
var copy = Object.assign({}, raster);
|
|
2572
|
-
if (raster.view) {
|
|
2573
|
-
copy.view = Object.assign({}, raster.view);
|
|
2574
|
-
if (raster.view.preview) {
|
|
2575
|
-
copy.view.preview = stripPreviewPixels(raster.view.preview);
|
|
2576
|
-
}
|
|
2577
|
-
}
|
|
2578
|
-
if (raster.preview) {
|
|
2579
|
-
copy.preview = stripPreviewPixels(raster.preview);
|
|
2580
|
-
}
|
|
2581
|
-
return copy;
|
|
2582
|
-
}
|
|
2583
|
-
|
|
2584
|
-
function unpackRasterUndoPayload(raster) {
|
|
2585
|
-
var copy = Object.assign({}, raster);
|
|
2586
|
-
if (raster.view) {
|
|
2587
|
-
copy.view = Object.assign({}, raster.view);
|
|
2588
|
-
if (raster.view.preview && !raster.view.preview.pixels && raster.grid && raster.grid.samples) {
|
|
2589
|
-
copy.view.preview = internal.renderRasterPreview(raster.grid, raster.view.recipe, raster.view.preview.width, raster.view.preview.height);
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
return copy;
|
|
2593
|
-
}
|
|
2594
|
-
|
|
2595
|
-
function stripPreviewPixels(preview) {
|
|
2596
|
-
var copy = Object.assign({}, preview);
|
|
2597
|
-
delete copy.canvas;
|
|
2598
|
-
delete copy.pixels;
|
|
2599
|
-
return copy;
|
|
2600
|
-
}
|
|
2601
|
-
|
|
2602
|
-
function packRecordsAsColumns(records) {
|
|
2603
|
-
var fields = getRecordFields(records);
|
|
2604
|
-
return {
|
|
2605
|
-
fields: fields,
|
|
2606
|
-
types: fields.map(function() { return null; }),
|
|
2607
|
-
data: fields.map(function(field) {
|
|
2608
|
-
return records.map(function(rec) {
|
|
2609
|
-
return rec ? rec[field] : undefined;
|
|
2610
|
-
});
|
|
2611
|
-
}),
|
|
2612
|
-
size: records.length
|
|
2613
|
-
};
|
|
2614
|
-
}
|
|
2615
|
-
|
|
2616
|
-
function getRecordFields(records) {
|
|
2617
|
-
var index = {};
|
|
2618
|
-
records.forEach(function(rec) {
|
|
2619
|
-
Object.keys(rec || {}).forEach(function(field) {
|
|
2620
|
-
index[field] = true;
|
|
2621
|
-
});
|
|
2622
|
-
});
|
|
2623
|
-
return Object.keys(index);
|
|
2624
|
-
}
|
|
2625
|
-
|
|
2626
|
-
function unpackRecordsFromColumns(data) {
|
|
2627
|
-
var records = [];
|
|
2628
|
-
for (var i = 0; i < data.size; i++) {
|
|
2629
|
-
records[i] = {};
|
|
2630
|
-
}
|
|
2631
|
-
data.fields.forEach(function(field, j) {
|
|
2632
|
-
var values = data.data[j];
|
|
2633
|
-
values.forEach(function(val, i) {
|
|
2634
|
-
records[i][field] = val;
|
|
2635
|
-
});
|
|
2636
|
-
});
|
|
2637
|
-
return records;
|
|
2638
|
-
}
|
|
2639
|
-
|
|
2640
|
-
function stripPayload(unit) {
|
|
2641
|
-
var fields = PAYLOAD_FIELDS[unit.type];
|
|
2642
|
-
var stripped = Object.assign({}, unit);
|
|
2643
|
-
if (fields) {
|
|
2644
|
-
fields.forEach(function(field) {
|
|
2645
|
-
delete stripped[field];
|
|
2646
|
-
});
|
|
2647
|
-
}
|
|
2648
|
-
return stripped;
|
|
2649
|
-
}
|
|
2650
|
-
|
|
2651
2425
|
// Fall back to browserify's Buffer polyfill
|
|
2652
2426
|
var B = typeof Buffer != 'undefined' ? Buffer : require$1('buffer').Buffer;
|
|
2653
2427
|
|
|
@@ -2673,7 +2447,7 @@
|
|
|
2673
2447
|
return obj === Object(obj); // via underscore
|
|
2674
2448
|
}
|
|
2675
2449
|
|
|
2676
|
-
function clamp(val, min, max) {
|
|
2450
|
+
function clamp$1(val, min, max) {
|
|
2677
2451
|
return val < min ? min : (val > max ? max : val);
|
|
2678
2452
|
}
|
|
2679
2453
|
|
|
@@ -3354,7 +3128,7 @@
|
|
|
3354
3128
|
function findValueByRank(arr, rank) {
|
|
3355
3129
|
if (!arr.length || rank < 1 || rank > arr.length) error$1("[findValueByRank()] invalid input");
|
|
3356
3130
|
|
|
3357
|
-
rank = clamp(rank | 0, 1, arr.length);
|
|
3131
|
+
rank = clamp$1(rank | 0, 1, arr.length);
|
|
3358
3132
|
var k = rank - 1, // conv. rank to array index
|
|
3359
3133
|
n = arr.length,
|
|
3360
3134
|
l = 0,
|
|
@@ -3728,7 +3502,7 @@
|
|
|
3728
3502
|
// self-import and the resulting Rollup circular-dependency warning.
|
|
3729
3503
|
var utils = {
|
|
3730
3504
|
addThousandsSep, addslashes, arrayToIndex,
|
|
3731
|
-
clamp, cleanNumericString, contains, copyElements, countValues, createBuffer,
|
|
3505
|
+
clamp: clamp$1, cleanNumericString, contains, copyElements, countValues, createBuffer,
|
|
3732
3506
|
defaults, difference,
|
|
3733
3507
|
endsWith, every, expandoBuffer, extend, extendBuffer,
|
|
3734
3508
|
find, findMedian, findQuantile, findRankByValue, findStringPrefix,
|
|
@@ -6504,18 +6278,244 @@
|
|
|
6504
6278
|
return Object.keys(index);
|
|
6505
6279
|
}
|
|
6506
6280
|
|
|
6507
|
-
|
|
6508
|
-
|
|
6281
|
+
var PAYLOAD_FIELDS = {
|
|
6282
|
+
table: ['records'],
|
|
6283
|
+
'table-records': ['records'],
|
|
6284
|
+
'table-fields': ['columns'],
|
|
6285
|
+
'table-schema': ['fields'],
|
|
6286
|
+
arcs: ['nn', 'xx', 'yy', 'zz', 'zlimit'],
|
|
6287
|
+
'arcs-simplification': ['zz'],
|
|
6288
|
+
layer: ['shapes', 'raster']
|
|
6289
|
+
};
|
|
6509
6290
|
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6291
|
+
async function storeUndoUnits(units, store, entryId, role) {
|
|
6292
|
+
var stored = [];
|
|
6293
|
+
try {
|
|
6294
|
+
for (var i = 0; i < units.length; i++) {
|
|
6295
|
+
stored.push(await storeUndoUnit(units[i], store, entryId, role));
|
|
6296
|
+
}
|
|
6297
|
+
} catch(e) {
|
|
6298
|
+
await store.delMany(getStoredUndoPayloadRefs(stored));
|
|
6299
|
+
throw e;
|
|
6300
|
+
}
|
|
6301
|
+
return stored;
|
|
6302
|
+
}
|
|
6514
6303
|
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6304
|
+
async function restoreStoredUndoUnits(units, store) {
|
|
6305
|
+
var hydrated = await hydrateStoredUndoUnits(units, store);
|
|
6306
|
+
restoreCapturedUnits(hydrated);
|
|
6307
|
+
}
|
|
6308
|
+
|
|
6309
|
+
async function hydrateStoredUndoUnits(units, store) {
|
|
6310
|
+
var hydrated = [];
|
|
6311
|
+
for (var i = 0; i < units.length; i++) {
|
|
6312
|
+
hydrated.push(await hydrateStoredUndoUnit(units[i], store));
|
|
6313
|
+
}
|
|
6314
|
+
return hydrated;
|
|
6315
|
+
}
|
|
6316
|
+
|
|
6317
|
+
function getStoredUndoPayloadRefs(units) {
|
|
6318
|
+
var refs = [];
|
|
6319
|
+
units.forEach(function(unit) {
|
|
6320
|
+
if (unit.payloadRef) refs.push(unit.payloadRef);
|
|
6321
|
+
});
|
|
6322
|
+
return refs;
|
|
6323
|
+
}
|
|
6324
|
+
|
|
6325
|
+
function getUndoRestoreFlags(units, baseFlags) {
|
|
6326
|
+
var flags = Object.assign({}, baseFlags || {}, {undo_restore: true});
|
|
6327
|
+
units.forEach(function(unit) {
|
|
6328
|
+
if (unit.type == 'changed') return;
|
|
6329
|
+
if (unit.type == 'arcs') {
|
|
6330
|
+
flags.arc_count = true;
|
|
6331
|
+
} else if (unit.type == 'arcs-simplification') {
|
|
6332
|
+
flags.simplify = true;
|
|
6333
|
+
} else if (unit.type == 'table' ||
|
|
6334
|
+
unit.type == 'table-records' ||
|
|
6335
|
+
unit.type == 'table-fields' ||
|
|
6336
|
+
unit.type == 'table-order' ||
|
|
6337
|
+
unit.type == 'table-schema') {
|
|
6338
|
+
flags.same_table = false;
|
|
6339
|
+
} else if (unit.type == 'catalog' || unit.type == 'dataset') {
|
|
6340
|
+
flags.select = true;
|
|
6341
|
+
flags.arc_count = true;
|
|
6342
|
+
} else if (unit.type == 'dataset-info') {
|
|
6343
|
+
flags.info = true;
|
|
6344
|
+
} else if (unit.type == 'layer' ||
|
|
6345
|
+
unit.type == 'layer-metadata' ||
|
|
6346
|
+
unit.type == 'layer-order') {
|
|
6347
|
+
flags.select = true;
|
|
6348
|
+
}
|
|
6349
|
+
});
|
|
6350
|
+
return flags;
|
|
6351
|
+
}
|
|
6352
|
+
|
|
6353
|
+
async function storeUndoUnit(unit, store, entryId, role) {
|
|
6354
|
+
var payload = await getUnitPayload(unit);
|
|
6355
|
+
var stored = stripPayload(unit);
|
|
6356
|
+
if (payload) {
|
|
6357
|
+
stored.payloadRef = await store.put(payload, {
|
|
6358
|
+
entryId: entryId,
|
|
6359
|
+
role: role,
|
|
6360
|
+
unitType: unit.type
|
|
6361
|
+
});
|
|
6362
|
+
}
|
|
6363
|
+
return stored;
|
|
6364
|
+
}
|
|
6365
|
+
|
|
6366
|
+
async function hydrateStoredUndoUnit(unit, store) {
|
|
6367
|
+
var hydrated = Object.assign({}, unit);
|
|
6368
|
+
var payload;
|
|
6369
|
+
if (unit.payloadRef) {
|
|
6370
|
+
payload = await store.get(unit.payloadRef);
|
|
6371
|
+
if (!payload) {
|
|
6372
|
+
throw new Error('Missing undo payload: ' + unit.payloadRef.key);
|
|
6373
|
+
}
|
|
6374
|
+
payload = unpackPayload(unit, payload);
|
|
6375
|
+
Object.assign(hydrated, payload);
|
|
6376
|
+
}
|
|
6377
|
+
delete hydrated.payloadRef;
|
|
6378
|
+
return hydrated;
|
|
6379
|
+
}
|
|
6380
|
+
|
|
6381
|
+
async function getUnitPayload(unit) {
|
|
6382
|
+
var fields = PAYLOAD_FIELDS[unit.type];
|
|
6383
|
+
var payload, hasPayload;
|
|
6384
|
+
if (!fields) return null;
|
|
6385
|
+
payload = {};
|
|
6386
|
+
fields.forEach(function(field) {
|
|
6387
|
+
if (field in unit) {
|
|
6388
|
+
payload[field] = unit[field];
|
|
6389
|
+
hasPayload = true;
|
|
6390
|
+
}
|
|
6391
|
+
});
|
|
6392
|
+
if (!hasPayload) return null;
|
|
6393
|
+
if (unit.type == 'layer') return packLayerPayload(payload);
|
|
6394
|
+
return unit.type == 'table' ? packTablePayload(payload) : payload;
|
|
6395
|
+
}
|
|
6396
|
+
|
|
6397
|
+
async function packLayerPayload(payload) {
|
|
6398
|
+
if (payload.raster) {
|
|
6399
|
+
payload = Object.assign({}, payload, {
|
|
6400
|
+
raster: packRasterUndoPayload(payload.raster)
|
|
6401
|
+
});
|
|
6402
|
+
}
|
|
6403
|
+
return payload;
|
|
6404
|
+
}
|
|
6405
|
+
|
|
6406
|
+
async function packTablePayload(payload) {
|
|
6407
|
+
return {
|
|
6408
|
+
packedRecords: packRecordsAsColumns(payload.records)
|
|
6409
|
+
};
|
|
6410
|
+
}
|
|
6411
|
+
|
|
6412
|
+
function unpackPayload(unit, payload) {
|
|
6413
|
+
if (unit.type == 'table' && payload.packedRecords) {
|
|
6414
|
+
return {
|
|
6415
|
+
records: unpackRecordsFromColumns(payload.packedRecords)
|
|
6416
|
+
};
|
|
6417
|
+
}
|
|
6418
|
+
if (unit.type == 'layer' && payload.raster) {
|
|
6419
|
+
return Object.assign({}, payload, {
|
|
6420
|
+
raster: unpackRasterUndoPayload(payload.raster)
|
|
6421
|
+
});
|
|
6422
|
+
}
|
|
6423
|
+
return payload;
|
|
6424
|
+
}
|
|
6425
|
+
|
|
6426
|
+
function packRasterUndoPayload(raster) {
|
|
6427
|
+
var copy = Object.assign({}, raster);
|
|
6428
|
+
if (raster.view) {
|
|
6429
|
+
copy.view = Object.assign({}, raster.view);
|
|
6430
|
+
if (raster.view.preview) {
|
|
6431
|
+
copy.view.preview = stripPreviewPixels(raster.view.preview);
|
|
6432
|
+
}
|
|
6433
|
+
}
|
|
6434
|
+
if (raster.preview) {
|
|
6435
|
+
copy.preview = stripPreviewPixels(raster.preview);
|
|
6436
|
+
}
|
|
6437
|
+
return copy;
|
|
6438
|
+
}
|
|
6439
|
+
|
|
6440
|
+
function unpackRasterUndoPayload(raster) {
|
|
6441
|
+
var copy = Object.assign({}, raster);
|
|
6442
|
+
if (raster.view) {
|
|
6443
|
+
copy.view = Object.assign({}, raster.view);
|
|
6444
|
+
if (raster.view.preview && !raster.view.preview.pixels && raster.grid && raster.grid.samples) {
|
|
6445
|
+
copy.view.preview = renderRasterPreview(raster.grid, raster.view.recipe, raster.view.preview.width, raster.view.preview.height);
|
|
6446
|
+
}
|
|
6447
|
+
}
|
|
6448
|
+
return copy;
|
|
6449
|
+
}
|
|
6450
|
+
|
|
6451
|
+
function stripPreviewPixels(preview) {
|
|
6452
|
+
var copy = Object.assign({}, preview);
|
|
6453
|
+
delete copy.canvas;
|
|
6454
|
+
delete copy.pixels;
|
|
6455
|
+
return copy;
|
|
6456
|
+
}
|
|
6457
|
+
|
|
6458
|
+
function packRecordsAsColumns(records) {
|
|
6459
|
+
var fields = getRecordFields(records);
|
|
6460
|
+
return {
|
|
6461
|
+
fields: fields,
|
|
6462
|
+
types: fields.map(function() { return null; }),
|
|
6463
|
+
data: fields.map(function(field) {
|
|
6464
|
+
return records.map(function(rec) {
|
|
6465
|
+
return rec ? rec[field] : undefined;
|
|
6466
|
+
});
|
|
6467
|
+
}),
|
|
6468
|
+
size: records.length
|
|
6469
|
+
};
|
|
6470
|
+
}
|
|
6471
|
+
|
|
6472
|
+
function getRecordFields(records) {
|
|
6473
|
+
var index = {};
|
|
6474
|
+
records.forEach(function(rec) {
|
|
6475
|
+
Object.keys(rec || {}).forEach(function(field) {
|
|
6476
|
+
index[field] = true;
|
|
6477
|
+
});
|
|
6478
|
+
});
|
|
6479
|
+
return Object.keys(index);
|
|
6480
|
+
}
|
|
6481
|
+
|
|
6482
|
+
function unpackRecordsFromColumns(data) {
|
|
6483
|
+
var records = [];
|
|
6484
|
+
for (var i = 0; i < data.size; i++) {
|
|
6485
|
+
records[i] = {};
|
|
6486
|
+
}
|
|
6487
|
+
data.fields.forEach(function(field, j) {
|
|
6488
|
+
var values = data.data[j];
|
|
6489
|
+
values.forEach(function(val, i) {
|
|
6490
|
+
records[i][field] = val;
|
|
6491
|
+
});
|
|
6492
|
+
});
|
|
6493
|
+
return records;
|
|
6494
|
+
}
|
|
6495
|
+
|
|
6496
|
+
function stripPayload(unit) {
|
|
6497
|
+
var fields = PAYLOAD_FIELDS[unit.type];
|
|
6498
|
+
var stripped = Object.assign({}, unit);
|
|
6499
|
+
if (fields) {
|
|
6500
|
+
fields.forEach(function(field) {
|
|
6501
|
+
delete stripped[field];
|
|
6502
|
+
});
|
|
6503
|
+
}
|
|
6504
|
+
return stripped;
|
|
6505
|
+
}
|
|
6506
|
+
|
|
6507
|
+
function createStoredUndoHistory(gui) {
|
|
6508
|
+
var undoEntryId = 0;
|
|
6509
|
+
|
|
6510
|
+
return {
|
|
6511
|
+
addTransaction: addTransaction,
|
|
6512
|
+
getPayloadStore: getPayloadStore
|
|
6513
|
+
};
|
|
6514
|
+
|
|
6515
|
+
async function addTransaction(tx, opts) {
|
|
6516
|
+
var undoUnits, redoCaptureUnits, updateFlags, store, entryId, storedUndoUnits,
|
|
6517
|
+
storedRedoUnits, storeStart, storeMillis = 0, evictToken = {};
|
|
6518
|
+
opts = opts || {};
|
|
6519
6519
|
if (!tx || opts.error) return {skipped: true};
|
|
6520
6520
|
undoUnits = filterUnchangedRestoreUnits(tx.getCapturedUnits());
|
|
6521
6521
|
if (!undoUnits.some(isRestoreUnit)) return {
|
|
@@ -10788,6 +10788,9 @@
|
|
|
10788
10788
|
if (e.deleteLayer) {
|
|
10789
10789
|
addMenuItem('delete layer', e.deleteLayer, '');
|
|
10790
10790
|
}
|
|
10791
|
+
if (e.styleLayer) {
|
|
10792
|
+
addMenuItem('style layer', e.styleLayer, '');
|
|
10793
|
+
}
|
|
10791
10794
|
if (e.showLayerInfo) {
|
|
10792
10795
|
addMenuItem('show info', e.showLayerInfo, '');
|
|
10793
10796
|
}
|
|
@@ -11225,8 +11228,19 @@
|
|
|
11225
11228
|
content.node().appendChild(renderLayerInfo(internal.getLayerInfo(target.layer, target.dataset)));
|
|
11226
11229
|
}
|
|
11227
11230
|
|
|
11231
|
+
function styleLayer() {
|
|
11232
|
+
var target = findLayerById(id);
|
|
11233
|
+
if (!target) return;
|
|
11234
|
+
if (target.layer.geometry_type == 'point' && gui.pointStyleTool) {
|
|
11235
|
+
gui.pointStyleTool.open(target.layer, target.dataset);
|
|
11236
|
+
} else if (gui.layerStyleTool) {
|
|
11237
|
+
gui.layerStyleTool.open(target.layer, target.dataset);
|
|
11238
|
+
}
|
|
11239
|
+
}
|
|
11240
|
+
|
|
11228
11241
|
function openLayerMenu(e) {
|
|
11229
11242
|
var menuEvent = e;
|
|
11243
|
+
var target = findLayerById(id);
|
|
11230
11244
|
e.stopPropagation();
|
|
11231
11245
|
if (!isFinite(e.pageX) || !isFinite(e.pageY)) {
|
|
11232
11246
|
var rect = moreBtn.node().getBoundingClientRect();
|
|
@@ -11237,6 +11251,9 @@
|
|
|
11237
11251
|
}
|
|
11238
11252
|
menuEvent.deleteLayer = deleteLayer;
|
|
11239
11253
|
menuEvent.showLayerInfo = showLayerInfo;
|
|
11254
|
+
if (target && layerCanBeStyled(target.layer)) {
|
|
11255
|
+
menuEvent.styleLayer = styleLayer;
|
|
11256
|
+
}
|
|
11240
11257
|
menuEvent.contextMenuId = 'layer-' + id;
|
|
11241
11258
|
openContextMenu(menuEvent, null, null);
|
|
11242
11259
|
}
|
|
@@ -11446,6 +11463,10 @@
|
|
|
11446
11463
|
return internal.layerIsGeometric(lyr) || internal.layerHasRaster(lyr) || internal.layerHasFurniture(lyr);
|
|
11447
11464
|
}
|
|
11448
11465
|
|
|
11466
|
+
function layerCanBeStyled(lyr) {
|
|
11467
|
+
return !!(lyr && (lyr.geometry_type == 'point' || lyr.geometry_type == 'polyline' || lyr.geometry_type == 'polygon'));
|
|
11468
|
+
}
|
|
11469
|
+
|
|
11449
11470
|
function rowHTML(c1, c2, cname) {
|
|
11450
11471
|
return utils$1.format('<div class="row%s"><div class="col1">%s</div>' +
|
|
11451
11472
|
'<div class="col2">%s</div></div>', cname ? ' ' + cname : '', c1, c2);
|
|
@@ -11676,32 +11697,148 @@
|
|
|
11676
11697
|
return value.toFixed(value < 10 && value >= 0.5 ? 1 : 0) + ' ' + units[i];
|
|
11677
11698
|
}
|
|
11678
11699
|
|
|
11679
|
-
function
|
|
11680
|
-
var
|
|
11681
|
-
|
|
11682
|
-
|
|
11683
|
-
|
|
11684
|
-
|
|
11685
|
-
|
|
11686
|
-
var nonEditingCommands = 'i,target,info,version,verbose,projections,inspect,help,h,encodings,calc,comment'.split(',');
|
|
11700
|
+
function cullCommandHistory(commands, parseCommand, isStyleProperty) {
|
|
11701
|
+
var out = [];
|
|
11702
|
+
(commands || []).forEach(function(cmd) {
|
|
11703
|
+
addCommand(out, cmd, parseCommand, isStyleProperty);
|
|
11704
|
+
});
|
|
11705
|
+
return out;
|
|
11706
|
+
}
|
|
11687
11707
|
|
|
11688
|
-
|
|
11689
|
-
|
|
11690
|
-
|
|
11691
|
-
|
|
11692
|
-
|
|
11693
|
-
|
|
11694
|
-
|
|
11695
|
-
|
|
11696
|
-
|
|
11708
|
+
function addCommand(commands, cmd, parseCommand, isStyleProperty) {
|
|
11709
|
+
var curr = getCullableCommand(cmd, parseCommand, isStyleProperty);
|
|
11710
|
+
var prev;
|
|
11711
|
+
if (!curr) {
|
|
11712
|
+
commands.push(cmd);
|
|
11713
|
+
return;
|
|
11714
|
+
}
|
|
11715
|
+
while (commands.length > 0) {
|
|
11716
|
+
prev = getCullableCommand(commands[commands.length - 1], parseCommand, isStyleProperty);
|
|
11717
|
+
if (!prev || !commandCanCull(curr, prev)) break;
|
|
11718
|
+
commands.pop();
|
|
11719
|
+
}
|
|
11720
|
+
commands.push(cmd);
|
|
11721
|
+
}
|
|
11697
11722
|
|
|
11698
|
-
|
|
11699
|
-
|
|
11700
|
-
|
|
11723
|
+
function commandCanCull(curr, prev) {
|
|
11724
|
+
if (curr.type != prev.type || curr.target != prev.target || curr.ids != prev.ids) {
|
|
11725
|
+
return false;
|
|
11726
|
+
}
|
|
11727
|
+
if (curr.type == 'style') {
|
|
11728
|
+
return isSuperset(curr.fields, prev.fields);
|
|
11729
|
+
}
|
|
11730
|
+
return curr.key == prev.key;
|
|
11731
|
+
}
|
|
11701
11732
|
|
|
11702
|
-
|
|
11703
|
-
|
|
11704
|
-
|
|
11733
|
+
function getCullableCommand(str, parseCommand, isStyleProperty) {
|
|
11734
|
+
var parsed, cmd, opts;
|
|
11735
|
+
if (!parseCommand || !isStyleProperty) return null;
|
|
11736
|
+
try {
|
|
11737
|
+
parsed = parseCommand(str);
|
|
11738
|
+
} catch(e) {
|
|
11739
|
+
return null;
|
|
11740
|
+
}
|
|
11741
|
+
if (!parsed || parsed.length != 1) return null;
|
|
11742
|
+
cmd = parsed[0];
|
|
11743
|
+
opts = cmd.options || {};
|
|
11744
|
+
if (cmd.name == 'style' || cmd.name == 'svg-style') {
|
|
11745
|
+
return getStyleCullInfo(opts, isStyleProperty);
|
|
11746
|
+
}
|
|
11747
|
+
if (cmd.name == 'classify') {
|
|
11748
|
+
return getClassifyCullInfo(opts);
|
|
11749
|
+
}
|
|
11750
|
+
return null;
|
|
11751
|
+
}
|
|
11752
|
+
|
|
11753
|
+
function getStyleCullInfo(opts, isStyleProperty) {
|
|
11754
|
+
var fields;
|
|
11755
|
+
if (opts.clear || opts.where) return null;
|
|
11756
|
+
fields = getStyleFields$1(opts, isStyleProperty);
|
|
11757
|
+
if (fields.length === 0) return null;
|
|
11758
|
+
return {
|
|
11759
|
+
type: 'style',
|
|
11760
|
+
target: getTargetKey(opts),
|
|
11761
|
+
ids: getIdsKey(opts),
|
|
11762
|
+
fields: fields
|
|
11763
|
+
};
|
|
11764
|
+
}
|
|
11765
|
+
|
|
11766
|
+
function getStyleFields$1(opts, isStyleProperty) {
|
|
11767
|
+
var fields = [];
|
|
11768
|
+
Object.keys(opts).forEach(function(name) {
|
|
11769
|
+
var field = name.replace(/_/g, '-');
|
|
11770
|
+
if (isStyleProperty(field) && fields.indexOf(field) == -1) {
|
|
11771
|
+
fields.push(field);
|
|
11772
|
+
}
|
|
11773
|
+
});
|
|
11774
|
+
return fields.sort();
|
|
11775
|
+
}
|
|
11776
|
+
|
|
11777
|
+
function getClassifyCullInfo(opts) {
|
|
11778
|
+
if (opts.where || !classifyIsRandomFill(opts)) return null;
|
|
11779
|
+
return {
|
|
11780
|
+
type: 'classify',
|
|
11781
|
+
target: getTargetKey(opts),
|
|
11782
|
+
ids: getIdsKey(opts),
|
|
11783
|
+
key: 'random-fill'
|
|
11784
|
+
};
|
|
11785
|
+
}
|
|
11786
|
+
|
|
11787
|
+
function classifyIsRandomFill(opts) {
|
|
11788
|
+
return opts.colors == 'random' && opts.method == 'non-adjacent' &&
|
|
11789
|
+
!opts.field && !opts.values && !opts['save-as'] && !opts.save_as;
|
|
11790
|
+
}
|
|
11791
|
+
|
|
11792
|
+
function getTargetKey(opts) {
|
|
11793
|
+
return opts.target ? String(opts.target) : '';
|
|
11794
|
+
}
|
|
11795
|
+
|
|
11796
|
+
function getIdsKey(opts) {
|
|
11797
|
+
var ids;
|
|
11798
|
+
if (!opts.ids) return '';
|
|
11799
|
+
if (Array.isArray(opts.ids)) {
|
|
11800
|
+
return opts.ids.concat().sort(function(a, b) {return a - b;}).join(',');
|
|
11801
|
+
}
|
|
11802
|
+
ids = String(opts.ids).split(',').map(Number);
|
|
11803
|
+
if (ids.every(isFinite)) {
|
|
11804
|
+
return ids.sort(function(a, b) {return a - b;}).join(',');
|
|
11805
|
+
}
|
|
11806
|
+
return String(opts.ids);
|
|
11807
|
+
}
|
|
11808
|
+
|
|
11809
|
+
function isSuperset(a, b) {
|
|
11810
|
+
for (var i=0; i<b.length; i++) {
|
|
11811
|
+
if (a.indexOf(b[i]) == -1) return false;
|
|
11812
|
+
}
|
|
11813
|
+
return true;
|
|
11814
|
+
}
|
|
11815
|
+
|
|
11816
|
+
function SessionHistory(gui) {
|
|
11817
|
+
var commands = [];
|
|
11818
|
+
var commandId = 0;
|
|
11819
|
+
// index of first command after the last "save" boundary; commands at indices
|
|
11820
|
+
// [savedAtIndex .. commands.length) are considered unsaved
|
|
11821
|
+
var savedAtIndex = 0;
|
|
11822
|
+
// commands that can be ignored when checking for unsaved changes
|
|
11823
|
+
var nonEditingCommands = 'i,target,info,version,verbose,projections,inspect,help,h,encodings,calc,comment'.split(',');
|
|
11824
|
+
|
|
11825
|
+
this.unsavedChanges = function() {
|
|
11826
|
+
for (var i = commands.length - 1; i >= savedAtIndex; i--) {
|
|
11827
|
+
if (!commandIsActive(commands[i])) continue;
|
|
11828
|
+
var cmdName = getCommandName(getCommandString(commands[i]));
|
|
11829
|
+
if (nonEditingCommands.includes(cmdName)) continue;
|
|
11830
|
+
return true;
|
|
11831
|
+
}
|
|
11832
|
+
return false;
|
|
11833
|
+
};
|
|
11834
|
+
|
|
11835
|
+
this.isEmpty = function() {
|
|
11836
|
+
return getActiveCommands().length === 0;
|
|
11837
|
+
};
|
|
11838
|
+
|
|
11839
|
+
// Mark the current end of the history as a "saved" boundary -- called after
|
|
11840
|
+
// data has been written somewhere durable (e.g. an -o export). Snapshots
|
|
11841
|
+
// are session-scoped and are NOT durable, so creating one does not mark saved.
|
|
11705
11842
|
this.markSaved = function() {
|
|
11706
11843
|
savedAtIndex = commands.length;
|
|
11707
11844
|
};
|
|
@@ -11814,7 +11951,8 @@
|
|
|
11814
11951
|
};
|
|
11815
11952
|
|
|
11816
11953
|
this.toCommandLineString = function() {
|
|
11817
|
-
var str = getActiveCommands().
|
|
11954
|
+
var str = cullCommandHistory(getActiveCommands(), internal.parseCommands,
|
|
11955
|
+
internal.isSupportedSvgStyleProperty).join(' \\\n ');
|
|
11818
11956
|
return 'mapshaper ' + str;
|
|
11819
11957
|
};
|
|
11820
11958
|
|
|
@@ -12551,13 +12689,13 @@
|
|
|
12551
12689
|
var menus = {
|
|
12552
12690
|
standard: ['info', 'selection', 'box'],
|
|
12553
12691
|
empty: ['edit_polygons', 'edit_lines', 'edit_points', 'box'],
|
|
12554
|
-
polygons: ['info', 'selection', 'box', 'edit_polygons'],
|
|
12555
|
-
rectangles: ['info', 'selection', 'box', 'rectangles', 'edit_polygons'],
|
|
12556
|
-
lines: ['info', 'selection', 'box', 'edit_lines'], // 'snip_lines'
|
|
12692
|
+
polygons: ['info', 'selection', 'box', 'polygon_style', 'edit_polygons'],
|
|
12693
|
+
rectangles: ['info', 'selection', 'box', 'polygon_style', 'rectangles', 'edit_polygons'],
|
|
12694
|
+
lines: ['info', 'selection', 'box', 'line_style', 'edit_lines'], // 'snip_lines'
|
|
12557
12695
|
table: ['info', 'selection'],
|
|
12558
12696
|
raster: ['box'],
|
|
12559
|
-
labels: ['info', 'selection', 'box', 'labels', 'edit_points'],
|
|
12560
|
-
points: ['info', 'selection', 'box', 'edit_points'] // , 'add-points'
|
|
12697
|
+
labels: ['info', 'selection', 'box', 'point_style', 'labels', 'edit_points'],
|
|
12698
|
+
points: ['info', 'selection', 'box', 'point_style', 'edit_points'] // , 'add-points'
|
|
12561
12699
|
};
|
|
12562
12700
|
|
|
12563
12701
|
var prompts = {
|
|
@@ -12572,6 +12710,9 @@
|
|
|
12572
12710
|
box: 'rectangle tool',
|
|
12573
12711
|
data: 'edit attributes',
|
|
12574
12712
|
label_style: 'style labels',
|
|
12713
|
+
point_style: 'style points',
|
|
12714
|
+
line_style: 'style lines',
|
|
12715
|
+
polygon_style: 'style polygons',
|
|
12575
12716
|
labels: 'position labels',
|
|
12576
12717
|
edit_points: 'add/drag points',
|
|
12577
12718
|
edit_lines: 'draw/edit polylines',
|
|
@@ -12606,7 +12747,7 @@
|
|
|
12606
12747
|
});
|
|
12607
12748
|
|
|
12608
12749
|
btn.on('mouseenter', function() {
|
|
12609
|
-
if (
|
|
12750
|
+
if (stylePanelIsActive()) return;
|
|
12610
12751
|
btn.addClass('hover');
|
|
12611
12752
|
if (_menuOpen) {
|
|
12612
12753
|
clearTimeout(_menuTimeout); // prevent timed closing
|
|
@@ -12620,7 +12761,7 @@
|
|
|
12620
12761
|
|
|
12621
12762
|
btn.on('click', function(e) {
|
|
12622
12763
|
if (_editMode == 'label_style') {
|
|
12623
|
-
setMode('
|
|
12764
|
+
setMode('off');
|
|
12624
12765
|
closeMenu();
|
|
12625
12766
|
} else if (active()) {
|
|
12626
12767
|
setMode('off');
|
|
@@ -12645,7 +12786,7 @@
|
|
|
12645
12786
|
};
|
|
12646
12787
|
|
|
12647
12788
|
this.modeUsesHitDetection = function(mode) {
|
|
12648
|
-
return ['info', 'selection', 'data', 'label_style', 'labels', 'edit_points', 'vertices', 'rectangles', 'edit_lines', 'edit_polygons', 'snip_lines'].includes(mode);
|
|
12789
|
+
return ['info', 'selection', 'data', 'label_style', 'point_style', 'line_style', 'polygon_style', 'labels', 'edit_points', 'vertices', 'rectangles', 'edit_lines', 'edit_polygons', 'snip_lines'].includes(mode);
|
|
12649
12790
|
};
|
|
12650
12791
|
|
|
12651
12792
|
this.modeUsesPopup = function(mode) {
|
|
@@ -12653,7 +12794,7 @@
|
|
|
12653
12794
|
};
|
|
12654
12795
|
|
|
12655
12796
|
this.modeSupportsUndo = function(mode) {
|
|
12656
|
-
return ['data', 'label_style', 'labels', 'edit_points', 'edit_lines', 'edit_polygons', 'vertices', 'rectangles'].includes(mode);
|
|
12797
|
+
return ['data', 'label_style', 'point_style', 'line_style', 'polygon_style', 'labels', 'edit_points', 'edit_lines', 'edit_polygons', 'vertices', 'rectangles'].includes(mode);
|
|
12657
12798
|
};
|
|
12658
12799
|
|
|
12659
12800
|
this.getMode = getInteractionMode;
|
|
@@ -12677,6 +12818,11 @@
|
|
|
12677
12818
|
return _editMode && _editMode != 'off';
|
|
12678
12819
|
}
|
|
12679
12820
|
|
|
12821
|
+
function stylePanelIsActive() {
|
|
12822
|
+
return _editMode == 'label_style' || _editMode == 'point_style' ||
|
|
12823
|
+
_editMode == 'line_style' || _editMode == 'polygon_style';
|
|
12824
|
+
}
|
|
12825
|
+
|
|
12680
12826
|
function getAvailableModes() {
|
|
12681
12827
|
var o = gui.model.getActiveLayer();
|
|
12682
12828
|
if (!o || !o.layer) {
|
|
@@ -12716,7 +12862,7 @@
|
|
|
12716
12862
|
modes.forEach(function(mode) {
|
|
12717
12863
|
// don't show "turn off" link if not currently editing
|
|
12718
12864
|
if (_editMode == 'off' && mode == 'off') return;
|
|
12719
|
-
var link = El('div').addClass('nav-menu-item').attr('data-name', mode).text(
|
|
12865
|
+
var link = El('div').addClass('nav-menu-item').attr('data-name', mode).text(getModeLabel(mode)).appendTo(menu);
|
|
12720
12866
|
link.on('click', function(e) {
|
|
12721
12867
|
if (_editMode == mode) {
|
|
12722
12868
|
// closeMenu();
|
|
@@ -12732,10 +12878,18 @@
|
|
|
12732
12878
|
updateSelectionHighlight();
|
|
12733
12879
|
}
|
|
12734
12880
|
|
|
12881
|
+
function getModeLabel(mode) {
|
|
12882
|
+
var o = gui.model.getActiveLayer();
|
|
12883
|
+
if (mode == 'point_style' && o && o.layer && internal.layerHasLabels(o.layer)) {
|
|
12884
|
+
return 'style labels';
|
|
12885
|
+
}
|
|
12886
|
+
return labels[mode];
|
|
12887
|
+
}
|
|
12888
|
+
|
|
12735
12889
|
// if current editing mode is not available, turn off the tool
|
|
12736
12890
|
function updateCurrentMode() {
|
|
12737
12891
|
var modes = getAvailableModes();
|
|
12738
|
-
if (modes.indexOf(_editMode) == -1 && !labelStyleModeIsAvailable()) {
|
|
12892
|
+
if (modes.indexOf(_editMode) == -1 && !labelStyleModeIsAvailable() && !layerStyleModeIsAvailable() && !pointStyleModeIsAvailable()) {
|
|
12739
12893
|
setMode('off');
|
|
12740
12894
|
}
|
|
12741
12895
|
}
|
|
@@ -12745,6 +12899,17 @@
|
|
|
12745
12899
|
return _editMode == 'label_style' && o && o.layer && internal.layerHasLabels(o.layer);
|
|
12746
12900
|
}
|
|
12747
12901
|
|
|
12902
|
+
function layerStyleModeIsAvailable() {
|
|
12903
|
+
var o = gui.model.getActiveLayer();
|
|
12904
|
+
return _editMode == 'line_style' && o && o.layer && o.layer.geometry_type == 'polyline' ||
|
|
12905
|
+
_editMode == 'polygon_style' && o && o.layer && o.layer.geometry_type == 'polygon';
|
|
12906
|
+
}
|
|
12907
|
+
|
|
12908
|
+
function pointStyleModeIsAvailable() {
|
|
12909
|
+
var o = gui.model.getActiveLayer();
|
|
12910
|
+
return _editMode == 'point_style' && o && o.layer && o.layer.geometry_type == 'point';
|
|
12911
|
+
}
|
|
12912
|
+
|
|
12748
12913
|
function openMenu() {
|
|
12749
12914
|
clearTimeout(_menuTimeout);
|
|
12750
12915
|
if (!_menuOpen) {
|
|
@@ -12795,7 +12960,7 @@
|
|
|
12795
12960
|
}
|
|
12796
12961
|
btn.classed('hover', _menuOpen);
|
|
12797
12962
|
// btn.classed('selected', active() && !_menuOpen);
|
|
12798
|
-
btn.classed('selected', active()
|
|
12963
|
+
btn.classed('selected', active());
|
|
12799
12964
|
}
|
|
12800
12965
|
|
|
12801
12966
|
function updateSelectionHighlight() {
|
|
@@ -13511,180 +13676,722 @@
|
|
|
13511
13676
|
return Math.round(val * 100) / 100;
|
|
13512
13677
|
}
|
|
13513
13678
|
|
|
13514
|
-
var
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
var fillField = 'fill';
|
|
13520
|
-
var cssField = 'css';
|
|
13521
|
-
var iconField = 'icon';
|
|
13522
|
-
var iconSizeField = 'icon-size';
|
|
13523
|
-
var defaultFontSize = 12;
|
|
13524
|
-
var defaultFontStyle = 'normal';
|
|
13525
|
-
var defaultFontWeight = '400';
|
|
13526
|
-
var defaultLabelColor = '#000000';
|
|
13527
|
-
var defaultIconSize = 5;
|
|
13528
|
-
var labelStyleMode = 'label_style';
|
|
13529
|
-
var labelStylePanelMode = 'label_style_tool';
|
|
13530
|
-
var savedStylesKey = 'label_styles';
|
|
13531
|
-
var labelPositionFields = internal.labelPositionFields;
|
|
13532
|
-
var savedStyleFields = [
|
|
13533
|
-
fontField,
|
|
13534
|
-
fontSizeField,
|
|
13535
|
-
fontStyleField,
|
|
13536
|
-
fontWeightField,
|
|
13537
|
-
fillField,
|
|
13538
|
-
cssField,
|
|
13539
|
-
'label-pos',
|
|
13540
|
-
iconField,
|
|
13541
|
-
iconSizeField
|
|
13679
|
+
var grayscaleColorPresets = [
|
|
13680
|
+
'#000000', '#111111', '#222222', '#333333',
|
|
13681
|
+
'#444444', '#555555', '#666666', '#777777',
|
|
13682
|
+
'#888888', '#999999', '#aaaaaa', '#bbbbbb',
|
|
13683
|
+
'#cccccc', '#dddddd', '#eeeeee', '#ffffff'
|
|
13542
13684
|
];
|
|
13543
|
-
var labelPositions = ['nw', 'n', 'ne', 'w', 'c', 'e', 'sw', 's', 'se'];
|
|
13544
|
-
var iconTypes = [{
|
|
13545
|
-
name: ''
|
|
13546
|
-
}, {
|
|
13547
|
-
name: 'circle'
|
|
13548
|
-
}, {
|
|
13549
|
-
name: 'square'
|
|
13550
|
-
}, {
|
|
13551
|
-
name: 'ring'
|
|
13552
|
-
}, {
|
|
13553
|
-
name: 'star'
|
|
13554
|
-
}];
|
|
13555
|
-
var iconButtonSymbols = {
|
|
13556
|
-
'': '<line x1="4.25" y1="4.25" x2="11.75" y2="11.75"></line><line x1="11.75" y1="4.25" x2="4.25" y2="11.75"></line>',
|
|
13557
|
-
circle: '<circle cx="8" cy="8" r="4.25"></circle>',
|
|
13558
|
-
square: '<rect x="4" y="4" width="8" height="8"></rect>',
|
|
13559
|
-
ring: '<circle cx="8" cy="8" r="3.8"></circle>',
|
|
13560
|
-
star: '<path d="M8 3.2l1.18 2.92 3.14.22-2.42 2 .76 3.06L8 9.75 5.34 11.4l.76-3.06-2.42-2 3.14-.22L8 3.2z"></path>'
|
|
13561
|
-
};
|
|
13562
|
-
|
|
13563
|
-
function LabelTool(gui) {
|
|
13564
|
-
// button is only visible when label editing is available
|
|
13565
|
-
// clicking the button opens a panel for applying styles to labels
|
|
13566
|
-
var textBtn = gui.buttons.addButton('#text-tool-icon').addClass('menu-btn pointer-btn');
|
|
13567
|
-
var parent = gui.container.findChild('.mshp-main-map');
|
|
13568
|
-
var panel = El('div').addClass('label-style-panel rollover').appendTo(parent).hide();
|
|
13569
|
-
var createPanel = El('div').addClass('label-style-panel label-create-panel rollover').appendTo(parent).hide();
|
|
13570
|
-
var createFieldSelect, createExprInput, createCopyCheckbox, createBtn;
|
|
13571
|
-
var styleSelect, fontSelect, fontStyleSelect, fontSizeText, colorChit, colorInput, colorPicker, sbCanvas, hueCanvas, sbMarker, hueMarker, pickerHsbInputs, cssInput, posBtns, iconBtns, iconSizeText, hit;
|
|
13572
|
-
var fontOptionsRendered = false;
|
|
13573
|
-
var pickerColor = {h: 0, s: 0, b: 0};
|
|
13574
|
-
var pendingStyleHistory = null;
|
|
13575
13685
|
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
|
|
13579
|
-
|
|
13580
|
-
|
|
13581
|
-
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
|
|
13587
|
-
|
|
13686
|
+
// Sequential ramps generated in OKLCH for smooth lightness/chroma progression,
|
|
13687
|
+
// then hue-normalized in the picker HSB space so every chip in a ramp reports
|
|
13688
|
+
// the same hue in the color picker.
|
|
13689
|
+
var redRamp = ['#600202', '#8a0303', '#b11b1b', '#cf3b3b', '#e26161', '#ef8b8b', '#f5b8b8', '#fbdede'];
|
|
13690
|
+
var orangeRamp = ['#94551e', '#a85f1e', '#bd6d26', '#d17f36', '#e39652', '#f0b37d', '#f7cda8', '#fce1ca'];
|
|
13691
|
+
var brownRamp = ['#442b03', '#634009', '#825a1b', '#9c763b', '#b39361', '#c8b08b', '#dcceb8', '#eee8df'];
|
|
13692
|
+
var greenRamp = ['#013c06', '#03580b', '#00750b', '#2e9137', '#5daa64', '#8bc190', '#b8d8bb', '#dfebe0'];
|
|
13693
|
+
var tealRamp = ['#023937', '#005350', '#036f6b', '#058d88', '#02aba5', '#65c4c1', '#a7d9d7', '#d7edec'];
|
|
13694
|
+
var blueRamp = ['#013550', '#034d73', '#016599', '#0881bf', '#39a5dd', '#77c2e8', '#aed9ef', '#daedf7'];
|
|
13695
|
+
var indigoRamp = ['#1d2964', '#2d3d8e', '#4053b5', '#596dd1', '#7889e1', '#9ba8eb', '#c0c8f1', '#e1e5f8'];
|
|
13696
|
+
var purpleRamp = ['#431b54', '#612b78', '#7f3f9a', '#9b5cb5', '#b37dc9', '#c8a0d9', '#dcc4e6', '#eee2f3'];
|
|
13697
|
+
|
|
13698
|
+
var layerColorPresetRows = [
|
|
13699
|
+
grayscaleColorPresets,
|
|
13700
|
+
redRamp.concat(orangeRamp),
|
|
13701
|
+
brownRamp.concat(greenRamp),
|
|
13702
|
+
tealRamp.concat(blueRamp),
|
|
13703
|
+
indigoRamp.concat(purpleRamp)
|
|
13704
|
+
];
|
|
13588
13705
|
|
|
13589
|
-
|
|
13590
|
-
|
|
13591
|
-
|
|
13592
|
-
|
|
13593
|
-
|
|
13594
|
-
|
|
13595
|
-
}
|
|
13596
|
-
});
|
|
13597
|
-
}
|
|
13706
|
+
function ColorPicker(parent, opts) {
|
|
13707
|
+
opts = opts || {};
|
|
13708
|
+
var colorPicker = El('div').addClass('label-color-picker').appendTo(parent).hide();
|
|
13709
|
+
var sbCanvas, hueCanvas, sbMarker, hueMarker, pickerHsbInputs;
|
|
13710
|
+
var pickerColor = {h: 0, s: 0, b: 0};
|
|
13711
|
+
var presetRows = opts.presetRows || [grayscaleColorPresets];
|
|
13598
13712
|
|
|
13599
|
-
|
|
13713
|
+
init();
|
|
13600
13714
|
|
|
13601
|
-
function
|
|
13602
|
-
|
|
13603
|
-
|
|
13604
|
-
|
|
13605
|
-
|
|
13715
|
+
this.toggle = function() {
|
|
13716
|
+
if (colorPicker.visible()) {
|
|
13717
|
+
this.hide();
|
|
13718
|
+
} else {
|
|
13719
|
+
colorPicker.show();
|
|
13720
|
+
drawColorPicker();
|
|
13721
|
+
}
|
|
13722
|
+
};
|
|
13606
13723
|
|
|
13607
|
-
|
|
13608
|
-
|
|
13609
|
-
|
|
13724
|
+
this.hide = function() {
|
|
13725
|
+
colorPicker.hide();
|
|
13726
|
+
};
|
|
13610
13727
|
|
|
13611
|
-
|
|
13612
|
-
|
|
13613
|
-
|
|
13614
|
-
if (fontSelect.node().value) {
|
|
13615
|
-
applyFont(fontSelect.node().value);
|
|
13616
|
-
}
|
|
13617
|
-
});
|
|
13728
|
+
this.visible = function() {
|
|
13729
|
+
return colorPicker.visible();
|
|
13730
|
+
};
|
|
13618
13731
|
|
|
13619
|
-
|
|
13620
|
-
|
|
13621
|
-
|
|
13622
|
-
|
|
13623
|
-
|
|
13624
|
-
}
|
|
13625
|
-
});
|
|
13732
|
+
this.setColor = function(color) {
|
|
13733
|
+
if (isHexColor(color)) {
|
|
13734
|
+
setPickerColor(hexToHsb(color));
|
|
13735
|
+
}
|
|
13736
|
+
};
|
|
13626
13737
|
|
|
13627
|
-
|
|
13628
|
-
|
|
13629
|
-
|
|
13630
|
-
colorChit = makePanelButton(colorRow, '', toggleColorPicker).addClass('label-color-chit');
|
|
13631
|
-
colorInput = El('input').attr('type', 'text').appendTo(colorRow).on('change', function() {
|
|
13632
|
-
var color = colorInput.node().value.trim();
|
|
13633
|
-
if (color) {
|
|
13634
|
-
if (isHexColor(color)) {
|
|
13635
|
-
setPickerColor(hexToHsb(color));
|
|
13636
|
-
}
|
|
13637
|
-
applyLabelColor(color);
|
|
13638
|
-
}
|
|
13639
|
-
});
|
|
13640
|
-
initColorPicker(colorRow);
|
|
13738
|
+
this.getColor = function() {
|
|
13739
|
+
return hsbToHex(pickerColor);
|
|
13740
|
+
};
|
|
13641
13741
|
|
|
13642
|
-
|
|
13643
|
-
El('
|
|
13644
|
-
|
|
13645
|
-
|
|
13742
|
+
function init() {
|
|
13743
|
+
var sbWrap = El('div').addClass('label-color-canvas-wrap').appendTo(colorPicker);
|
|
13744
|
+
sbCanvas = El('canvas').attr('width', '256').attr('height', '256').appendTo(sbWrap);
|
|
13745
|
+
sbMarker = makePickerMarker().appendTo(sbWrap);
|
|
13746
|
+
var hueWrap = El('div').addClass('label-color-canvas-wrap').appendTo(colorPicker);
|
|
13747
|
+
hueCanvas = El('canvas').attr('width', '256').attr('height', '18').appendTo(hueWrap);
|
|
13748
|
+
hueMarker = makePickerMarker().appendTo(hueWrap);
|
|
13749
|
+
renderPresetRows(colorPicker);
|
|
13750
|
+
pickerHsbInputs = {};
|
|
13751
|
+
var hsbRow = El('div').addClass('label-color-picker-fields').appendTo(colorPicker);
|
|
13752
|
+
addPickerNumberInput(hsbRow, 'h', 'H');
|
|
13753
|
+
addPickerNumberInput(hsbRow, 's', 'S');
|
|
13754
|
+
addPickerNumberInput(hsbRow, 'b', 'B');
|
|
13755
|
+
El('button').appendTo(hsbRow).text('Close').on('click', function() {
|
|
13756
|
+
colorPicker.hide();
|
|
13646
13757
|
});
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
nudgeFontSize(1);
|
|
13758
|
+
sbCanvas.on('mousedown', function(e) {
|
|
13759
|
+
startCanvasDrag(e, updateSbFromEvent);
|
|
13650
13760
|
});
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
El('span').appendTo(cssRow).text('Inline CSS');
|
|
13654
|
-
cssInput = El('input').attr('type', 'text').appendTo(cssRow).on('change', function() {
|
|
13655
|
-
applyInlineCss(cssInput.node().value.trim());
|
|
13761
|
+
hueCanvas.on('mousedown', function(e) {
|
|
13762
|
+
startCanvasDrag(e, updateHueFromEvent);
|
|
13656
13763
|
});
|
|
13764
|
+
setPickerColor(pickerColor);
|
|
13765
|
+
}
|
|
13657
13766
|
|
|
13658
|
-
|
|
13659
|
-
var
|
|
13660
|
-
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
13664
|
-
|
|
13665
|
-
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
13669
|
-
|
|
13670
|
-
|
|
13767
|
+
function renderPresetRows(parent) {
|
|
13768
|
+
var container = El('div').addClass('label-color-presets').appendTo(parent);
|
|
13769
|
+
presetRows.forEach(function(row) {
|
|
13770
|
+
var rowEl = El('div').addClass('label-color-preset-row').appendTo(container);
|
|
13771
|
+
row.forEach(function(color, i) {
|
|
13772
|
+
var tile = El('div')
|
|
13773
|
+
.addClass('label-color-preset')
|
|
13774
|
+
.attr('role', 'button')
|
|
13775
|
+
.attr('tabindex', '0')
|
|
13776
|
+
.attr('title', color)
|
|
13777
|
+
.appendTo(rowEl)
|
|
13778
|
+
.css('background-color', color);
|
|
13779
|
+
if (row.length == 16 && i == 8) tile.addClass('label-color-preset-group-start');
|
|
13780
|
+
tile.on('click', function() {
|
|
13781
|
+
applyPreset(color);
|
|
13782
|
+
}).on('keydown', function(e) {
|
|
13783
|
+
if (e.key == 'Enter' || e.key == ' ') {
|
|
13784
|
+
e.preventDefault();
|
|
13785
|
+
applyPreset(color);
|
|
13786
|
+
}
|
|
13787
|
+
});
|
|
13788
|
+
});
|
|
13671
13789
|
});
|
|
13790
|
+
}
|
|
13672
13791
|
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
});
|
|
13678
|
-
iconSizeText = El('span').addClass('label-icon-size-value').appendTo(sizeRow);
|
|
13679
|
-
makePanelButton(sizeRow, '+', function() {
|
|
13680
|
-
nudgeIconSize(1);
|
|
13681
|
-
});
|
|
13792
|
+
function applyPreset(color) {
|
|
13793
|
+
setPickerColor(hexToHsb(color));
|
|
13794
|
+
commitPickerColor();
|
|
13795
|
+
}
|
|
13682
13796
|
|
|
13683
|
-
|
|
13684
|
-
El('
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13797
|
+
function addPickerNumberInput(row, name, label) {
|
|
13798
|
+
var wrapper = El('label').appendTo(row);
|
|
13799
|
+
El('span').appendTo(wrapper).text(label);
|
|
13800
|
+
pickerHsbInputs[name] = El('input')
|
|
13801
|
+
.attr('type', 'text')
|
|
13802
|
+
.appendTo(wrapper)
|
|
13803
|
+
.on('change', function() {
|
|
13804
|
+
var h = parseNumberField(pickerHsbInputs.h.node().value);
|
|
13805
|
+
var s = parseNumberField(pickerHsbInputs.s.node().value);
|
|
13806
|
+
var b = parseNumberField(pickerHsbInputs.b.node().value);
|
|
13807
|
+
if (!isFinite(h) || !isFinite(s) || !isFinite(b)) return;
|
|
13808
|
+
setPickerColor({
|
|
13809
|
+
h: degreesToByte(h),
|
|
13810
|
+
s: pctToByte(s),
|
|
13811
|
+
b: pctToByte(b)
|
|
13812
|
+
});
|
|
13813
|
+
commitPickerColor();
|
|
13814
|
+
});
|
|
13815
|
+
}
|
|
13816
|
+
|
|
13817
|
+
function startCanvasDrag(e, update) {
|
|
13818
|
+
var evt = e.originalEvent || e;
|
|
13819
|
+
colorPicker.addClass('dragging-color');
|
|
13820
|
+
El('body').addClass('dragging-color-picker');
|
|
13821
|
+
update(evt);
|
|
13822
|
+
document.addEventListener('mousemove', onmove);
|
|
13823
|
+
document.addEventListener('mouseup', onup);
|
|
13824
|
+
evt.preventDefault();
|
|
13825
|
+
function onmove(evt) {
|
|
13826
|
+
update(evt);
|
|
13827
|
+
}
|
|
13828
|
+
function onup() {
|
|
13829
|
+
document.removeEventListener('mousemove', onmove);
|
|
13830
|
+
document.removeEventListener('mouseup', onup);
|
|
13831
|
+
colorPicker.removeClass('dragging-color');
|
|
13832
|
+
El('body').removeClass('dragging-color-picker');
|
|
13833
|
+
commitPickerColor();
|
|
13834
|
+
}
|
|
13835
|
+
}
|
|
13836
|
+
|
|
13837
|
+
function updateSbFromEvent(evt) {
|
|
13838
|
+
var p = getCanvasPoint(sbCanvas.node(), evt);
|
|
13839
|
+
setPickerColor({
|
|
13840
|
+
h: pickerColor.h,
|
|
13841
|
+
s: p.x,
|
|
13842
|
+
b: 255 - p.y
|
|
13843
|
+
});
|
|
13844
|
+
}
|
|
13845
|
+
|
|
13846
|
+
function updateHueFromEvent(evt) {
|
|
13847
|
+
var p = getCanvasPoint(hueCanvas.node(), evt);
|
|
13848
|
+
setPickerColor({
|
|
13849
|
+
h: p.x,
|
|
13850
|
+
s: pickerColor.s,
|
|
13851
|
+
b: pickerColor.b
|
|
13852
|
+
});
|
|
13853
|
+
}
|
|
13854
|
+
|
|
13855
|
+
function getCanvasPoint(canvas, evt) {
|
|
13856
|
+
var rect = canvas.getBoundingClientRect();
|
|
13857
|
+
return {
|
|
13858
|
+
x: clamp(Math.round((evt.clientX - rect.left) / rect.width * (canvas.width - 1)), 0, canvas.width - 1),
|
|
13859
|
+
y: clamp(Math.round((evt.clientY - rect.top) / rect.height * (canvas.height - 1)), 0, canvas.height - 1)
|
|
13860
|
+
};
|
|
13861
|
+
}
|
|
13862
|
+
|
|
13863
|
+
function setPickerColor(hsb) {
|
|
13864
|
+
pickerColor = {
|
|
13865
|
+
h: clamp(Math.round(hsb.h), 0, 255),
|
|
13866
|
+
s: clamp(Math.round(hsb.s), 0, 255),
|
|
13867
|
+
b: clamp(Math.round(hsb.b), 0, 255)
|
|
13868
|
+
};
|
|
13869
|
+
drawColorPicker();
|
|
13870
|
+
updatePickerFields();
|
|
13871
|
+
if (opts.onPreview) opts.onPreview(hsbToHex(pickerColor));
|
|
13872
|
+
}
|
|
13873
|
+
|
|
13874
|
+
function updatePickerFields() {
|
|
13875
|
+
pickerHsbInputs.h.node().value = byteToDegrees(pickerColor.h) + '°';
|
|
13876
|
+
pickerHsbInputs.s.node().value = byteToPct(pickerColor.s) + '%';
|
|
13877
|
+
pickerHsbInputs.b.node().value = byteToPct(pickerColor.b) + '%';
|
|
13878
|
+
}
|
|
13879
|
+
|
|
13880
|
+
function drawColorPicker() {
|
|
13881
|
+
if (!sbCanvas) return;
|
|
13882
|
+
drawSaturationBrightnessCanvas();
|
|
13883
|
+
drawHueCanvas();
|
|
13884
|
+
}
|
|
13885
|
+
|
|
13886
|
+
function drawSaturationBrightnessCanvas() {
|
|
13887
|
+
var ctx = sbCanvas.node().getContext('2d');
|
|
13888
|
+
var image = ctx.createImageData(256, 256);
|
|
13889
|
+
var data = image.data;
|
|
13890
|
+
var i = 0;
|
|
13891
|
+
for (var y=0; y<256; y++) {
|
|
13892
|
+
for (var x=0; x<256; x++) {
|
|
13893
|
+
var rgb = hsbToRgb({
|
|
13894
|
+
h: pickerColor.h,
|
|
13895
|
+
s: x,
|
|
13896
|
+
b: 255 - y
|
|
13897
|
+
});
|
|
13898
|
+
data[i++] = rgb.r;
|
|
13899
|
+
data[i++] = rgb.g;
|
|
13900
|
+
data[i++] = rgb.b;
|
|
13901
|
+
data[i++] = 255;
|
|
13902
|
+
}
|
|
13903
|
+
}
|
|
13904
|
+
ctx.putImageData(image, 0, 0);
|
|
13905
|
+
positionMarker(sbMarker, pickerColor.s, 255 - pickerColor.b, pickerColor);
|
|
13906
|
+
}
|
|
13907
|
+
|
|
13908
|
+
function drawHueCanvas() {
|
|
13909
|
+
var ctx = hueCanvas.node().getContext('2d');
|
|
13910
|
+
var image = ctx.createImageData(256, 18);
|
|
13911
|
+
var data = image.data;
|
|
13912
|
+
var i = 0;
|
|
13913
|
+
for (var y=0; y<18; y++) {
|
|
13914
|
+
for (var x=0; x<256; x++) {
|
|
13915
|
+
var rgb = hsbToRgb({h: x, s: 255, b: 255});
|
|
13916
|
+
data[i++] = rgb.r;
|
|
13917
|
+
data[i++] = rgb.g;
|
|
13918
|
+
data[i++] = rgb.b;
|
|
13919
|
+
data[i++] = 255;
|
|
13920
|
+
}
|
|
13921
|
+
}
|
|
13922
|
+
ctx.putImageData(image, 0, 0);
|
|
13923
|
+
positionMarker(hueMarker, pickerColor.h, 9, {h: pickerColor.h, s: 255, b: 255});
|
|
13924
|
+
}
|
|
13925
|
+
|
|
13926
|
+
function commitPickerColor() {
|
|
13927
|
+
if (opts.onChange) opts.onChange(hsbToHex(pickerColor));
|
|
13928
|
+
}
|
|
13929
|
+
|
|
13930
|
+
function getMarkerColor(rgb) {
|
|
13931
|
+
var luminance = rgb.r * 0.2126 + rgb.g * 0.7152 + rgb.b * 0.0722;
|
|
13932
|
+
return luminance < 128 ? '#fff' : '#000';
|
|
13933
|
+
}
|
|
13934
|
+
|
|
13935
|
+
function makePickerMarker() {
|
|
13936
|
+
return El('<svg class="label-color-marker" width="16" height="16" viewBox="0 0 16 16"><circle cx="8" cy="8" r="6"></circle></svg>');
|
|
13937
|
+
}
|
|
13938
|
+
|
|
13939
|
+
function positionMarker(marker, x, y, hsb) {
|
|
13940
|
+
var rgb = hsbToRgb(hsb);
|
|
13941
|
+
x = utils$1.clamp(x, 1, 254);
|
|
13942
|
+
y = utils$1.clamp(y, 1, 254) + 0.5;
|
|
13943
|
+
marker.css({
|
|
13944
|
+
left: x - 8,
|
|
13945
|
+
top: y - 8
|
|
13946
|
+
});
|
|
13947
|
+
marker.findChild('circle').attr('stroke', getMarkerColor(rgb));
|
|
13948
|
+
}
|
|
13949
|
+
}
|
|
13950
|
+
|
|
13951
|
+
function isHexColor(str) {
|
|
13952
|
+
return /^#[0-9a-f]{6}$/i.test(str);
|
|
13953
|
+
}
|
|
13954
|
+
|
|
13955
|
+
function hexToHsb(hex) {
|
|
13956
|
+
var r = parseInt(hex.substr(1, 2), 16);
|
|
13957
|
+
var g = parseInt(hex.substr(3, 2), 16);
|
|
13958
|
+
var b = parseInt(hex.substr(5, 2), 16);
|
|
13959
|
+
var max = Math.max(r, g, b);
|
|
13960
|
+
var min = Math.min(r, g, b);
|
|
13961
|
+
var d = max - min;
|
|
13962
|
+
var h = 0;
|
|
13963
|
+
if (d) {
|
|
13964
|
+
if (max == r) h = ((g - b) / d) % 6;
|
|
13965
|
+
else if (max == g) h = (b - r) / d + 2;
|
|
13966
|
+
else h = (r - g) / d + 4;
|
|
13967
|
+
h *= 60;
|
|
13968
|
+
if (h < 0) h += 360;
|
|
13969
|
+
}
|
|
13970
|
+
return {
|
|
13971
|
+
h: Math.round(h / 360 * 255),
|
|
13972
|
+
s: Math.round(max === 0 ? 0 : d / max * 255),
|
|
13973
|
+
b: max
|
|
13974
|
+
};
|
|
13975
|
+
}
|
|
13976
|
+
|
|
13977
|
+
function hsbToHex(hsb) {
|
|
13978
|
+
var rgb = hsbToRgb(hsb);
|
|
13979
|
+
return '#' + [rgb.r, rgb.g, rgb.b].map(function(val) {
|
|
13980
|
+
return val.toString(16).padStart(2, '0');
|
|
13981
|
+
}).join('');
|
|
13982
|
+
}
|
|
13983
|
+
|
|
13984
|
+
function hsbToRgb(hsb) {
|
|
13985
|
+
var h = hsb.h / 255 * 360;
|
|
13986
|
+
var s = hsb.s / 255;
|
|
13987
|
+
var v = hsb.b / 255;
|
|
13988
|
+
var c = v * s;
|
|
13989
|
+
var x = c * (1 - Math.abs((h / 60) % 2 - 1));
|
|
13990
|
+
var m = v - c;
|
|
13991
|
+
var rgb = h < 60 ? [c, x, 0] :
|
|
13992
|
+
h < 120 ? [x, c, 0] :
|
|
13993
|
+
h < 180 ? [0, c, x] :
|
|
13994
|
+
h < 240 ? [0, x, c] :
|
|
13995
|
+
h < 300 ? [x, 0, c] : [c, 0, x];
|
|
13996
|
+
return {
|
|
13997
|
+
r: Math.round((rgb[0] + m) * 255),
|
|
13998
|
+
g: Math.round((rgb[1] + m) * 255),
|
|
13999
|
+
b: Math.round((rgb[2] + m) * 255)
|
|
14000
|
+
};
|
|
14001
|
+
}
|
|
14002
|
+
|
|
14003
|
+
function byteToPct(val) {
|
|
14004
|
+
return Math.round(val / 255 * 100);
|
|
14005
|
+
}
|
|
14006
|
+
|
|
14007
|
+
function pctToByte(val) {
|
|
14008
|
+
return Math.round(clamp(val, 0, 100) / 100 * 255);
|
|
14009
|
+
}
|
|
14010
|
+
|
|
14011
|
+
function byteToDegrees(val) {
|
|
14012
|
+
return Math.round(val / 255 * 360);
|
|
14013
|
+
}
|
|
14014
|
+
|
|
14015
|
+
function degreesToByte(val) {
|
|
14016
|
+
return Math.round(clamp(val, 0, 360) / 360 * 255);
|
|
14017
|
+
}
|
|
14018
|
+
|
|
14019
|
+
function parseNumberField(str) {
|
|
14020
|
+
return Number(String(str).replace(/[°%]/g, '').trim());
|
|
14021
|
+
}
|
|
14022
|
+
|
|
14023
|
+
function clamp(val, min, max) {
|
|
14024
|
+
return isFinite(val) ? Math.max(min, Math.min(max, val)) : min;
|
|
14025
|
+
}
|
|
14026
|
+
|
|
14027
|
+
function makeStylePresetId(styles, prefix, name) {
|
|
14028
|
+
var base = prefix + '-' + makeSlug(name);
|
|
14029
|
+
var ids = (styles || []).reduce(function(memo, item) {
|
|
14030
|
+
if (item && item.id) memo[item.id] = true;
|
|
14031
|
+
if (item && !item.id && item.name) memo[prefix + '-' + makeSlug(item.name)] = true;
|
|
14032
|
+
return memo;
|
|
14033
|
+
}, {});
|
|
14034
|
+
var id = base;
|
|
14035
|
+
var i = 2;
|
|
14036
|
+
while (ids[id]) {
|
|
14037
|
+
id = base + '-' + i++;
|
|
14038
|
+
}
|
|
14039
|
+
return id;
|
|
14040
|
+
}
|
|
14041
|
+
|
|
14042
|
+
function makeSlug(str) {
|
|
14043
|
+
var slug = String(str || '')
|
|
14044
|
+
.toLowerCase()
|
|
14045
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
14046
|
+
.replace(/^-+|-+$/g, '');
|
|
14047
|
+
return slug || 'style';
|
|
14048
|
+
}
|
|
14049
|
+
|
|
14050
|
+
function StylePresetControl(parent, opts) {
|
|
14051
|
+
var row = El('div').addClass('label-style-row label-saved-style-row').appendTo(parent);
|
|
14052
|
+
var select, saveBtn, deleteBtn;
|
|
14053
|
+
|
|
14054
|
+
El('span').appendTo(row).text('Presets');
|
|
14055
|
+
select = El('select').appendTo(row).on('change', function() {
|
|
14056
|
+
var item = findVisibleStyle(select.node().value);
|
|
14057
|
+
if (item) {
|
|
14058
|
+
opts.applyStyle(item.style);
|
|
14059
|
+
}
|
|
14060
|
+
updateControls();
|
|
14061
|
+
});
|
|
14062
|
+
saveBtn = El('button').appendTo(row).text('Save preset').on('click', openSaveStylePopup);
|
|
14063
|
+
deleteBtn = El('button').appendTo(row).text('Delete').on('click', deleteSelectedStyle);
|
|
14064
|
+
render();
|
|
14065
|
+
|
|
14066
|
+
this.render = render;
|
|
14067
|
+
this.update = updateControls;
|
|
14068
|
+
this.clearSelection = clearSelection;
|
|
14069
|
+
this.select = function() {
|
|
14070
|
+
return select;
|
|
14071
|
+
};
|
|
14072
|
+
|
|
14073
|
+
function openSaveStylePopup() {
|
|
14074
|
+
var popup = showPopupAlert('', opts.saveTitle);
|
|
14075
|
+
var el = popup.container();
|
|
14076
|
+
el.addClass('option-menu');
|
|
14077
|
+
el.html(`<div><input type="text" class="style-name text-input" placeholder="style name"></div>
|
|
14078
|
+
<div tabindex="0" class="btn dialog-btn">Save</div>`);
|
|
14079
|
+
var input = el.findChild('.style-name');
|
|
14080
|
+
var btn = el.findChild('.btn');
|
|
14081
|
+
input.node().focus();
|
|
14082
|
+
btn.on('click', function() {
|
|
14083
|
+
var name = input.node().value.trim();
|
|
14084
|
+
if (!name) return;
|
|
14085
|
+
saveStyleWithName(name);
|
|
14086
|
+
popup.close();
|
|
14087
|
+
});
|
|
14088
|
+
input.on('keydown', function(e) {
|
|
14089
|
+
if (e.key == 'Enter') {
|
|
14090
|
+
btn.node().click();
|
|
14091
|
+
}
|
|
14092
|
+
});
|
|
14093
|
+
}
|
|
14094
|
+
|
|
14095
|
+
function saveStyleWithName(name) {
|
|
14096
|
+
var styles = getSavedStyles();
|
|
14097
|
+
var type = getType();
|
|
14098
|
+
var id = makeStylePresetId(styles, type, name);
|
|
14099
|
+
var item = {
|
|
14100
|
+
id: id,
|
|
14101
|
+
name: name,
|
|
14102
|
+
style: opts.getStyle()
|
|
14103
|
+
};
|
|
14104
|
+
if (opts.useType !== false) {
|
|
14105
|
+
item.type = type;
|
|
14106
|
+
}
|
|
14107
|
+
styles.push(item);
|
|
14108
|
+
styles.sort(opts.sort || sortByName);
|
|
14109
|
+
setSavedStyles(styles);
|
|
14110
|
+
render();
|
|
14111
|
+
}
|
|
14112
|
+
|
|
14113
|
+
async function deleteSelectedStyle() {
|
|
14114
|
+
var id = select.node().value;
|
|
14115
|
+
var item = findVisibleStyle(id);
|
|
14116
|
+
var styles;
|
|
14117
|
+
if (!item) return;
|
|
14118
|
+
if (!await showPrompt('Delete ' + opts.styleLabel + ' "' + item.name + '"?', 'Delete preset')) return;
|
|
14119
|
+
styles = getSavedStyles().filter(function(item) {
|
|
14120
|
+
return getItemId(item) != id;
|
|
14121
|
+
});
|
|
14122
|
+
setSavedStyles(styles);
|
|
14123
|
+
render();
|
|
14124
|
+
}
|
|
14125
|
+
|
|
14126
|
+
function render(selectedId) {
|
|
14127
|
+
var styles = getVisibleStyles();
|
|
14128
|
+
var value = selectedId || select.node().value;
|
|
14129
|
+
select.empty();
|
|
14130
|
+
if (styles.length > 0) {
|
|
14131
|
+
El('option').attr('value', '').appendTo(select).text('Apply preset...');
|
|
14132
|
+
styles.forEach(function(item) {
|
|
14133
|
+
El('option').attr('value', getItemId(item)).appendTo(select).text(item.name);
|
|
14134
|
+
});
|
|
14135
|
+
select.node().value = findVisibleStyle(value) ? value : '';
|
|
14136
|
+
} else {
|
|
14137
|
+
El('option').attr('value', '').appendTo(select).text('No presets');
|
|
14138
|
+
select.node().value = '';
|
|
14139
|
+
}
|
|
14140
|
+
updateControls();
|
|
14141
|
+
}
|
|
14142
|
+
|
|
14143
|
+
function updateControls() {
|
|
14144
|
+
var disabled = opts.disabled ? opts.disabled() : false;
|
|
14145
|
+
var hasPresets = getVisibleStyles().length > 0;
|
|
14146
|
+
select.node().disabled = disabled || !hasPresets;
|
|
14147
|
+
saveBtn.node().disabled = disabled;
|
|
14148
|
+
deleteBtn.node().disabled = disabled || !select.node().value;
|
|
14149
|
+
}
|
|
14150
|
+
|
|
14151
|
+
function clearSelection() {
|
|
14152
|
+
if (select.node().value) {
|
|
14153
|
+
select.node().value = '';
|
|
14154
|
+
updateControls();
|
|
14155
|
+
}
|
|
14156
|
+
}
|
|
14157
|
+
|
|
14158
|
+
function getVisibleStyles() {
|
|
14159
|
+
var type = getType();
|
|
14160
|
+
return getSavedStyles().filter(function(item) {
|
|
14161
|
+
return opts.filter ? opts.filter(item, type) : true;
|
|
14162
|
+
});
|
|
14163
|
+
}
|
|
14164
|
+
|
|
14165
|
+
function findVisibleStyle(id) {
|
|
14166
|
+
return getVisibleStyles().find(function(item) {
|
|
14167
|
+
return getItemId(item) == id;
|
|
14168
|
+
});
|
|
14169
|
+
}
|
|
14170
|
+
|
|
14171
|
+
function getSavedStyles() {
|
|
14172
|
+
var styles = GUI.getSavedValue(opts.storageKey);
|
|
14173
|
+
return Array.isArray(styles) ? styles : [];
|
|
14174
|
+
}
|
|
14175
|
+
|
|
14176
|
+
function setSavedStyles(styles) {
|
|
14177
|
+
GUI.setSavedValue(opts.storageKey, styles);
|
|
14178
|
+
}
|
|
14179
|
+
|
|
14180
|
+
function getType() {
|
|
14181
|
+
return typeof opts.type == 'function' ? opts.type() : opts.type;
|
|
14182
|
+
}
|
|
14183
|
+
|
|
14184
|
+
function getItemId(item) {
|
|
14185
|
+
return opts.getItemId ? opts.getItemId(item) : item.id;
|
|
14186
|
+
}
|
|
14187
|
+
}
|
|
14188
|
+
|
|
14189
|
+
function sortByName(a, b) {
|
|
14190
|
+
var aName = String(a.name || '').toLowerCase();
|
|
14191
|
+
var bName = String(b.name || '').toLowerCase();
|
|
14192
|
+
return aName < bName ? -1 : aName > bName ? 1 : 0;
|
|
14193
|
+
}
|
|
14194
|
+
|
|
14195
|
+
function runGuiEditCommand(gui, cmd, optsArg) {
|
|
14196
|
+
var opts = optsArg || {};
|
|
14197
|
+
if (!gui.console) return;
|
|
14198
|
+
gui.console.runMapshaperCommands(cmd, function(err, flags) {
|
|
14199
|
+
if (err) {
|
|
14200
|
+
showPopupAlert(err.message || String(err), opts.title || 'Command error');
|
|
14201
|
+
if (opts.onError) opts.onError(err);
|
|
14202
|
+
} else if (opts.onSuccess) {
|
|
14203
|
+
opts.onSuccess(flags);
|
|
14204
|
+
}
|
|
14205
|
+
if (opts.onDone) {
|
|
14206
|
+
opts.onDone(err, flags);
|
|
14207
|
+
}
|
|
14208
|
+
});
|
|
14209
|
+
}
|
|
14210
|
+
|
|
14211
|
+
var fontField = 'font-family';
|
|
14212
|
+
var fontSizeField = 'font-size';
|
|
14213
|
+
var fontStyleField = 'font-style';
|
|
14214
|
+
var fontWeightField = 'font-weight';
|
|
14215
|
+
var fillField = 'fill';
|
|
14216
|
+
var cssField = 'css';
|
|
14217
|
+
var iconField = 'icon';
|
|
14218
|
+
var iconSizeField = 'icon-size';
|
|
14219
|
+
var defaultFontSize = 12;
|
|
14220
|
+
var defaultFontStyle = 'normal';
|
|
14221
|
+
var defaultFontWeight = '400';
|
|
14222
|
+
var defaultLabelColor = '#000000';
|
|
14223
|
+
var defaultIconSize = 5;
|
|
14224
|
+
var labelStyleMode = 'label_style';
|
|
14225
|
+
var labelStylePanelMode = 'label_style_tool';
|
|
14226
|
+
var savedStylesKey$1 = 'label_styles';
|
|
14227
|
+
var savedStyleFields = [
|
|
14228
|
+
fontField,
|
|
14229
|
+
fontSizeField,
|
|
14230
|
+
fontStyleField,
|
|
14231
|
+
fontWeightField,
|
|
14232
|
+
fillField,
|
|
14233
|
+
cssField,
|
|
14234
|
+
'label-pos',
|
|
14235
|
+
iconField,
|
|
14236
|
+
iconSizeField
|
|
14237
|
+
];
|
|
14238
|
+
var labelPositions = ['nw', 'n', 'ne', 'w', 'c', 'e', 'sw', 's', 'se'];
|
|
14239
|
+
var iconTypes = [{
|
|
14240
|
+
name: ''
|
|
14241
|
+
}, {
|
|
14242
|
+
name: 'circle'
|
|
14243
|
+
}, {
|
|
14244
|
+
name: 'square'
|
|
14245
|
+
}, {
|
|
14246
|
+
name: 'ring'
|
|
14247
|
+
}, {
|
|
14248
|
+
name: 'star'
|
|
14249
|
+
}];
|
|
14250
|
+
var iconButtonSymbols = {
|
|
14251
|
+
'': '<line x1="4.25" y1="4.25" x2="11.75" y2="11.75"></line><line x1="11.75" y1="4.25" x2="4.25" y2="11.75"></line>',
|
|
14252
|
+
circle: '<circle cx="8" cy="8" r="4.25"></circle>',
|
|
14253
|
+
square: '<rect x="4" y="4" width="8" height="8"></rect>',
|
|
14254
|
+
ring: '<circle cx="8" cy="8" r="3.8"></circle>',
|
|
14255
|
+
star: '<path d="M8 3.2l1.18 2.92 3.14.22-2.42 2 .76 3.06L8 9.75 5.34 11.4l.76-3.06-2.42-2 3.14-.22L8 3.2z"></path>'
|
|
14256
|
+
};
|
|
14257
|
+
|
|
14258
|
+
function LabelTool(gui) {
|
|
14259
|
+
// Label styling is opened from the point styling entry point.
|
|
14260
|
+
var textBtn = El('div').hide();
|
|
14261
|
+
var parent = gui.container.findChild('.mshp-main-map');
|
|
14262
|
+
var panel = El('div').addClass('label-style-panel rollover').appendTo(parent).hide();
|
|
14263
|
+
var presetControl, fontSelect, fontStyleSelect, fontSizeText, colorChit, colorInput, colorPicker, cssInput, posBtns, iconBtns, iconSizeText, editingStatus, clearLink, hit;
|
|
14264
|
+
var fontOptionsRendered = false;
|
|
14265
|
+
|
|
14266
|
+
initPanel();
|
|
14267
|
+
gui.addMode(labelStylePanelMode, turnOn, turnOff);
|
|
14268
|
+
gui.model.on('update', updateVisibility);
|
|
14269
|
+
gui.model.on('update', function() {
|
|
14270
|
+
setTimeout(updateSelectionDisplay, 0);
|
|
14271
|
+
});
|
|
14272
|
+
gui.on('undo_redo_post', function() {
|
|
14273
|
+
if (panel.visible()) {
|
|
14274
|
+
updateControls();
|
|
14275
|
+
updateSelectionDisplay();
|
|
14276
|
+
}
|
|
14277
|
+
});
|
|
14278
|
+
gui.on('interaction_mode_change', function(e) {
|
|
14279
|
+
if (panel.visible() && e.mode != labelStyleMode && gui.getMode() == labelStylePanelMode) {
|
|
14280
|
+
gui.clearMode();
|
|
14281
|
+
}
|
|
14282
|
+
});
|
|
14283
|
+
|
|
14284
|
+
hit = gui.map.getHitControl && gui.map.getHitControl();
|
|
14285
|
+
if (hit) {
|
|
14286
|
+
hit.on('change', function(e) {
|
|
14287
|
+
if (e.mode == labelStyleMode) {
|
|
14288
|
+
updateSelectionDisplay();
|
|
14289
|
+
updateControls();
|
|
14290
|
+
}
|
|
14291
|
+
});
|
|
14292
|
+
}
|
|
14293
|
+
|
|
14294
|
+
updateVisibility();
|
|
14295
|
+
|
|
14296
|
+
this.open = function(lyr, dataset) {
|
|
14297
|
+
if (!lyr || !internal.layerHasLabels(lyr)) return;
|
|
14298
|
+
if (!gui.map.isActiveLayer(lyr)) {
|
|
14299
|
+
modelSelectLayer(lyr, dataset);
|
|
14300
|
+
}
|
|
14301
|
+
if (gui.getMode() == labelStylePanelMode) {
|
|
14302
|
+
showStylePanel();
|
|
14303
|
+
} else {
|
|
14304
|
+
gui.enterMode(labelStylePanelMode);
|
|
14305
|
+
}
|
|
14306
|
+
};
|
|
14307
|
+
|
|
14308
|
+
function initPanel() {
|
|
14309
|
+
var header = El('div').addClass('label-style-panel-title').appendTo(panel).text('Label styles');
|
|
14310
|
+
El('button').addClass('label-style-close').appendTo(header).text('×').on('click', function() {
|
|
14311
|
+
gui.clearMode();
|
|
14312
|
+
});
|
|
14313
|
+
|
|
14314
|
+
var selectRow = El('div').addClass('label-style-row label-style-selection-row').appendTo(panel);
|
|
14315
|
+
editingStatus = El('span').addClass('label-editing-status').appendTo(selectRow);
|
|
14316
|
+
clearLink = El('span').addClass('label-editing-clear colored-text').appendTo(selectRow).text('deselect').on('click', clearSelection);
|
|
14317
|
+
|
|
14318
|
+
var fontRow = El('label').addClass('label-style-row').appendTo(panel);
|
|
14319
|
+
El('span').appendTo(fontRow).text('Font');
|
|
14320
|
+
fontSelect = El('select').appendTo(fontRow).on('change', function() {
|
|
14321
|
+
if (fontSelect.node().value) {
|
|
14322
|
+
applyFont(fontSelect.node().value);
|
|
14323
|
+
}
|
|
14324
|
+
});
|
|
14325
|
+
|
|
14326
|
+
var fontStyleRow = El('label').addClass('label-style-row').appendTo(panel);
|
|
14327
|
+
El('span').appendTo(fontStyleRow).text('Font style');
|
|
14328
|
+
fontStyleSelect = El('select').appendTo(fontStyleRow).on('change', function() {
|
|
14329
|
+
if (fontStyleSelect.node().value) {
|
|
14330
|
+
applyFontStyleVariant(fontStyleSelect.node().value);
|
|
14331
|
+
}
|
|
14332
|
+
});
|
|
14333
|
+
|
|
14334
|
+
var colorSizeRow = El('div').addClass('label-style-row label-split-row').appendTo(panel);
|
|
14335
|
+
var colorRow = El('div').addClass('label-split-cell label-color-row').appendTo(colorSizeRow);
|
|
14336
|
+
El('span').appendTo(colorRow).text('Color');
|
|
14337
|
+
colorChit = makePanelButton(colorRow, '', toggleColorPicker).addClass('label-color-chit');
|
|
14338
|
+
colorInput = El('input').attr('type', 'text').appendTo(colorRow).on('change', function() {
|
|
14339
|
+
var color = colorInput.node().value.trim();
|
|
14340
|
+
if (color) {
|
|
14341
|
+
if (isHexColor(color)) {
|
|
14342
|
+
colorPicker.setColor(color);
|
|
14343
|
+
}
|
|
14344
|
+
applyLabelColor(color);
|
|
14345
|
+
}
|
|
14346
|
+
});
|
|
14347
|
+
initColorPicker(colorRow);
|
|
14348
|
+
|
|
14349
|
+
var fontSizeRow = El('div').addClass('label-split-cell label-size-row').appendTo(colorSizeRow);
|
|
14350
|
+
El('span').appendTo(fontSizeRow).text('Font size');
|
|
14351
|
+
makePanelButton(fontSizeRow, '−', function() {
|
|
14352
|
+
nudgeFontSize(-1);
|
|
14353
|
+
});
|
|
14354
|
+
fontSizeText = El('span').addClass('label-size-value').appendTo(fontSizeRow);
|
|
14355
|
+
makePanelButton(fontSizeRow, '+', function() {
|
|
14356
|
+
nudgeFontSize(1);
|
|
14357
|
+
});
|
|
14358
|
+
|
|
14359
|
+
var cssRow = El('label').addClass('label-style-row label-css-row').appendTo(panel);
|
|
14360
|
+
El('span').appendTo(cssRow).text('Inline CSS');
|
|
14361
|
+
cssInput = El('input').attr('type', 'text').appendTo(cssRow).on('change', function() {
|
|
14362
|
+
applyInlineCss(cssInput.node().value.trim());
|
|
14363
|
+
});
|
|
14364
|
+
|
|
14365
|
+
var iconSizeRow = El('div').addClass('label-style-row label-split-row').appendTo(panel);
|
|
14366
|
+
var iconRow = El('div').addClass('label-split-cell').appendTo(iconSizeRow);
|
|
14367
|
+
El('div').addClass('label-style-row-label').appendTo(iconRow).text('Icon');
|
|
14368
|
+
var iconGroup = El('div').addClass('label-icon-buttons').appendTo(iconRow);
|
|
14369
|
+
iconBtns = {};
|
|
14370
|
+
iconTypes.forEach(function(icon) {
|
|
14371
|
+
var btn = makePanelButton(iconGroup, '', function() {
|
|
14372
|
+
applyIcon(icon.name);
|
|
14373
|
+
})
|
|
14374
|
+
.attr('data-icon', icon.name || 'none')
|
|
14375
|
+
.attr('title', icon.name || 'no icon');
|
|
14376
|
+
iconBtns[icon.name] = btn;
|
|
14377
|
+
appendIconButtonSymbol(btn, icon.name);
|
|
14378
|
+
});
|
|
14379
|
+
|
|
14380
|
+
var sizeRow = El('div').addClass('label-split-cell label-icon-size-row').appendTo(iconSizeRow);
|
|
14381
|
+
El('span').appendTo(sizeRow).text('Icon size');
|
|
14382
|
+
makePanelButton(sizeRow, '−', function() {
|
|
14383
|
+
nudgeIconSize(-1);
|
|
14384
|
+
});
|
|
14385
|
+
iconSizeText = El('span').addClass('label-icon-size-value').appendTo(sizeRow);
|
|
14386
|
+
makePanelButton(sizeRow, '+', function() {
|
|
14387
|
+
nudgeIconSize(1);
|
|
14388
|
+
});
|
|
14389
|
+
|
|
14390
|
+
var posRow = El('div').addClass('label-style-row').appendTo(panel);
|
|
14391
|
+
El('div').addClass('label-style-row-label').appendTo(posRow).text('Position');
|
|
14392
|
+
var grid = El('div').addClass('label-position-grid').appendTo(posRow);
|
|
14393
|
+
posBtns = {};
|
|
14394
|
+
labelPositions.forEach(function(pos) {
|
|
13688
14395
|
posBtns[pos] = makePanelButton(grid, '', function() {
|
|
13689
14396
|
applyLabelPosition(pos);
|
|
13690
14397
|
})
|
|
@@ -13692,1108 +14399,1653 @@
|
|
|
13692
14399
|
.attr('title', pos);
|
|
13693
14400
|
});
|
|
13694
14401
|
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
|
|
14402
|
+
presetControl = new StylePresetControl(panel, {
|
|
14403
|
+
storageKey: savedStylesKey$1,
|
|
14404
|
+
type: 'label',
|
|
14405
|
+
useType: false,
|
|
14406
|
+
saveTitle: 'Save label style',
|
|
14407
|
+
styleLabel: 'label style',
|
|
14408
|
+
getStyle: getCurrentStyle,
|
|
14409
|
+
applyStyle: applyStyleObject,
|
|
14410
|
+
getItemId: getStyleId,
|
|
14411
|
+
disabled: function() {
|
|
14412
|
+
return getTargetIds().length === 0;
|
|
13700
14413
|
}
|
|
13701
|
-
updateSavedStyleControls();
|
|
13702
14414
|
});
|
|
13703
|
-
El('button').appendTo(savedRow).text('Save preset').on('click', saveCurrentStyle);
|
|
13704
|
-
El('button').appendTo(savedRow).text('Delete').on('click', deleteSelectedStyle);
|
|
13705
|
-
renderSavedStyles();
|
|
13706
14415
|
}
|
|
13707
14416
|
|
|
13708
|
-
function
|
|
13709
|
-
var
|
|
13710
|
-
|
|
13711
|
-
|
|
13712
|
-
|
|
14417
|
+
function appendIconButtonSymbol(btn, iconName) {
|
|
14418
|
+
var svg = '<svg class="label-icon-symbol" viewBox="0 0 16 16" aria-hidden="true">' +
|
|
14419
|
+
iconButtonSymbols[iconName] + '</svg>';
|
|
14420
|
+
El(svg).appendTo(btn);
|
|
14421
|
+
}
|
|
14422
|
+
|
|
14423
|
+
function makePanelButton(parent, label, action) {
|
|
14424
|
+
return El('div')
|
|
14425
|
+
.addClass('label-panel-btn')
|
|
14426
|
+
.attr('role', 'button')
|
|
14427
|
+
.attr('tabindex', '0')
|
|
14428
|
+
.appendTo(parent)
|
|
14429
|
+
.text(label)
|
|
14430
|
+
.on('click', function(e) {
|
|
14431
|
+
if (this.classList.contains('disabled')) return;
|
|
14432
|
+
action(e);
|
|
14433
|
+
})
|
|
14434
|
+
.on('keydown', function(e) {
|
|
14435
|
+
if (e.key == 'Enter' || e.key == ' ') {
|
|
14436
|
+
e.preventDefault();
|
|
14437
|
+
if (!this.classList.contains('disabled')) action(e);
|
|
14438
|
+
}
|
|
14439
|
+
});
|
|
14440
|
+
}
|
|
14441
|
+
|
|
14442
|
+
function setPanelButtonDisabled(el, disabled) {
|
|
14443
|
+
el.classed('disabled', !!disabled)
|
|
14444
|
+
.attr('aria-disabled', disabled ? 'true' : 'false')
|
|
14445
|
+
.attr('tabindex', disabled ? '-1' : '0');
|
|
14446
|
+
}
|
|
14447
|
+
|
|
14448
|
+
function turnOn() {
|
|
14449
|
+
if (!activeLayerHasLabels()) {
|
|
14450
|
+
gui.clearMode();
|
|
14451
|
+
return;
|
|
14452
|
+
}
|
|
14453
|
+
showStylePanel();
|
|
14454
|
+
}
|
|
14455
|
+
|
|
14456
|
+
function showStylePanel() {
|
|
14457
|
+
renderFontOptions();
|
|
14458
|
+
gui.interaction.setMode(labelStyleMode);
|
|
14459
|
+
gui.state.label_style_panel_open = true;
|
|
14460
|
+
panel.show();
|
|
14461
|
+
textBtn.addClass('selected');
|
|
14462
|
+
updateControls();
|
|
14463
|
+
updateSelectionDisplay();
|
|
14464
|
+
}
|
|
14465
|
+
|
|
14466
|
+
function turnOff() {
|
|
14467
|
+
panel.hide();
|
|
14468
|
+
hideColorPicker();
|
|
14469
|
+
gui.state.label_style_panel_open = false;
|
|
14470
|
+
textBtn.removeClass('selected');
|
|
14471
|
+
clearSelectionDisplay();
|
|
14472
|
+
if (hit) hit.clearSelection();
|
|
14473
|
+
if (gui.interaction.getMode() == labelStyleMode) {
|
|
14474
|
+
gui.interaction.turnOff();
|
|
14475
|
+
}
|
|
14476
|
+
}
|
|
14477
|
+
|
|
14478
|
+
function updateVisibility() {
|
|
14479
|
+
var enabled = activeLayerHasLabels();
|
|
14480
|
+
textBtn.classed('disabled', !enabled);
|
|
14481
|
+
textBtn[enabled ? 'show' : 'hide']();
|
|
14482
|
+
if (!enabled && gui.getMode() == labelStylePanelMode) {
|
|
14483
|
+
gui.clearMode();
|
|
14484
|
+
}
|
|
14485
|
+
}
|
|
14486
|
+
|
|
14487
|
+
function activeLayerHasLabels() {
|
|
14488
|
+
var active = gui.model.getActiveLayer();
|
|
14489
|
+
return !!(active && internal.layerHasLabels(active.layer));
|
|
14490
|
+
}
|
|
14491
|
+
|
|
14492
|
+
function activeLayerIsPointLayer() {
|
|
14493
|
+
var active = gui.model.getActiveLayer();
|
|
14494
|
+
return !!(active && active.layer && active.layer.geometry_type == 'point');
|
|
14495
|
+
}
|
|
14496
|
+
|
|
14497
|
+
function modelSelectLayer(lyr, dataset) {
|
|
14498
|
+
if (lyr) lyr.hidden = false;
|
|
14499
|
+
gui.model.selectLayer(lyr, dataset);
|
|
14500
|
+
}
|
|
14501
|
+
|
|
14502
|
+
function renderFontOptions() {
|
|
14503
|
+
if (fontOptionsRendered) return;
|
|
14504
|
+
fontOptionsRendered = true;
|
|
14505
|
+
fontSelect.empty();
|
|
14506
|
+
El('option').attr('value', '').appendTo(fontSelect).text('');
|
|
14507
|
+
getInstalledFonts().forEach(function(group) {
|
|
14508
|
+
var optgroup = El('optgroup').attr('label', group.name).appendTo(fontSelect);
|
|
14509
|
+
group.fonts.forEach(function(fontName) {
|
|
14510
|
+
El('option').attr('value', fontName).appendTo(optgroup).text(fontName);
|
|
14511
|
+
});
|
|
14512
|
+
});
|
|
14513
|
+
}
|
|
14514
|
+
|
|
14515
|
+
function quoteCommandValue(str) {
|
|
14516
|
+
return "'" + String(str).replace(/'/g, "\\'") + "'";
|
|
14517
|
+
}
|
|
14518
|
+
|
|
14519
|
+
function clearSelection() {
|
|
14520
|
+
if (hit) hit.clearSelection();
|
|
14521
|
+
updateSelectionDisplay();
|
|
14522
|
+
updateControls();
|
|
14523
|
+
}
|
|
14524
|
+
|
|
14525
|
+
function getActiveLayer() {
|
|
14526
|
+
var active = gui.model.getActiveLayer();
|
|
14527
|
+
return active && active.layer;
|
|
14528
|
+
}
|
|
14529
|
+
|
|
14530
|
+
function getActiveTable() {
|
|
14531
|
+
var lyr = getActiveLayer();
|
|
14532
|
+
return lyr && lyr.data || null;
|
|
14533
|
+
}
|
|
14534
|
+
|
|
14535
|
+
function getSelectionIds() {
|
|
14536
|
+
return hit ? hit.getSelectionIds() : [];
|
|
14537
|
+
}
|
|
14538
|
+
|
|
14539
|
+
function getTargetIds() {
|
|
14540
|
+
var ids = getSelectionIds();
|
|
14541
|
+
return ids.length > 0 ? ids : getAllLabelIds();
|
|
14542
|
+
}
|
|
14543
|
+
|
|
14544
|
+
function getAllLabelIds() {
|
|
14545
|
+
var lyr = getActiveLayer();
|
|
14546
|
+
var ids = [];
|
|
14547
|
+
if (!lyr) return ids;
|
|
14548
|
+
for (var i=0, n=internal.getFeatureCount(lyr); i<n; i++) {
|
|
14549
|
+
ids.push(i);
|
|
14550
|
+
}
|
|
14551
|
+
return ids;
|
|
14552
|
+
}
|
|
14553
|
+
|
|
14554
|
+
function updateControls() {
|
|
14555
|
+
var ids = getTargetIds();
|
|
14556
|
+
var manualIds = getSelectionIds();
|
|
14557
|
+
var fontVal = getCommonValue(ids, fontField);
|
|
14558
|
+
var fontSizeVal = getCommonValue(ids, fontSizeField, {useDefault: true, defaultValue: defaultFontSize});
|
|
14559
|
+
var fontStyleVal = getCommonValue(ids, fontStyleField, {useDefault: true, defaultValue: defaultFontStyle});
|
|
14560
|
+
var fontWeightVal = getCommonValue(ids, fontWeightField, {useDefault: true, defaultValue: defaultFontWeight});
|
|
14561
|
+
var fillVal = getCommonValue(ids, fillField, {useDefault: true, defaultValue: defaultLabelColor});
|
|
14562
|
+
var cssVal = getCommonValue(ids, cssField);
|
|
14563
|
+
var posVal = getCommonValue(ids, 'label-pos');
|
|
14564
|
+
var iconVal = getCommonValue(ids, iconField);
|
|
14565
|
+
var iconSizeVal = getCommonValue(ids, iconSizeField, {useDefault: true, defaultValue: defaultIconSize});
|
|
14566
|
+
updateEditingStatus(manualIds.length);
|
|
14567
|
+
updateSavedStyleControls();
|
|
14568
|
+
fontSelect.node().disabled = ids.length === 0;
|
|
14569
|
+
fontSelect.node().value = fontVal;
|
|
14570
|
+
updateFontStyleControls(fontVal, fontStyleVal, fontWeightVal);
|
|
14571
|
+
updateFontSizeControls(ids.length ? fontSizeVal : '');
|
|
14572
|
+
updateColorControls(ids.length ? fillVal : '');
|
|
14573
|
+
updateCssControl(ids.length ? cssVal : '');
|
|
14574
|
+
updatePositionButtons(ids.length ? posVal : '');
|
|
14575
|
+
updateIconButtons(ids.length ? iconVal : '');
|
|
14576
|
+
updateIconSizeControls(ids.length ? iconSizeVal : '');
|
|
14577
|
+
}
|
|
14578
|
+
|
|
14579
|
+
function updatePositionButtons(pos) {
|
|
14580
|
+
var disabled = getTargetIds().length === 0;
|
|
14581
|
+
labelPositions.forEach(function(name) {
|
|
14582
|
+
posBtns[name].classed('selected', name == pos);
|
|
14583
|
+
setPanelButtonDisabled(posBtns[name], disabled);
|
|
14584
|
+
});
|
|
14585
|
+
}
|
|
14586
|
+
|
|
14587
|
+
function updateEditingStatus(count) {
|
|
14588
|
+
editingStatus.text(count > 0 ? 'Editing: ' + count + ' selected' : 'Editing: all');
|
|
14589
|
+
clearLink.classed('hidden', count === 0);
|
|
14590
|
+
}
|
|
14591
|
+
|
|
14592
|
+
function updateFontSizeControls(fontSizeVal) {
|
|
14593
|
+
var disabled = getTargetIds().length === 0;
|
|
14594
|
+
fontSizeText.text(fontSizeVal || '');
|
|
14595
|
+
panel.findChildren('.label-size-row .label-panel-btn').forEach(function(btn) {
|
|
14596
|
+
setPanelButtonDisabled(btn, disabled);
|
|
14597
|
+
});
|
|
14598
|
+
}
|
|
14599
|
+
|
|
14600
|
+
function updateFontStyleControls(fontName, fontStyleVal, fontWeightVal) {
|
|
14601
|
+
var disabled = getTargetIds().length === 0 || !fontName;
|
|
14602
|
+
fontStyleSelect.empty();
|
|
14603
|
+
El('option').attr('value', '').appendTo(fontStyleSelect).text('');
|
|
14604
|
+
if (fontName) {
|
|
14605
|
+
getFontStyleVariants(fontName).forEach(function(variant) {
|
|
14606
|
+
El('option').attr('value', variant.value).appendTo(fontStyleSelect).text(variant.label);
|
|
14607
|
+
});
|
|
14608
|
+
}
|
|
14609
|
+
fontStyleSelect.node().disabled = disabled;
|
|
14610
|
+
fontStyleSelect.node().value = fontStyleVal && fontWeightVal ?
|
|
14611
|
+
fontStyleVal + '|' + fontWeightVal : '';
|
|
14612
|
+
}
|
|
14613
|
+
|
|
14614
|
+
function updateColorControls(colorVal) {
|
|
14615
|
+
var disabled = getTargetIds().length === 0;
|
|
14616
|
+
colorInput.node().disabled = disabled;
|
|
14617
|
+
colorInput.node().value = colorVal || '';
|
|
14618
|
+
setPanelButtonDisabled(colorChit, disabled);
|
|
14619
|
+
colorChit.css('background-color', isHexColor(colorVal) ? colorVal : 'transparent');
|
|
14620
|
+
if (colorPicker.visible()) {
|
|
14621
|
+
return; // avoid HSB -> RGB -> HSB rounding jumps after picker commits
|
|
14622
|
+
}
|
|
14623
|
+
if (isHexColor(colorVal)) {
|
|
14624
|
+
colorPicker.setColor(colorVal);
|
|
14625
|
+
} else {
|
|
14626
|
+
hideColorPicker();
|
|
14627
|
+
}
|
|
14628
|
+
}
|
|
14629
|
+
|
|
14630
|
+
function updateCssControl(cssVal) {
|
|
14631
|
+
cssInput.node().disabled = getTargetIds().length === 0;
|
|
14632
|
+
cssInput.node().value = cssVal || '';
|
|
14633
|
+
}
|
|
14634
|
+
|
|
14635
|
+
function updateIconButtons(iconVal) {
|
|
14636
|
+
var disabled = getTargetIds().length === 0;
|
|
14637
|
+
iconTypes.forEach(function(icon) {
|
|
14638
|
+
iconBtns[icon.name].classed('selected', !disabled && icon.name == iconVal);
|
|
14639
|
+
setPanelButtonDisabled(iconBtns[icon.name], disabled);
|
|
14640
|
+
});
|
|
14641
|
+
}
|
|
14642
|
+
|
|
14643
|
+
function updateIconSizeControls(iconSizeVal) {
|
|
14644
|
+
var disabled = getTargetIds().length === 0;
|
|
14645
|
+
iconSizeText.text(iconSizeVal || '');
|
|
14646
|
+
panel.findChildren('.label-icon-size-row .label-panel-btn').forEach(function(btn) {
|
|
14647
|
+
setPanelButtonDisabled(btn, disabled);
|
|
14648
|
+
});
|
|
14649
|
+
}
|
|
14650
|
+
|
|
14651
|
+
function updateSavedStyleControls() {
|
|
14652
|
+
presetControl.update();
|
|
14653
|
+
}
|
|
13713
14654
|
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
14655
|
+
function getCommonValue(ids, field, opts) {
|
|
14656
|
+
var table = getActiveTable();
|
|
14657
|
+
var records = table && table.getRecords();
|
|
14658
|
+
var value, val, hasValue;
|
|
14659
|
+
if (!records || ids.length === 0) return '';
|
|
14660
|
+
for (var i=0; i<ids.length; i++) {
|
|
14661
|
+
val = records[ids[i]] && records[ids[i]][field];
|
|
14662
|
+
if (!val) {
|
|
14663
|
+
if (opts && opts.useDefault) {
|
|
14664
|
+
val = opts.defaultValue;
|
|
14665
|
+
} else {
|
|
14666
|
+
return '';
|
|
14667
|
+
}
|
|
14668
|
+
} else {
|
|
14669
|
+
hasValue = true;
|
|
13720
14670
|
}
|
|
13721
|
-
|
|
13722
|
-
|
|
14671
|
+
if (i === 0) {
|
|
14672
|
+
value = val;
|
|
14673
|
+
} else if (val != value) {
|
|
14674
|
+
return '';
|
|
14675
|
+
}
|
|
14676
|
+
}
|
|
14677
|
+
return hasValue || opts && opts.useDefault ? value : '';
|
|
14678
|
+
}
|
|
13723
14679
|
|
|
13724
|
-
|
|
13725
|
-
|
|
13726
|
-
|
|
13727
|
-
.attr('type', 'text')
|
|
13728
|
-
.appendTo(exprRow)
|
|
13729
|
-
.on('input', updateCreateButton)
|
|
13730
|
-
.on('change', updateCreateButton);
|
|
14680
|
+
function applyFont(fontName) {
|
|
14681
|
+
applyStyleValues([[fontField, fontName]]);
|
|
14682
|
+
}
|
|
13731
14683
|
|
|
13732
|
-
|
|
13733
|
-
|
|
13734
|
-
|
|
14684
|
+
function nudgeFontSize(delta) {
|
|
14685
|
+
var ids = getTargetIds();
|
|
14686
|
+
var size = getNumericSize(ids, fontSizeField, defaultFontSize);
|
|
14687
|
+
if (ids.length === 0) return;
|
|
14688
|
+
size = Math.max(1, size + delta);
|
|
14689
|
+
applyStyleValues([[fontSizeField, size]]);
|
|
14690
|
+
}
|
|
13735
14691
|
|
|
13736
|
-
|
|
13737
|
-
|
|
14692
|
+
function applyFontStyleVariant(value) {
|
|
14693
|
+
var variant = parseFontStyleVariant(value);
|
|
14694
|
+
if (!variant) return;
|
|
14695
|
+
applyStyleValues([[fontStyleField, variant.style], [fontWeightField, variant.weight]]);
|
|
13738
14696
|
}
|
|
13739
14697
|
|
|
13740
|
-
function
|
|
13741
|
-
|
|
13742
|
-
iconButtonSymbols[iconName] + '</svg>';
|
|
13743
|
-
El(svg).appendTo(btn);
|
|
14698
|
+
function applyLabelColor(color) {
|
|
14699
|
+
applyStyleValues([[fillField, color]]);
|
|
13744
14700
|
}
|
|
13745
14701
|
|
|
13746
|
-
function
|
|
13747
|
-
|
|
13748
|
-
.addClass('label-panel-btn')
|
|
13749
|
-
.attr('role', 'button')
|
|
13750
|
-
.attr('tabindex', '0')
|
|
13751
|
-
.appendTo(parent)
|
|
13752
|
-
.text(label)
|
|
13753
|
-
.on('click', function(e) {
|
|
13754
|
-
if (this.classList.contains('disabled')) return;
|
|
13755
|
-
action(e);
|
|
13756
|
-
})
|
|
13757
|
-
.on('keydown', function(e) {
|
|
13758
|
-
if (e.key == 'Enter' || e.key == ' ') {
|
|
13759
|
-
e.preventDefault();
|
|
13760
|
-
if (!this.classList.contains('disabled')) action(e);
|
|
13761
|
-
}
|
|
13762
|
-
});
|
|
14702
|
+
function applyInlineCss(css) {
|
|
14703
|
+
applyStyleValues([[cssField, css || '']]);
|
|
13763
14704
|
}
|
|
13764
14705
|
|
|
13765
|
-
function
|
|
13766
|
-
|
|
13767
|
-
.attr('aria-disabled', disabled ? 'true' : 'false')
|
|
13768
|
-
.attr('tabindex', disabled ? '-1' : '0');
|
|
14706
|
+
function getStyleId(item) {
|
|
14707
|
+
return item.id || 'label-' + item.name;
|
|
13769
14708
|
}
|
|
13770
14709
|
|
|
13771
|
-
function
|
|
13772
|
-
|
|
13773
|
-
|
|
13774
|
-
|
|
14710
|
+
function getCurrentStyle() {
|
|
14711
|
+
var style = {};
|
|
14712
|
+
var fontStyle = parseFontStyleVariant(fontStyleSelect.node().value);
|
|
14713
|
+
var icon = getSelectedIcon();
|
|
14714
|
+
addStyleValue(style, fontField, fontSelect.node().value);
|
|
14715
|
+
if (fontStyle) {
|
|
14716
|
+
style[fontStyleField] = fontStyle.style;
|
|
14717
|
+
style[fontWeightField] = fontStyle.weight;
|
|
13775
14718
|
}
|
|
13776
|
-
|
|
13777
|
-
|
|
13778
|
-
|
|
14719
|
+
addStyleValue(style, fontSizeField, getNumericControlValue(fontSizeText));
|
|
14720
|
+
addStyleValue(style, fillField, colorInput.node().value.trim());
|
|
14721
|
+
addStyleValue(style, cssField, cssInput.node().value.trim());
|
|
14722
|
+
addStyleValue(style, 'label-pos', getSelectedLabelPosition());
|
|
14723
|
+
addStyleValue(style, iconField, icon);
|
|
14724
|
+
if (icon) {
|
|
14725
|
+
addStyleValue(style, iconSizeField, getNumericControlValue(iconSizeText));
|
|
13779
14726
|
}
|
|
13780
|
-
|
|
14727
|
+
return style;
|
|
13781
14728
|
}
|
|
13782
14729
|
|
|
13783
|
-
function
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
gui.state.label_style_panel_open = true;
|
|
13788
|
-
panel.show();
|
|
13789
|
-
textBtn.addClass('selected');
|
|
13790
|
-
updateControls();
|
|
13791
|
-
updateSelectionDisplay();
|
|
14730
|
+
function addStyleValue(style, field, value) {
|
|
14731
|
+
if (value || value === 0) {
|
|
14732
|
+
style[field] = value;
|
|
14733
|
+
}
|
|
13792
14734
|
}
|
|
13793
14735
|
|
|
13794
|
-
function
|
|
13795
|
-
|
|
13796
|
-
|
|
13797
|
-
if (gui.interaction.getMode() == labelStyleMode) {
|
|
13798
|
-
gui.interaction.turnOff();
|
|
13799
|
-
}
|
|
13800
|
-
gui.state.label_style_panel_open = true;
|
|
13801
|
-
createPanel.show();
|
|
13802
|
-
textBtn.addClass('selected');
|
|
13803
|
-
renderCreateFields();
|
|
13804
|
-
updateCreateButton();
|
|
14736
|
+
function getNumericControlValue(el) {
|
|
14737
|
+
var value = Number(el.text());
|
|
14738
|
+
return isFinite(value) && value > 0 ? value : null;
|
|
13805
14739
|
}
|
|
13806
14740
|
|
|
13807
|
-
function
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
|
|
13812
|
-
|
|
13813
|
-
hideColorPicker();
|
|
13814
|
-
gui.state.label_style_panel_open = false;
|
|
13815
|
-
textBtn.removeClass('selected');
|
|
13816
|
-
clearSelectionDisplay();
|
|
13817
|
-
if (hit) hit.clearSelection();
|
|
13818
|
-
if (gui.interaction.getMode() == labelStyleMode) {
|
|
13819
|
-
gui.interaction.turnOff();
|
|
13820
|
-
}
|
|
14741
|
+
function getSelectedLabelPosition() {
|
|
14742
|
+
var out = '';
|
|
14743
|
+
labelPositions.forEach(function(pos) {
|
|
14744
|
+
if (posBtns[pos].hasClass('selected')) out = pos;
|
|
14745
|
+
});
|
|
14746
|
+
return out;
|
|
13821
14747
|
}
|
|
13822
14748
|
|
|
13823
|
-
function
|
|
13824
|
-
var
|
|
13825
|
-
|
|
13826
|
-
|
|
13827
|
-
|
|
13828
|
-
|
|
14749
|
+
function getSelectedIcon() {
|
|
14750
|
+
var out = '';
|
|
14751
|
+
iconTypes.forEach(function(icon) {
|
|
14752
|
+
if (iconBtns[icon.name].hasClass('selected')) out = icon.name;
|
|
14753
|
+
});
|
|
14754
|
+
return out;
|
|
14755
|
+
}
|
|
14756
|
+
|
|
14757
|
+
function applyStyleObject(style) {
|
|
14758
|
+
var styles = [];
|
|
14759
|
+
savedStyleFields.forEach(function(field) {
|
|
14760
|
+
if (field in style) {
|
|
14761
|
+
styles.push([field, style[field]]);
|
|
14762
|
+
}
|
|
14763
|
+
});
|
|
14764
|
+
applyStyleValues(styles, {preservePreset: true});
|
|
14765
|
+
}
|
|
14766
|
+
|
|
14767
|
+
function parseFontStyleVariant(value) {
|
|
14768
|
+
var parts = String(value).split('|');
|
|
14769
|
+
if (parts.length != 2) return null;
|
|
14770
|
+
return {
|
|
14771
|
+
style: parts[0],
|
|
14772
|
+
weight: parts[1]
|
|
14773
|
+
};
|
|
14774
|
+
}
|
|
14775
|
+
|
|
14776
|
+
function applyLabelPosition(pos) {
|
|
14777
|
+
applyStyleValues([['label-pos', pos]]);
|
|
14778
|
+
}
|
|
14779
|
+
|
|
14780
|
+
function applyIcon(iconName) {
|
|
14781
|
+
var styles = [[iconField, iconName || '']];
|
|
14782
|
+
if (iconName) {
|
|
14783
|
+
styles.push([iconSizeField, getNumericSize(getTargetIds(), iconSizeField, defaultIconSize)]);
|
|
14784
|
+
} else {
|
|
14785
|
+
styles.push([iconSizeField, 0]);
|
|
13829
14786
|
}
|
|
14787
|
+
applyStyleValues(styles);
|
|
13830
14788
|
}
|
|
13831
14789
|
|
|
13832
|
-
function
|
|
13833
|
-
var
|
|
13834
|
-
|
|
14790
|
+
function nudgeIconSize(delta) {
|
|
14791
|
+
var ids = getTargetIds();
|
|
14792
|
+
var size = getNumericSize(ids, iconSizeField, defaultIconSize);
|
|
14793
|
+
if (ids.length === 0) return;
|
|
14794
|
+
size = Math.max(1, size + delta);
|
|
14795
|
+
applyStyleValues([[iconField, getCommonValue(ids, iconField) || 'circle'], [iconSizeField, size]]);
|
|
13835
14796
|
}
|
|
13836
14797
|
|
|
13837
|
-
function
|
|
13838
|
-
var
|
|
13839
|
-
|
|
14798
|
+
function getNumericSize(ids, field, defaultValue) {
|
|
14799
|
+
var val = getCommonValue(ids, field);
|
|
14800
|
+
val = val ? Number(val) : defaultValue;
|
|
14801
|
+
return isFinite(val) && val > 0 ? val : defaultValue;
|
|
13840
14802
|
}
|
|
13841
14803
|
|
|
13842
|
-
function
|
|
13843
|
-
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13849
|
-
group.fonts.forEach(function(fontName) {
|
|
13850
|
-
El('option').attr('value', fontName).appendTo(optgroup).text(fontName);
|
|
13851
|
-
});
|
|
14804
|
+
function initColorPicker(colorRow) {
|
|
14805
|
+
colorPicker = new ColorPicker(colorRow, {
|
|
14806
|
+
onPreview: function(hex) {
|
|
14807
|
+
colorInput.node().value = hex;
|
|
14808
|
+
colorChit.css('background-color', hex);
|
|
14809
|
+
},
|
|
14810
|
+
onChange: applyLabelColor
|
|
13852
14811
|
});
|
|
13853
14812
|
}
|
|
13854
14813
|
|
|
13855
|
-
function
|
|
14814
|
+
function toggleColorPicker() {
|
|
14815
|
+
colorPicker.toggle();
|
|
14816
|
+
}
|
|
14817
|
+
|
|
14818
|
+
function hideColorPicker() {
|
|
14819
|
+
colorPicker.hide();
|
|
14820
|
+
}
|
|
14821
|
+
|
|
14822
|
+
function applyStyleValues(styles, opts) {
|
|
13856
14823
|
var lyr = getActiveLayer();
|
|
13857
|
-
var
|
|
13858
|
-
var
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
14824
|
+
var ids = getTargetIds();
|
|
14825
|
+
var parts = ['-style'];
|
|
14826
|
+
if (!gui.console || !lyr || ids.length === 0 || styles.length === 0) return;
|
|
14827
|
+
if (!opts || !opts.preservePreset) {
|
|
14828
|
+
presetControl.clearSelection();
|
|
14829
|
+
}
|
|
14830
|
+
styles.forEach(function(style) {
|
|
14831
|
+
parts.push(style[0] + '=' + quoteCommandValue(style[1]));
|
|
14832
|
+
});
|
|
14833
|
+
if (ids.length < internal.getFeatureCount(lyr)) {
|
|
14834
|
+
parts.push('ids=' + ids.join(','));
|
|
14835
|
+
}
|
|
14836
|
+
runGuiEditCommand(gui, parts.join(' '), {
|
|
14837
|
+
title: 'Label styles',
|
|
14838
|
+
onDone: function() {
|
|
14839
|
+
setTimeout(updateSelectionDisplay, 0);
|
|
14840
|
+
updateControls();
|
|
14841
|
+
updateSelectionDisplay();
|
|
14842
|
+
}
|
|
13866
14843
|
});
|
|
13867
|
-
createFieldSelect.node().disabled = fields.length === 0;
|
|
13868
|
-
createFieldSelect.node().value = fields.indexOf(value) > -1 ? value : '';
|
|
13869
14844
|
}
|
|
13870
14845
|
|
|
13871
|
-
function
|
|
13872
|
-
|
|
14846
|
+
function updateSelectionDisplay() {
|
|
14847
|
+
clearSelectionDisplay();
|
|
14848
|
+
getSelectionIds().forEach(function(id) {
|
|
14849
|
+
var textNode = getTextNodeById(id);
|
|
14850
|
+
if (textNode) {
|
|
14851
|
+
textNode.classList.add('label-style-selected');
|
|
14852
|
+
}
|
|
14853
|
+
});
|
|
13873
14854
|
}
|
|
13874
14855
|
|
|
13875
|
-
function
|
|
13876
|
-
|
|
14856
|
+
function clearSelectionDisplay() {
|
|
14857
|
+
var lyr = hit && hit.getHitTarget();
|
|
14858
|
+
var container = lyr && lyr.gui && lyr.gui.svg_container;
|
|
14859
|
+
if (!container) return;
|
|
14860
|
+
container.querySelectorAll('.label-style-selected').forEach(function(node) {
|
|
14861
|
+
node.classList.remove('label-style-selected');
|
|
14862
|
+
});
|
|
13877
14863
|
}
|
|
13878
14864
|
|
|
13879
|
-
function
|
|
13880
|
-
var
|
|
13881
|
-
var
|
|
13882
|
-
var
|
|
13883
|
-
|
|
13884
|
-
|
|
13885
|
-
if (!srcLyr || srcLyr.geometry_type != 'point' || !expr) return;
|
|
13886
|
-
lyr = createCopyCheckbox.node().checked ? makeLabelLayerCopy(srcLyr, dataset) : srcLyr;
|
|
13887
|
-
if (!applyLabelText(lyr, expr)) return;
|
|
13888
|
-
if (lyr != srcLyr) {
|
|
13889
|
-
addLabelLayerCopy(lyr, srcLyr, dataset);
|
|
13890
|
-
recordCreateLabelsCommand(expr, lyr);
|
|
13891
|
-
selectLabelLayerCopy(lyr, dataset);
|
|
13892
|
-
} else {
|
|
13893
|
-
gui.model.updated({style: true, same_table: true});
|
|
13894
|
-
recordCreateLabelsCommand(expr);
|
|
13895
|
-
}
|
|
13896
|
-
showStylePanel();
|
|
13897
|
-
setTimeout(function() {
|
|
13898
|
-
selectAllLabels();
|
|
13899
|
-
}, 0);
|
|
14865
|
+
function getTextNodeById(id) {
|
|
14866
|
+
var lyr = hit && hit.getHitTarget();
|
|
14867
|
+
var container = lyr && lyr.gui && lyr.gui.svg_container;
|
|
14868
|
+
var symbol = container && container.querySelector('[data-id="' + id + '"]');
|
|
14869
|
+
if (!symbol) return null;
|
|
14870
|
+
return symbol.tagName == 'text' ? symbol : symbol.querySelector('text');
|
|
13900
14871
|
}
|
|
13901
14872
|
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
|
|
13906
|
-
return lyr;
|
|
13907
|
-
}
|
|
14873
|
+
}
|
|
14874
|
+
|
|
14875
|
+
var savedStylesKey = 'layer_style_presets';
|
|
14876
|
+
var styleFields = ['stroke', 'stroke-width', 'stroke-opacity', 'fill', 'fill-opacity'];
|
|
13908
14877
|
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
|
|
13912
|
-
|
|
13913
|
-
|
|
13914
|
-
}
|
|
14878
|
+
function LayerStyleTool(gui) {
|
|
14879
|
+
var parent = gui.container.findChild('.mshp-main-map');
|
|
14880
|
+
var panel = El('div').addClass('label-style-panel layer-style-panel rollover').appendTo(parent).hide();
|
|
14881
|
+
var title, editingStatus, clearLink, strokeControl, fillControl, strokeWidthText, strokeWidthClickText, strokeOpacityInput, fillOpacityInput, randomFillBtn, presetControl, hit;
|
|
14882
|
+
var targetLayer = null;
|
|
13915
14883
|
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
14884
|
+
initPanel();
|
|
14885
|
+
hit = gui.map.getHitControl && gui.map.getHitControl();
|
|
14886
|
+
if (hit) {
|
|
14887
|
+
hit.on('change', function(e) {
|
|
14888
|
+
if (targetLayer && (e.mode == 'line_style' || e.mode == 'polygon_style')) {
|
|
14889
|
+
updateControls();
|
|
14890
|
+
}
|
|
14891
|
+
});
|
|
13919
14892
|
}
|
|
13920
14893
|
|
|
13921
|
-
function
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
var accessor;
|
|
13926
|
-
try {
|
|
13927
|
-
accessor = internal.getSymbolPropertyAccessor(expr, labelTextField, lyr);
|
|
13928
|
-
} catch(e) {
|
|
13929
|
-
showPopupAlert(e.message || 'Invalid label expression', 'Create labels');
|
|
13930
|
-
return false;
|
|
13931
|
-
}
|
|
13932
|
-
if (hasField) {
|
|
13933
|
-
table.captureFieldsBefore([labelTextField], {operation: 'create-labels'});
|
|
13934
|
-
} else {
|
|
13935
|
-
table.captureSchemaBefore({operation: 'create-labels', fields: [labelTextField]});
|
|
14894
|
+
this.open = function(lyr, dataset) {
|
|
14895
|
+
if (!layerCanBeStyled(lyr)) return;
|
|
14896
|
+
if (!gui.map.isActiveLayer(lyr)) {
|
|
14897
|
+
modelSelectLayer(lyr, dataset);
|
|
13936
14898
|
}
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
13941
|
-
if (
|
|
13942
|
-
|
|
14899
|
+
gui.interaction.setMode(lyr.geometry_type == 'polygon' ? 'polygon_style' : 'line_style');
|
|
14900
|
+
};
|
|
14901
|
+
|
|
14902
|
+
gui.on('interaction_mode_change', function(e) {
|
|
14903
|
+
if (modeMatchesActiveLayer(e.mode)) {
|
|
14904
|
+
turnOn();
|
|
13943
14905
|
} else {
|
|
13944
|
-
|
|
14906
|
+
turnOff();
|
|
13945
14907
|
}
|
|
13946
|
-
|
|
13947
|
-
}
|
|
14908
|
+
});
|
|
13948
14909
|
|
|
13949
|
-
|
|
13950
|
-
if (
|
|
13951
|
-
|
|
13952
|
-
|
|
13953
|
-
|
|
14910
|
+
gui.model.on('update', function() {
|
|
14911
|
+
if (panel.visible() && !modeMatchesActiveLayer(gui.interaction.getMode())) {
|
|
14912
|
+
gui.interaction.turnOff();
|
|
14913
|
+
} else if (panel.visible()) {
|
|
14914
|
+
updateControls();
|
|
13954
14915
|
}
|
|
13955
|
-
|
|
13956
|
-
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
|
|
13960
|
-
};
|
|
14916
|
+
});
|
|
14917
|
+
|
|
14918
|
+
gui.on('undo_redo_post', function() {
|
|
14919
|
+
if (panel.visible()) {
|
|
14920
|
+
updateControls();
|
|
13961
14921
|
}
|
|
13962
|
-
|
|
13963
|
-
|
|
13964
|
-
|
|
13965
|
-
|
|
13966
|
-
|
|
14922
|
+
});
|
|
14923
|
+
|
|
14924
|
+
function turnOn() {
|
|
14925
|
+
targetLayer = getActiveLayer();
|
|
14926
|
+
applyDefaultLineStyle();
|
|
14927
|
+
panel.show();
|
|
14928
|
+
updateControls();
|
|
13967
14929
|
}
|
|
13968
14930
|
|
|
13969
|
-
function
|
|
13970
|
-
|
|
13971
|
-
|
|
13972
|
-
|
|
13973
|
-
|
|
13974
|
-
if (cmd) {
|
|
13975
|
-
gui.session.consoleCommands(cmd);
|
|
13976
|
-
}
|
|
14931
|
+
function turnOff() {
|
|
14932
|
+
panel.hide();
|
|
14933
|
+
strokeControl.picker.hide();
|
|
14934
|
+
fillControl.picker.hide();
|
|
14935
|
+
targetLayer = null;
|
|
13977
14936
|
}
|
|
13978
14937
|
|
|
13979
|
-
function
|
|
13980
|
-
var
|
|
13981
|
-
|
|
13982
|
-
|
|
13983
|
-
|
|
14938
|
+
function initPanel() {
|
|
14939
|
+
var header = El('div').addClass('label-style-panel-title').appendTo(panel);
|
|
14940
|
+
title = El('span').appendTo(header);
|
|
14941
|
+
El('button').addClass('label-style-close').appendTo(header).text('×').on('click', closePanel);
|
|
14942
|
+
|
|
14943
|
+
var editRow = El('div').addClass('label-style-row label-style-selection-row layer-style-selection-row').appendTo(panel);
|
|
14944
|
+
editingStatus = El('span').addClass('label-editing-status').appendTo(editRow);
|
|
14945
|
+
clearLink = El('span').addClass('label-editing-clear colored-text').appendTo(editRow).text('deselect').on('click', clearSelection);
|
|
14946
|
+
|
|
14947
|
+
fillControl = addColorControl(panel, 'Fill', 'fill', '');
|
|
14948
|
+
fillOpacityInput = addStyleNumberControl(fillControl, 'Opacity', 'fill-opacity', {
|
|
14949
|
+
defaultValue: 1,
|
|
14950
|
+
parser: parseOpacityValue,
|
|
14951
|
+
formatter: formatOpacityPct
|
|
13984
14952
|
});
|
|
13985
|
-
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
|
|
13990
|
-
|
|
14953
|
+
strokeControl = addColorControl(panel, 'Stroke', 'stroke', '#000000');
|
|
14954
|
+
strokeOpacityInput = addStyleNumberControl(strokeControl, 'Opacity', 'stroke-opacity', {
|
|
14955
|
+
defaultValue: 1,
|
|
14956
|
+
parser: parseOpacityValue,
|
|
14957
|
+
formatter: formatOpacityPct
|
|
14958
|
+
});
|
|
14959
|
+
strokeWidthText = addStrokeWidthControl(panel);
|
|
14960
|
+
|
|
14961
|
+
var buttonRow = El('div').addClass('label-style-row').appendTo(panel);
|
|
14962
|
+
randomFillBtn = El('button').appendTo(buttonRow).text('Random fills').on('click', applyRandomFillColors);
|
|
14963
|
+
El('button').appendTo(buttonRow).text('Clear style').on('click', clearLayerStyle);
|
|
14964
|
+
|
|
14965
|
+
presetControl = new StylePresetControl(panel, {
|
|
14966
|
+
storageKey: savedStylesKey,
|
|
14967
|
+
type: getStyleType,
|
|
14968
|
+
saveTitle: 'Save layer style',
|
|
14969
|
+
styleLabel: 'layer style',
|
|
14970
|
+
getStyle: getCurrentStyle,
|
|
14971
|
+
applyStyle: applyStyleObject,
|
|
14972
|
+
filter: function(item, type) {
|
|
14973
|
+
return item.type == type;
|
|
14974
|
+
},
|
|
14975
|
+
sort: function(a, b) {
|
|
14976
|
+
return getSortKey(a) < getSortKey(b) ? -1 :
|
|
14977
|
+
getSortKey(a) > getSortKey(b) ? 1 : 0;
|
|
14978
|
+
}
|
|
13991
14979
|
});
|
|
13992
|
-
if (parts.length == 1) return '';
|
|
13993
|
-
if (getActiveLayer() != entry.layer) {
|
|
13994
|
-
parts.push('target=' + internal.formatOptionValue(internal.getLayerTargetId(gui.model, entry.layer)));
|
|
13995
|
-
}
|
|
13996
|
-
if (entry.ids.length < internal.getFeatureCount(entry.layer)) {
|
|
13997
|
-
parts.push('where=' + quoteCommandValue(getIdsWhereExpression(entry.ids)));
|
|
13998
|
-
}
|
|
13999
|
-
return parts.join(' ');
|
|
14000
14980
|
}
|
|
14001
14981
|
|
|
14002
|
-
function
|
|
14003
|
-
|
|
14004
|
-
|
|
14005
|
-
|
|
14006
|
-
|
|
14982
|
+
function addColorControl(parent, label, field, defaultColor) {
|
|
14983
|
+
var row = El('div').addClass('label-style-row label-color-row layer-color-row').appendTo(parent);
|
|
14984
|
+
var control = {
|
|
14985
|
+
field: field,
|
|
14986
|
+
defaultColor: defaultColor,
|
|
14987
|
+
row: row,
|
|
14988
|
+
chit: null,
|
|
14989
|
+
input: null,
|
|
14990
|
+
controls: null,
|
|
14991
|
+
picker: null
|
|
14992
|
+
};
|
|
14993
|
+
var controlLine = El('div').addClass('layer-style-control-line').appendTo(row);
|
|
14994
|
+
var colorCell = El('div').addClass('layer-color-cell').appendTo(controlLine);
|
|
14995
|
+
control.controls = El('div').addClass('layer-row-controls').appendTo(controlLine);
|
|
14996
|
+
El('span').appendTo(colorCell).text(label);
|
|
14997
|
+
control.chit = makePanelButton(colorCell, '', function() {
|
|
14998
|
+
control.picker.toggle();
|
|
14999
|
+
}).addClass('label-color-chit');
|
|
15000
|
+
control.input = El('input').attr('type', 'text').appendTo(colorCell).on('change', function() {
|
|
15001
|
+
var color = control.input.node().value.trim();
|
|
15002
|
+
if (!color) return;
|
|
15003
|
+
if (isHexColor(color)) {
|
|
15004
|
+
control.picker.setColor(color);
|
|
14007
15005
|
}
|
|
14008
|
-
|
|
14009
|
-
}
|
|
15006
|
+
applyColorControlStyle(control, color);
|
|
15007
|
+
});
|
|
15008
|
+
control.picker = new ColorPicker(row, {
|
|
15009
|
+
presetRows: layerColorPresetRows,
|
|
15010
|
+
onPreview: function(hex) {
|
|
15011
|
+
setColorControlValue(control, hex);
|
|
15012
|
+
},
|
|
15013
|
+
onChange: function(hex) {
|
|
15014
|
+
applyColorControlStyle(control, hex);
|
|
15015
|
+
}
|
|
15016
|
+
});
|
|
15017
|
+
return control;
|
|
14010
15018
|
}
|
|
14011
15019
|
|
|
14012
|
-
function
|
|
14013
|
-
var
|
|
14014
|
-
|
|
14015
|
-
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
|
|
14019
|
-
|
|
15020
|
+
function addStrokeWidthControl(parent) {
|
|
15021
|
+
var row = El('div').addClass('label-style-row layer-stroke-width-row').appendTo(parent);
|
|
15022
|
+
var control = El('div').addClass('layer-number-control layer-stroke-width-control').appendTo(row);
|
|
15023
|
+
var buttonRow;
|
|
15024
|
+
El('span').appendTo(control).text('Stroke width');
|
|
15025
|
+
buttonRow = El('div').addClass('layer-stepper-control').appendTo(control);
|
|
15026
|
+
makePanelButton(buttonRow, '−', function() {
|
|
15027
|
+
nudgeStrokeWidth(-1);
|
|
15028
|
+
});
|
|
15029
|
+
var text = El('span').addClass('layer-stroke-width-value').appendTo(buttonRow);
|
|
15030
|
+
strokeWidthClickText = new ClickText2(text);
|
|
15031
|
+
strokeWidthClickText.on('change', function() {
|
|
15032
|
+
var value = parsePositiveNumber(strokeWidthClickText.value());
|
|
15033
|
+
if (value === null) {
|
|
15034
|
+
updateStrokeWidthControl();
|
|
15035
|
+
return;
|
|
14020
15036
|
}
|
|
14021
|
-
|
|
14022
|
-
|
|
15037
|
+
applyStrokeWidthStyle(value);
|
|
15038
|
+
});
|
|
15039
|
+
makePanelButton(buttonRow, '+', function() {
|
|
15040
|
+
nudgeStrokeWidth(1);
|
|
15041
|
+
});
|
|
15042
|
+
return text;
|
|
14023
15043
|
}
|
|
14024
15044
|
|
|
14025
|
-
function
|
|
14026
|
-
var
|
|
14027
|
-
|
|
14028
|
-
|
|
14029
|
-
|
|
14030
|
-
|
|
14031
|
-
|
|
15045
|
+
function addStyleNumberControl(colorControl, label, field, opts) {
|
|
15046
|
+
var control = El('label').addClass('layer-number-control').appendTo(colorControl.controls);
|
|
15047
|
+
El('span').appendTo(control).text(label);
|
|
15048
|
+
return El('input')
|
|
15049
|
+
.attr('type', 'text')
|
|
15050
|
+
.appendTo(control)
|
|
15051
|
+
.on('change', function() {
|
|
15052
|
+
var value = opts.parser(this.value);
|
|
15053
|
+
if (value === null) return;
|
|
15054
|
+
applyLayerStyle(field, value);
|
|
15055
|
+
});
|
|
14032
15056
|
}
|
|
14033
15057
|
|
|
14034
|
-
function
|
|
14035
|
-
return
|
|
15058
|
+
function makePanelButton(parent, label, action) {
|
|
15059
|
+
return El('div')
|
|
15060
|
+
.addClass('label-panel-btn')
|
|
15061
|
+
.attr('role', 'button')
|
|
15062
|
+
.attr('tabindex', '0')
|
|
15063
|
+
.appendTo(parent)
|
|
15064
|
+
.text(label)
|
|
15065
|
+
.on('click', function(e) {
|
|
15066
|
+
action(e);
|
|
15067
|
+
})
|
|
15068
|
+
.on('keydown', function(e) {
|
|
15069
|
+
if (e.key == 'Enter' || e.key == ' ') {
|
|
15070
|
+
e.preventDefault();
|
|
15071
|
+
action(e);
|
|
15072
|
+
}
|
|
15073
|
+
});
|
|
14036
15074
|
}
|
|
14037
15075
|
|
|
14038
|
-
function
|
|
14039
|
-
|
|
14040
|
-
|
|
14041
|
-
|
|
14042
|
-
|
|
14043
|
-
|
|
15076
|
+
function updateControls() {
|
|
15077
|
+
syncTargetLayer();
|
|
15078
|
+
var geom = targetLayer && targetLayer.geometry_type;
|
|
15079
|
+
var manualIds = getSelectionIds();
|
|
15080
|
+
if (!targetLayer) return;
|
|
15081
|
+
title.text(geom == 'polygon' ? 'Polygon styles' : 'Line styles');
|
|
15082
|
+
updateEditingStatus(manualIds.length);
|
|
15083
|
+
strokeControl.row.show();
|
|
15084
|
+
fillControl.row.classed('hidden', geom != 'polygon');
|
|
15085
|
+
updateColorControl(strokeControl);
|
|
15086
|
+
updateColorControl(fillControl);
|
|
15087
|
+
updateStrokeWidthControl();
|
|
15088
|
+
updateNumberControl(strokeOpacityInput, 'stroke-opacity', 1, formatOpacityPct);
|
|
15089
|
+
updateNumberControl(fillOpacityInput, 'fill-opacity', 1, formatOpacityPct);
|
|
15090
|
+
randomFillBtn.classed('hidden', geom != 'polygon');
|
|
15091
|
+
presetControl.render();
|
|
15092
|
+
updateSavedStyleControls();
|
|
14044
15093
|
}
|
|
14045
15094
|
|
|
14046
|
-
function
|
|
14047
|
-
var
|
|
14048
|
-
|
|
14049
|
-
if (
|
|
14050
|
-
|
|
15095
|
+
function updateColorControl(control) {
|
|
15096
|
+
var value = getCommonStyleValue(control.field);
|
|
15097
|
+
setColorControlValue(control, value);
|
|
15098
|
+
if (isHexColor(value)) {
|
|
15099
|
+
control.picker.setColor(value);
|
|
15100
|
+
} else {
|
|
15101
|
+
control.picker.hide();
|
|
14051
15102
|
}
|
|
14052
|
-
cmd += '-style label-text=' + quoteCommandValue(expr);
|
|
14053
|
-
gui.session.consoleCommands(cmd);
|
|
14054
15103
|
}
|
|
14055
15104
|
|
|
14056
|
-
function
|
|
14057
|
-
|
|
15105
|
+
function setColorControlValue(control, value) {
|
|
15106
|
+
control.input.node().value = value || '';
|
|
15107
|
+
control.chit.css('background-color', isHexColor(value) ? value : 'transparent');
|
|
14058
15108
|
}
|
|
14059
15109
|
|
|
14060
|
-
function
|
|
14061
|
-
var
|
|
14062
|
-
|
|
14063
|
-
|
|
14064
|
-
|
|
14065
|
-
|
|
15110
|
+
function updateNumberControl(input, field, defaultValue, formatter) {
|
|
15111
|
+
var value = getCommonStyleValue(field);
|
|
15112
|
+
input.node().value = formatter(value === '' || value === undefined || value === null ? defaultValue : value);
|
|
15113
|
+
}
|
|
15114
|
+
|
|
15115
|
+
function updateStrokeWidthControl() {
|
|
15116
|
+
var value = getCommonStyleValue('stroke-width');
|
|
15117
|
+
strokeWidthClickText.value(formatNumberValue(value === '' || value === undefined || value === null ? getDefaultStrokeWidth() : value));
|
|
15118
|
+
}
|
|
15119
|
+
|
|
15120
|
+
function nudgeStrokeWidth(direction) {
|
|
15121
|
+
var value = Number(getCommonStyleValue('stroke-width'));
|
|
15122
|
+
if (!isFinite(value)) value = getDefaultStrokeWidth();
|
|
15123
|
+
applyStrokeWidthStyle(getNextStrokeWidth(value, direction));
|
|
15124
|
+
}
|
|
15125
|
+
|
|
15126
|
+
function getNextStrokeWidth(value, direction) {
|
|
15127
|
+
var baseSteps = [0, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4];
|
|
15128
|
+
var i;
|
|
15129
|
+
if (direction > 0) {
|
|
15130
|
+
for (i=0; i<baseSteps.length; i++) {
|
|
15131
|
+
if (value < baseSteps[i]) return baseSteps[i];
|
|
15132
|
+
}
|
|
15133
|
+
return Math.floor(value) + 1;
|
|
14066
15134
|
}
|
|
14067
|
-
|
|
14068
|
-
|
|
14069
|
-
hit.addSelectionIds(ids);
|
|
15135
|
+
for (i=baseSteps.length - 1; i>=0; i--) {
|
|
15136
|
+
if (value > baseSteps[i]) return baseSteps[i];
|
|
14070
15137
|
}
|
|
14071
|
-
|
|
14072
|
-
updateControls();
|
|
15138
|
+
return baseSteps[0];
|
|
14073
15139
|
}
|
|
14074
15140
|
|
|
14075
|
-
function
|
|
14076
|
-
|
|
14077
|
-
updateSelectionDisplay();
|
|
14078
|
-
updateControls();
|
|
15141
|
+
function applyLayerStyle(field, value) {
|
|
15142
|
+
runStyleCommand([[field, value]]);
|
|
14079
15143
|
}
|
|
14080
15144
|
|
|
14081
|
-
function
|
|
14082
|
-
var
|
|
14083
|
-
|
|
15145
|
+
function applyColorControlStyle(control, color) {
|
|
15146
|
+
var styles = [[control.field, color]];
|
|
15147
|
+
if (control.field == 'stroke' && strokeWidthIsUnsetForTargets()) {
|
|
15148
|
+
styles.push(['stroke-width', 1]);
|
|
15149
|
+
}
|
|
15150
|
+
runStyleCommand(styles);
|
|
14084
15151
|
}
|
|
14085
15152
|
|
|
14086
|
-
function
|
|
14087
|
-
var
|
|
14088
|
-
|
|
15153
|
+
function applyStrokeWidthStyle(value) {
|
|
15154
|
+
var styles = [['stroke-width', value]];
|
|
15155
|
+
if (value > 0 && styleFieldIsUnsetForTargets('stroke')) {
|
|
15156
|
+
styles.push(['stroke', strokeControl.defaultColor]);
|
|
15157
|
+
}
|
|
15158
|
+
runStyleCommand(styles);
|
|
14089
15159
|
}
|
|
14090
15160
|
|
|
14091
|
-
function
|
|
14092
|
-
|
|
15161
|
+
function runStyleCommand(styles, opts) {
|
|
15162
|
+
var parts = ['-style'];
|
|
15163
|
+
syncTargetLayer();
|
|
15164
|
+
var ids = getTargetIds();
|
|
15165
|
+
if (!gui.console || !targetLayer || ids.length === 0) return;
|
|
15166
|
+
if (!opts || !opts.preservePreset) {
|
|
15167
|
+
presetControl.clearSelection();
|
|
15168
|
+
}
|
|
15169
|
+
styles.forEach(function(style) {
|
|
15170
|
+
parts.push(style[0] + '=' + quoteCommandValue(style[1]));
|
|
15171
|
+
});
|
|
15172
|
+
addTargetOption(parts);
|
|
15173
|
+
if (ids.length < internal.getFeatureCount(targetLayer)) {
|
|
15174
|
+
parts.push('ids=' + ids.join(','));
|
|
15175
|
+
}
|
|
15176
|
+
runCommand(parts.join(' '), 'Style layer');
|
|
14093
15177
|
}
|
|
14094
15178
|
|
|
14095
|
-
function
|
|
14096
|
-
var
|
|
14097
|
-
|
|
14098
|
-
|
|
14099
|
-
|
|
14100
|
-
|
|
14101
|
-
|
|
14102
|
-
|
|
14103
|
-
|
|
14104
|
-
var iconVal = getCommonValue(ids, iconField);
|
|
14105
|
-
var iconSizeVal = getCommonValue(ids, iconSizeField, {useDefault: true, defaultValue: defaultIconSize});
|
|
14106
|
-
styleSelect.node().disabled = ids.length === 0;
|
|
14107
|
-
updateSavedStyleControls();
|
|
14108
|
-
fontSelect.node().disabled = ids.length === 0;
|
|
14109
|
-
fontSelect.node().value = fontVal;
|
|
14110
|
-
updateFontStyleControls(fontVal, fontStyleVal, fontWeightVal);
|
|
14111
|
-
updateFontSizeControls(ids.length ? fontSizeVal : '');
|
|
14112
|
-
updateColorControls(ids.length ? fillVal : '');
|
|
14113
|
-
updateCssControl(ids.length ? cssVal : '');
|
|
14114
|
-
updatePositionButtons(ids.length ? posVal : '');
|
|
14115
|
-
updateIconButtons(ids.length ? iconVal : '');
|
|
14116
|
-
updateIconSizeControls(ids.length ? iconSizeVal : '');
|
|
15179
|
+
function applyDefaultLineStyle() {
|
|
15180
|
+
var styles = [];
|
|
15181
|
+
if (!targetLayer || targetLayer.geometry_type != 'polyline') return;
|
|
15182
|
+
if (styleFieldIsUnsetForTargets('stroke-width')) {
|
|
15183
|
+
styles.push(['stroke-width', 1]);
|
|
15184
|
+
}
|
|
15185
|
+
if (styles.length > 0) {
|
|
15186
|
+
runStyleCommand(styles);
|
|
15187
|
+
}
|
|
14117
15188
|
}
|
|
14118
15189
|
|
|
14119
|
-
function
|
|
14120
|
-
var
|
|
14121
|
-
|
|
14122
|
-
|
|
14123
|
-
|
|
14124
|
-
|
|
15190
|
+
function applyRandomFillColors() {
|
|
15191
|
+
var cmd = '-classify colors=random non-adjacent';
|
|
15192
|
+
syncTargetLayer();
|
|
15193
|
+
if (!gui.console || !targetLayer || targetLayer.geometry_type != 'polygon') return;
|
|
15194
|
+
if (getActiveLayer() != targetLayer) {
|
|
15195
|
+
cmd += ' target=' + internal.formatOptionValue(internal.getLayerTargetId(gui.model, targetLayer));
|
|
15196
|
+
}
|
|
15197
|
+
presetControl.clearSelection();
|
|
15198
|
+
runCommand(cmd, 'Random fill colors');
|
|
14125
15199
|
}
|
|
14126
15200
|
|
|
14127
|
-
function
|
|
14128
|
-
|
|
14129
|
-
|
|
14130
|
-
|
|
14131
|
-
setPanelButtonDisabled(btn, disabled);
|
|
15201
|
+
function runCommand(cmd, title) {
|
|
15202
|
+
runGuiEditCommand(gui, cmd, {
|
|
15203
|
+
title: title,
|
|
15204
|
+
onDone: updateControls
|
|
14132
15205
|
});
|
|
14133
15206
|
}
|
|
14134
15207
|
|
|
14135
|
-
function
|
|
14136
|
-
var
|
|
14137
|
-
|
|
14138
|
-
|
|
14139
|
-
|
|
14140
|
-
|
|
14141
|
-
|
|
14142
|
-
|
|
15208
|
+
function applyStyleObject(style) {
|
|
15209
|
+
var styles = [];
|
|
15210
|
+
styleFields.forEach(function(field) {
|
|
15211
|
+
if (field in style) {
|
|
15212
|
+
styles.push([field, style[field]]);
|
|
15213
|
+
}
|
|
15214
|
+
});
|
|
15215
|
+
if (styles.length > 0) {
|
|
15216
|
+
runStyleCommand(styles, {preservePreset: true});
|
|
14143
15217
|
}
|
|
14144
|
-
fontStyleSelect.node().disabled = disabled;
|
|
14145
|
-
fontStyleSelect.node().value = fontStyleVal && fontWeightVal ?
|
|
14146
|
-
fontStyleVal + '|' + fontWeightVal : '';
|
|
14147
15218
|
}
|
|
14148
15219
|
|
|
14149
|
-
function
|
|
14150
|
-
var
|
|
14151
|
-
|
|
14152
|
-
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
|
|
14156
|
-
|
|
15220
|
+
function getCurrentStyle() {
|
|
15221
|
+
var style = {};
|
|
15222
|
+
addStyleValue(style, 'stroke', getControlValue(strokeControl.input));
|
|
15223
|
+
addStyleValue(style, 'stroke-width', parsePositiveNumber(strokeWidthClickText.value()));
|
|
15224
|
+
addStyleValue(style, 'stroke-opacity', parseOpacityValue(strokeOpacityInput.node().value));
|
|
15225
|
+
if (targetLayer && targetLayer.geometry_type == 'polygon') {
|
|
15226
|
+
addStyleValue(style, 'fill', getControlValue(fillControl.input));
|
|
15227
|
+
addStyleValue(style, 'fill-opacity', parseOpacityValue(fillOpacityInput.node().value));
|
|
14157
15228
|
}
|
|
14158
|
-
|
|
14159
|
-
|
|
14160
|
-
|
|
14161
|
-
|
|
15229
|
+
return style;
|
|
15230
|
+
}
|
|
15231
|
+
|
|
15232
|
+
function addStyleValue(style, field, value) {
|
|
15233
|
+
if (value || value === 0) {
|
|
15234
|
+
style[field] = value;
|
|
14162
15235
|
}
|
|
14163
15236
|
}
|
|
14164
15237
|
|
|
14165
|
-
function
|
|
14166
|
-
|
|
14167
|
-
cssInput.node().value = cssVal || '';
|
|
15238
|
+
function getControlValue(input) {
|
|
15239
|
+
return input.node().value.trim();
|
|
14168
15240
|
}
|
|
14169
15241
|
|
|
14170
|
-
function
|
|
14171
|
-
|
|
14172
|
-
iconTypes.forEach(function(icon) {
|
|
14173
|
-
iconBtns[icon.name].classed('selected', !disabled && icon.name == iconVal);
|
|
14174
|
-
setPanelButtonDisabled(iconBtns[icon.name], disabled);
|
|
14175
|
-
});
|
|
15242
|
+
function updateSavedStyleControls() {
|
|
15243
|
+
presetControl.update();
|
|
14176
15244
|
}
|
|
14177
15245
|
|
|
14178
|
-
function
|
|
14179
|
-
|
|
14180
|
-
iconSizeText.text(iconSizeVal || '');
|
|
14181
|
-
panel.findChildren('.label-icon-size-row .label-panel-btn').forEach(function(btn) {
|
|
14182
|
-
setPanelButtonDisabled(btn, disabled);
|
|
14183
|
-
});
|
|
15246
|
+
function getStyleType() {
|
|
15247
|
+
return targetLayer && targetLayer.geometry_type == 'polygon' ? 'polygon' : 'line';
|
|
14184
15248
|
}
|
|
14185
15249
|
|
|
14186
|
-
function
|
|
14187
|
-
|
|
14188
|
-
var buttons = panel.findChildren('.label-saved-style-row button');
|
|
14189
|
-
buttons.forEach(function(btn, i) {
|
|
14190
|
-
btn.node().disabled = i === 0 ? disabled : disabled || !styleSelect.node().value;
|
|
14191
|
-
});
|
|
15250
|
+
function getSortKey(item) {
|
|
15251
|
+
return (item.type || '') + '\t' + String(item.name || '').toLowerCase() + '\t' + (item.id || '');
|
|
14192
15252
|
}
|
|
14193
15253
|
|
|
14194
|
-
function
|
|
14195
|
-
var
|
|
14196
|
-
|
|
14197
|
-
|
|
14198
|
-
|
|
15254
|
+
function clearLayerStyle() {
|
|
15255
|
+
var parts = ['-style clear'];
|
|
15256
|
+
syncTargetLayer();
|
|
15257
|
+
if (!gui.console || !targetLayer) return;
|
|
15258
|
+
presetControl.clearSelection();
|
|
15259
|
+
addTargetOption(parts);
|
|
15260
|
+
runCommand(parts.join(' '), 'Clear style');
|
|
15261
|
+
}
|
|
15262
|
+
|
|
15263
|
+
function addTargetOption(parts) {
|
|
15264
|
+
if (getActiveLayer() != targetLayer) {
|
|
15265
|
+
parts.push('target=' + internal.formatOptionValue(internal.getLayerTargetId(gui.model, targetLayer)));
|
|
15266
|
+
}
|
|
15267
|
+
}
|
|
15268
|
+
|
|
15269
|
+
function getCommonStyleValue(field, idsArg) {
|
|
15270
|
+
var records = targetLayer && targetLayer.data && targetLayer.data.getRecords();
|
|
15271
|
+
var ids;
|
|
15272
|
+
var value, val;
|
|
15273
|
+
if (!records) return '';
|
|
15274
|
+
ids = idsArg || getTargetIds();
|
|
15275
|
+
if (ids.length === 0) return '';
|
|
14199
15276
|
for (var i=0; i<ids.length; i++) {
|
|
14200
15277
|
val = records[ids[i]] && records[ids[i]][field];
|
|
14201
|
-
if (!val) {
|
|
14202
|
-
if (opts && opts.useDefault) {
|
|
14203
|
-
val = opts.defaultValue;
|
|
14204
|
-
} else {
|
|
14205
|
-
return '';
|
|
14206
|
-
}
|
|
14207
|
-
} else {
|
|
14208
|
-
hasValue = true;
|
|
14209
|
-
}
|
|
14210
15278
|
if (i === 0) {
|
|
14211
15279
|
value = val;
|
|
14212
15280
|
} else if (val != value) {
|
|
14213
15281
|
return '';
|
|
14214
15282
|
}
|
|
14215
15283
|
}
|
|
14216
|
-
return
|
|
15284
|
+
return value;
|
|
15285
|
+
}
|
|
15286
|
+
|
|
15287
|
+
function strokeWidthIsUnsetForTargets() {
|
|
15288
|
+
return styleFieldIsUnsetForTargets('stroke-width');
|
|
15289
|
+
}
|
|
15290
|
+
|
|
15291
|
+
function styleFieldIsUnsetForTargets(field) {
|
|
15292
|
+
var records = targetLayer && targetLayer.data && targetLayer.data.getRecords();
|
|
15293
|
+
var ids = getTargetIds();
|
|
15294
|
+
var val;
|
|
15295
|
+
if (!records) return true;
|
|
15296
|
+
for (var i=0; i<ids.length; i++) {
|
|
15297
|
+
val = records[ids[i]] && records[ids[i]][field];
|
|
15298
|
+
if (val !== undefined && val !== null && val !== '') {
|
|
15299
|
+
return false;
|
|
15300
|
+
}
|
|
15301
|
+
}
|
|
15302
|
+
return ids.length > 0;
|
|
15303
|
+
}
|
|
15304
|
+
|
|
15305
|
+
function getDefaultStrokeWidth() {
|
|
15306
|
+
return targetLayer && targetLayer.geometry_type == 'polyline' ? 1 : 0;
|
|
15307
|
+
}
|
|
15308
|
+
|
|
15309
|
+
function getAllFeatureIds(lyr) {
|
|
15310
|
+
var ids = [];
|
|
15311
|
+
for (var i=0, n=internal.getFeatureCount(lyr); i<n; i++) {
|
|
15312
|
+
ids.push(i);
|
|
15313
|
+
}
|
|
15314
|
+
return ids;
|
|
14217
15315
|
}
|
|
14218
15316
|
|
|
14219
|
-
function
|
|
14220
|
-
|
|
14221
|
-
rec[fontField] = fontName;
|
|
14222
|
-
});
|
|
15317
|
+
function getSelectionIds() {
|
|
15318
|
+
return hit ? hit.getSelectionIds() : [];
|
|
14223
15319
|
}
|
|
14224
15320
|
|
|
14225
|
-
function
|
|
15321
|
+
function getTargetIds() {
|
|
14226
15322
|
var ids = getSelectionIds();
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
size = Math.max(1, size + delta);
|
|
14230
|
-
applyStyleFields([fontSizeField], function(rec) {
|
|
14231
|
-
rec[fontSizeField] = size;
|
|
14232
|
-
});
|
|
15323
|
+
if (!targetLayer) return [];
|
|
15324
|
+
return ids.length > 0 ? ids : getAllFeatureIds(targetLayer);
|
|
14233
15325
|
}
|
|
14234
15326
|
|
|
14235
|
-
function
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
applyStyleFields([fontStyleField, fontWeightField], function(rec) {
|
|
14239
|
-
rec[fontStyleField] = variant.style;
|
|
14240
|
-
rec[fontWeightField] = variant.weight;
|
|
14241
|
-
});
|
|
15327
|
+
function clearSelection() {
|
|
15328
|
+
if (hit) hit.clearSelection();
|
|
15329
|
+
updateControls();
|
|
14242
15330
|
}
|
|
14243
15331
|
|
|
14244
|
-
function
|
|
14245
|
-
|
|
14246
|
-
|
|
14247
|
-
});
|
|
15332
|
+
function updateEditingStatus(count) {
|
|
15333
|
+
editingStatus.text(count > 0 ? 'Editing: ' + count + ' selected' : 'Editing: all');
|
|
15334
|
+
clearLink.classed('hidden', count === 0);
|
|
14248
15335
|
}
|
|
14249
15336
|
|
|
14250
|
-
function
|
|
14251
|
-
|
|
14252
|
-
|
|
14253
|
-
});
|
|
15337
|
+
function getActiveLayer() {
|
|
15338
|
+
var active = gui.model.getActiveLayer();
|
|
15339
|
+
return active && active.layer;
|
|
14254
15340
|
}
|
|
14255
15341
|
|
|
14256
|
-
function
|
|
14257
|
-
|
|
15342
|
+
function syncTargetLayer() {
|
|
15343
|
+
var lyr = getActiveLayer();
|
|
15344
|
+
if (lyr == targetLayer) return;
|
|
15345
|
+
if (layerCanBeStyled(lyr)) {
|
|
15346
|
+
targetLayer = lyr;
|
|
15347
|
+
if (hit) hit.clearSelection();
|
|
15348
|
+
} else {
|
|
15349
|
+
targetLayer = null;
|
|
15350
|
+
}
|
|
14258
15351
|
}
|
|
14259
15352
|
|
|
14260
|
-
function
|
|
14261
|
-
|
|
14262
|
-
|
|
14263
|
-
|
|
14264
|
-
|
|
14265
|
-
<div tabindex="0" class="btn dialog-btn">Save</div>`);
|
|
14266
|
-
var input = el.findChild('.style-name');
|
|
14267
|
-
var btn = el.findChild('.btn');
|
|
14268
|
-
input.node().focus();
|
|
14269
|
-
btn.on('click', function() {
|
|
14270
|
-
var name = input.node().value.trim();
|
|
14271
|
-
if (!name) return;
|
|
14272
|
-
saveStyleWithName(name);
|
|
14273
|
-
popup.close();
|
|
14274
|
-
});
|
|
14275
|
-
input.on('keydown', function(e) {
|
|
14276
|
-
if (e.key == 'Enter') {
|
|
14277
|
-
btn.node().click();
|
|
14278
|
-
}
|
|
14279
|
-
});
|
|
15353
|
+
function closePanel() {
|
|
15354
|
+
turnOff();
|
|
15355
|
+
if (gui.interaction.getMode() == 'line_style' || gui.interaction.getMode() == 'polygon_style') {
|
|
15356
|
+
gui.interaction.turnOff();
|
|
15357
|
+
}
|
|
14280
15358
|
}
|
|
14281
15359
|
|
|
14282
|
-
function
|
|
14283
|
-
|
|
14284
|
-
return item.name != name;
|
|
14285
|
-
});
|
|
14286
|
-
var i;
|
|
14287
|
-
styles.push({
|
|
14288
|
-
name: name,
|
|
14289
|
-
style: getCurrentStyle()
|
|
14290
|
-
});
|
|
14291
|
-
styles.sort(function(a, b) {
|
|
14292
|
-
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 :
|
|
14293
|
-
a.name.toLowerCase() > b.name.toLowerCase() ? 1 : 0;
|
|
14294
|
-
});
|
|
14295
|
-
GUI.setSavedValue(savedStylesKey, styles);
|
|
14296
|
-
renderSavedStyles();
|
|
14297
|
-
for (i=0; i<styleSelect.node().options.length; i++) {
|
|
14298
|
-
if (styleSelect.node().options[i].value == name) {
|
|
14299
|
-
styleSelect.node().selectedIndex = i;
|
|
14300
|
-
break;
|
|
14301
|
-
}
|
|
14302
|
-
}
|
|
15360
|
+
function layerCanBeStyled(lyr) {
|
|
15361
|
+
return !!(lyr && (lyr.geometry_type == 'polyline' || lyr.geometry_type == 'polygon'));
|
|
14303
15362
|
}
|
|
14304
15363
|
|
|
14305
|
-
|
|
14306
|
-
var
|
|
14307
|
-
|
|
14308
|
-
|
|
14309
|
-
if (!await showPrompt('Delete label style "' + name + '"?', 'Delete preset')) return;
|
|
14310
|
-
styles = getSavedStyles().filter(function(item) {
|
|
14311
|
-
return item.name != name;
|
|
14312
|
-
});
|
|
14313
|
-
GUI.setSavedValue(savedStylesKey, styles);
|
|
14314
|
-
renderSavedStyles();
|
|
14315
|
-
updateSavedStyleControls();
|
|
15364
|
+
function modeMatchesActiveLayer(mode) {
|
|
15365
|
+
var lyr = getActiveLayer();
|
|
15366
|
+
return mode == 'line_style' && lyr && lyr.geometry_type == 'polyline' ||
|
|
15367
|
+
mode == 'polygon_style' && lyr && lyr.geometry_type == 'polygon';
|
|
14316
15368
|
}
|
|
14317
15369
|
|
|
14318
|
-
function
|
|
14319
|
-
|
|
14320
|
-
|
|
14321
|
-
});
|
|
14322
|
-
if (!item) return;
|
|
14323
|
-
applyStyleObject(item.style);
|
|
15370
|
+
function modelSelectLayer(lyr, dataset) {
|
|
15371
|
+
if (lyr) lyr.hidden = false;
|
|
15372
|
+
gui.model.selectLayer(lyr, dataset);
|
|
14324
15373
|
}
|
|
14325
15374
|
|
|
14326
|
-
function
|
|
14327
|
-
var
|
|
14328
|
-
|
|
15375
|
+
function parseOpacityValue(str) {
|
|
15376
|
+
var pct = Number(String(str).replace('%', '').trim());
|
|
15377
|
+
if (!isFinite(pct)) return null;
|
|
15378
|
+
return Math.max(0, Math.min(100, pct)) / 100;
|
|
14329
15379
|
}
|
|
14330
15380
|
|
|
14331
|
-
function
|
|
14332
|
-
var
|
|
14333
|
-
|
|
14334
|
-
styleSelect.empty();
|
|
14335
|
-
El('option').attr('value', '').appendTo(styleSelect).text('Apply preset...');
|
|
14336
|
-
getSavedStyles().forEach(function(item) {
|
|
14337
|
-
El('option').attr('value', item.name).appendTo(styleSelect).text(item.name);
|
|
14338
|
-
});
|
|
14339
|
-
styleSelect.node().value = value || '';
|
|
14340
|
-
updateSavedStyleControls();
|
|
15381
|
+
function parsePositiveNumber(str) {
|
|
15382
|
+
var val = Number(String(str).trim());
|
|
15383
|
+
return isFinite(val) && val >= 0 ? val : null;
|
|
14341
15384
|
}
|
|
14342
15385
|
|
|
14343
|
-
function
|
|
14344
|
-
|
|
14345
|
-
|
|
14346
|
-
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
|
|
14350
|
-
|
|
15386
|
+
function formatOpacityPct(val) {
|
|
15387
|
+
val = val === '' || val === undefined || val === null ? 1 : Number(val);
|
|
15388
|
+
return isFinite(val) ? Math.round(Math.max(0, Math.min(1, val)) * 100) + '%' : '';
|
|
15389
|
+
}
|
|
15390
|
+
|
|
15391
|
+
function formatNumberValue(val) {
|
|
15392
|
+
val = Number(val);
|
|
15393
|
+
return isFinite(val) ? String(val) : '';
|
|
15394
|
+
}
|
|
15395
|
+
|
|
15396
|
+
function quoteCommandValue(str) {
|
|
15397
|
+
return "'" + String(str).replace(/'/g, "\\'") + "'";
|
|
15398
|
+
}
|
|
15399
|
+
}
|
|
15400
|
+
|
|
15401
|
+
var defaultCircleRadius = 0;
|
|
15402
|
+
var defaultCreatedCircleRadius = 3;
|
|
15403
|
+
var defaultCircleFill = '#000000';
|
|
15404
|
+
|
|
15405
|
+
function PointStyleTool(gui) {
|
|
15406
|
+
var parent = gui.container.findChild('.mshp-main-map');
|
|
15407
|
+
var panel = El('div').addClass('label-style-panel point-style-panel rollover').appendTo(parent).hide();
|
|
15408
|
+
var title, noteSection, labelsSection, circlesSection, symbolsSection, labelNoteSection;
|
|
15409
|
+
var circleSectionLabel;
|
|
15410
|
+
var symbolNote;
|
|
15411
|
+
var createFieldSelect, createExprInput, createCopyCheckbox, createLabelsBtn;
|
|
15412
|
+
var editingRow, editingStatus, clearLink;
|
|
15413
|
+
var createCirclesRow;
|
|
15414
|
+
var circleControlRows = [];
|
|
15415
|
+
var circleRadiusClickText, circleFillControl, circleStrokeControl;
|
|
15416
|
+
var circleFillOpacityInput, circleStrokeOpacityInput, circleStrokeWidthClickText;
|
|
15417
|
+
var targetLayer = null;
|
|
15418
|
+
var hit = null;
|
|
15419
|
+
|
|
15420
|
+
initPanel();
|
|
15421
|
+
|
|
15422
|
+
this.open = function(lyr, dataset) {
|
|
15423
|
+
if (!layerCanBeStyled(lyr)) return;
|
|
15424
|
+
if (!gui.map.isActiveLayer(lyr)) {
|
|
15425
|
+
modelSelectLayer(lyr, dataset);
|
|
14351
15426
|
}
|
|
14352
|
-
|
|
14353
|
-
|
|
14354
|
-
|
|
14355
|
-
|
|
14356
|
-
|
|
14357
|
-
|
|
14358
|
-
|
|
15427
|
+
gui.interaction.setMode('point_style');
|
|
15428
|
+
};
|
|
15429
|
+
|
|
15430
|
+
gui.on('interaction_mode_change', function(e) {
|
|
15431
|
+
if (modeMatchesActiveLayer(e.mode)) {
|
|
15432
|
+
turnOn();
|
|
15433
|
+
} else {
|
|
15434
|
+
turnOff();
|
|
14359
15435
|
}
|
|
14360
|
-
|
|
14361
|
-
}
|
|
15436
|
+
});
|
|
14362
15437
|
|
|
14363
|
-
|
|
14364
|
-
if (
|
|
14365
|
-
|
|
15438
|
+
gui.model.on('update', function() {
|
|
15439
|
+
if (panel.visible() && !modeMatchesActiveLayer(gui.interaction.getMode())) {
|
|
15440
|
+
gui.interaction.turnOff();
|
|
15441
|
+
} else if (panel.visible()) {
|
|
15442
|
+
updateControls();
|
|
14366
15443
|
}
|
|
15444
|
+
});
|
|
15445
|
+
|
|
15446
|
+
hit = gui.map.getHitControl && gui.map.getHitControl();
|
|
15447
|
+
if (hit) {
|
|
15448
|
+
hit.on('change', function(e) {
|
|
15449
|
+
if (e.mode == 'point_style') {
|
|
15450
|
+
updateControls();
|
|
15451
|
+
}
|
|
15452
|
+
});
|
|
14367
15453
|
}
|
|
14368
15454
|
|
|
14369
|
-
function
|
|
14370
|
-
var
|
|
14371
|
-
|
|
15455
|
+
function initPanel() {
|
|
15456
|
+
var header = El('div').addClass('label-style-panel-title').appendTo(panel);
|
|
15457
|
+
title = El('span').appendTo(header).text('Point symbols');
|
|
15458
|
+
El('button').addClass('label-style-close').appendTo(header).text('×').on('click', closePanel);
|
|
15459
|
+
|
|
15460
|
+
initNoteSections();
|
|
15461
|
+
initCreateLabelsSection();
|
|
15462
|
+
initCreateCirclesSection();
|
|
15463
|
+
initSymbolsSection();
|
|
14372
15464
|
}
|
|
14373
15465
|
|
|
14374
|
-
function
|
|
14375
|
-
|
|
14376
|
-
|
|
14377
|
-
|
|
14378
|
-
|
|
14379
|
-
|
|
15466
|
+
function initNoteSections() {
|
|
15467
|
+
noteSection = El('div').addClass('point-style-section point-style-note-section').appendTo(panel);
|
|
15468
|
+
El('div').addClass('point-style-note').appendTo(noteSection).text('This layer contains unstyled points.');
|
|
15469
|
+
|
|
15470
|
+
labelNoteSection = El('div').addClass('point-style-section point-label-note-section').appendTo(panel);
|
|
15471
|
+
El('div').addClass('point-style-note').appendTo(labelNoteSection)
|
|
15472
|
+
.text('This layer is rendered as labels. Use the label style tool to edit label styles.');
|
|
14380
15473
|
}
|
|
14381
15474
|
|
|
14382
|
-
function
|
|
14383
|
-
|
|
14384
|
-
|
|
14385
|
-
|
|
15475
|
+
function initCreateLabelsSection() {
|
|
15476
|
+
labelsSection = El('div').addClass('point-style-section').appendTo(panel);
|
|
15477
|
+
El('div').addClass('label-style-row-label').appendTo(labelsSection).text('Labels');
|
|
15478
|
+
|
|
15479
|
+
var fieldRow = El('label').addClass('label-style-row').appendTo(labelsSection);
|
|
15480
|
+
El('span').appendTo(fieldRow).text('Label field');
|
|
15481
|
+
createFieldSelect = El('select').appendTo(fieldRow).on('change', function() {
|
|
15482
|
+
var field = createFieldSelect.node().value;
|
|
15483
|
+
if (field) {
|
|
15484
|
+
createExprInput.node().value = getFieldExpression(field);
|
|
15485
|
+
}
|
|
15486
|
+
updateCreateLabelsButton();
|
|
14386
15487
|
});
|
|
14387
|
-
return out;
|
|
14388
|
-
}
|
|
14389
15488
|
|
|
14390
|
-
|
|
14391
|
-
|
|
14392
|
-
|
|
14393
|
-
|
|
14394
|
-
|
|
14395
|
-
|
|
14396
|
-
|
|
14397
|
-
|
|
15489
|
+
var exprRow = El('label').addClass('label-style-row label-create-expression-row').appendTo(labelsSection);
|
|
15490
|
+
El('span').appendTo(exprRow).text('or expression');
|
|
15491
|
+
createExprInput = El('input')
|
|
15492
|
+
.attr('type', 'text')
|
|
15493
|
+
.appendTo(exprRow)
|
|
15494
|
+
.on('input', updateCreateLabelsButton)
|
|
15495
|
+
.on('change', updateCreateLabelsButton);
|
|
15496
|
+
|
|
15497
|
+
var btnRow = El('div').addClass('label-style-row point-create-labels-row').appendTo(labelsSection);
|
|
15498
|
+
createLabelsBtn = El('button').appendTo(btnRow).text('Create').on('click', createLabels);
|
|
15499
|
+
var copyLabel = El('label').addClass('point-create-copy-label').appendTo(btnRow);
|
|
15500
|
+
createCopyCheckbox = El('input').attr('type', 'checkbox').appendTo(copyLabel);
|
|
15501
|
+
El('span').appendTo(copyLabel).text('as new layer');
|
|
15502
|
+
}
|
|
15503
|
+
|
|
15504
|
+
function initCreateCirclesSection() {
|
|
15505
|
+
circlesSection = El('div').addClass('point-style-section point-circle-section').appendTo(panel);
|
|
15506
|
+
circleSectionLabel = El('div').addClass('label-style-row-label').appendTo(circlesSection).text('Circles');
|
|
15507
|
+
El('div').addClass('point-style-note point-circle-note').appendTo(circlesSection)
|
|
15508
|
+
.text('Use the -style command in the console to create proportional circles.');
|
|
15509
|
+
|
|
15510
|
+
createCirclesRow = El('div').addClass('label-style-row point-create-circles-row').appendTo(circlesSection);
|
|
15511
|
+
El('button').appendTo(createCirclesRow).text('Create').on('click', createSimpleCircles);
|
|
15512
|
+
El('span').appendTo(createCirclesRow).text('simple circles');
|
|
15513
|
+
|
|
15514
|
+
editingRow = El('div').addClass('label-style-row label-style-selection-row point-style-selection-row').appendTo(circlesSection);
|
|
15515
|
+
editingStatus = El('span').addClass('label-editing-status').appendTo(editingRow);
|
|
15516
|
+
clearLink = El('span').addClass('label-editing-clear colored-text').appendTo(editingRow).text('deselect').on('click', clearSelection);
|
|
15517
|
+
|
|
15518
|
+
var fillRow = El('div').addClass('label-style-row point-symbol-row').appendTo(circlesSection);
|
|
15519
|
+
circleFillControl = addCircleColorControl(fillRow, 'Fill');
|
|
15520
|
+
circleFillOpacityInput = addCircleNumberControl(fillRow, 'Opacity', '100%');
|
|
15521
|
+
circleControlRows.push(fillRow);
|
|
15522
|
+
|
|
15523
|
+
var strokeRow = El('div').addClass('label-style-row point-symbol-row').appendTo(circlesSection);
|
|
15524
|
+
circleStrokeControl = addCircleColorControl(strokeRow, 'Stroke');
|
|
15525
|
+
circleStrokeOpacityInput = addCircleNumberControl(strokeRow, 'Opacity', '100%');
|
|
15526
|
+
circleControlRows.push(strokeRow);
|
|
15527
|
+
|
|
15528
|
+
var sizeRow = El('div').addClass('label-style-row point-symbol-size-row').appendTo(circlesSection);
|
|
15529
|
+
addCircleStepperControl(sizeRow, 'Stroke width', function() {
|
|
15530
|
+
return getCircleStrokeWidth();
|
|
15531
|
+
}, function(direction) {
|
|
15532
|
+
setCircleStrokeWidth(getNextStrokeWidth(getCircleStrokeWidth(), direction));
|
|
15533
|
+
applyCircleStyles();
|
|
15534
|
+
}, function(value) {
|
|
15535
|
+
setCircleStrokeWidth(value);
|
|
15536
|
+
applyCircleStyles();
|
|
15537
|
+
}, function(clickText) {
|
|
15538
|
+
circleStrokeWidthClickText = clickText;
|
|
15539
|
+
});
|
|
15540
|
+
|
|
15541
|
+
addCircleStepperControl(sizeRow, 'Radius', function() {
|
|
15542
|
+
return getCircleRadiusForNudge();
|
|
15543
|
+
}, function(direction) {
|
|
15544
|
+
setCircleRadius(getNextCircleRadius(getCircleRadiusForNudge(), direction));
|
|
15545
|
+
applyCircleStyles();
|
|
15546
|
+
}, function(value) {
|
|
15547
|
+
setCircleRadius(value);
|
|
15548
|
+
applyCircleStyles();
|
|
15549
|
+
}, function(clickText, text) {
|
|
15550
|
+
circleRadiusClickText = clickText;
|
|
15551
|
+
text.addClass('label-icon-size-value');
|
|
15552
|
+
});
|
|
15553
|
+
circleControlRows.push(sizeRow);
|
|
15554
|
+
}
|
|
15555
|
+
|
|
15556
|
+
function initSymbolsSection() {
|
|
15557
|
+
symbolsSection = El('div').addClass('point-style-section point-symbol-info-section').appendTo(panel);
|
|
15558
|
+
El('div').addClass('label-style-row-label').appendTo(symbolsSection).text('Symbols');
|
|
15559
|
+
symbolNote = El('div').addClass('point-style-note').appendTo(symbolsSection)
|
|
15560
|
+
.text('Use the -symbols command in the console to create arrows and other symbols.');
|
|
15561
|
+
}
|
|
15562
|
+
|
|
15563
|
+
function addCircleColorControl(row, label) {
|
|
15564
|
+
var colorCell = El('div').addClass('point-symbol-color-cell label-color-row').appendTo(row);
|
|
15565
|
+
var control = {};
|
|
15566
|
+
El('span').appendTo(colorCell).text(label);
|
|
15567
|
+
control.chit = makePanelButton(colorCell, '', function() {
|
|
15568
|
+
control.picker.toggle();
|
|
15569
|
+
}).addClass('label-color-chit');
|
|
15570
|
+
control.input = El('input').attr('type', 'text').appendTo(colorCell).on('change', function() {
|
|
15571
|
+
var color = control.input.node().value.trim();
|
|
15572
|
+
if (isHexColor(color)) {
|
|
15573
|
+
control.picker.setColor(color);
|
|
14398
15574
|
}
|
|
14399
|
-
|
|
14400
|
-
}
|
|
14401
|
-
|
|
14402
|
-
|
|
14403
|
-
|
|
14404
|
-
|
|
14405
|
-
|
|
14406
|
-
|
|
14407
|
-
|
|
14408
|
-
|
|
15575
|
+
applyCircleStyles();
|
|
15576
|
+
});
|
|
15577
|
+
control.picker = new ColorPicker(colorCell, {
|
|
15578
|
+
presetRows: layerColorPresetRows,
|
|
15579
|
+
onPreview: function(hex) {
|
|
15580
|
+
setCircleColor(control, hex);
|
|
15581
|
+
},
|
|
15582
|
+
onChange: function(hex) {
|
|
15583
|
+
setCircleColor(control, hex);
|
|
15584
|
+
applyCircleStyles();
|
|
15585
|
+
}
|
|
15586
|
+
});
|
|
15587
|
+
setCircleColor(control, '');
|
|
15588
|
+
return control;
|
|
15589
|
+
}
|
|
15590
|
+
|
|
15591
|
+
function addCircleStepperControl(row, label, getValue, nudgeValue, setValue, capture) {
|
|
15592
|
+
var control;
|
|
15593
|
+
var buttonRow;
|
|
15594
|
+
var text;
|
|
15595
|
+
var clickText;
|
|
15596
|
+
control = El('div').addClass('point-symbol-stepper-control').appendTo(row);
|
|
15597
|
+
El('span').appendTo(control).text(label);
|
|
15598
|
+
buttonRow = El('div').addClass('layer-stepper-control').appendTo(control);
|
|
15599
|
+
makePanelButton(buttonRow, '−', function() {
|
|
15600
|
+
nudgeValue(-1);
|
|
15601
|
+
});
|
|
15602
|
+
text = El('span').addClass('layer-stroke-width-value').appendTo(buttonRow);
|
|
15603
|
+
clickText = new ClickText2(text);
|
|
15604
|
+
clickText.on('change', function() {
|
|
15605
|
+
var value = parsePositiveNumber(clickText.value());
|
|
15606
|
+
if (value === null) {
|
|
15607
|
+
clickText.value(formatNumberValue(getValue()));
|
|
15608
|
+
return;
|
|
14409
15609
|
}
|
|
15610
|
+
setValue(value);
|
|
15611
|
+
});
|
|
15612
|
+
makePanelButton(buttonRow, '+', function() {
|
|
15613
|
+
nudgeValue(1);
|
|
14410
15614
|
});
|
|
15615
|
+
capture(clickText, text);
|
|
14411
15616
|
}
|
|
14412
15617
|
|
|
14413
|
-
function
|
|
14414
|
-
var
|
|
14415
|
-
|
|
14416
|
-
|
|
14417
|
-
|
|
14418
|
-
|
|
14419
|
-
|
|
15618
|
+
function addCircleNumberControl(row, label, value) {
|
|
15619
|
+
var control = El('label').addClass('layer-number-control').appendTo(row);
|
|
15620
|
+
var input;
|
|
15621
|
+
El('span').appendTo(control).text(label);
|
|
15622
|
+
input = El('input').attr('type', 'text').appendTo(control).on('change', applyCircleStyles);
|
|
15623
|
+
input.node().value = value;
|
|
15624
|
+
return input;
|
|
14420
15625
|
}
|
|
14421
15626
|
|
|
14422
|
-
function
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
15627
|
+
function makePanelButton(parent, label, action) {
|
|
15628
|
+
return El('div')
|
|
15629
|
+
.addClass('label-panel-btn')
|
|
15630
|
+
.attr('role', 'button')
|
|
15631
|
+
.attr('tabindex', '0')
|
|
15632
|
+
.appendTo(parent)
|
|
15633
|
+
.text(label)
|
|
15634
|
+
.on('click', function(e) {
|
|
15635
|
+
action(e);
|
|
15636
|
+
})
|
|
15637
|
+
.on('keydown', function(e) {
|
|
15638
|
+
if (e.key == 'Enter' || e.key == ' ') {
|
|
15639
|
+
e.preventDefault();
|
|
15640
|
+
action(e);
|
|
15641
|
+
}
|
|
15642
|
+
});
|
|
14426
15643
|
}
|
|
14427
15644
|
|
|
14428
|
-
function
|
|
14429
|
-
|
|
14430
|
-
|
|
14431
|
-
|
|
14432
|
-
|
|
14433
|
-
|
|
14434
|
-
|
|
14435
|
-
|
|
14436
|
-
|
|
14437
|
-
|
|
14438
|
-
}
|
|
14439
|
-
});
|
|
15645
|
+
function turnOn() {
|
|
15646
|
+
targetLayer = getActiveLayer();
|
|
15647
|
+
if (getPointRepresentation() == 'label' && gui.labelTool && gui.labelTool.open) {
|
|
15648
|
+
gui.labelTool.open(targetLayer);
|
|
15649
|
+
targetLayer = null;
|
|
15650
|
+
return;
|
|
15651
|
+
}
|
|
15652
|
+
renderCreateFields();
|
|
15653
|
+
updateControls();
|
|
15654
|
+
panel.show();
|
|
14440
15655
|
}
|
|
14441
15656
|
|
|
14442
|
-
function
|
|
14443
|
-
|
|
14444
|
-
|
|
14445
|
-
|
|
14446
|
-
|
|
14447
|
-
applyStyleFields([iconField, iconSizeField], function(rec) {
|
|
14448
|
-
if (!rec[iconField]) {
|
|
14449
|
-
rec[iconField] = 'circle';
|
|
14450
|
-
}
|
|
14451
|
-
rec[iconSizeField] = size;
|
|
14452
|
-
});
|
|
15657
|
+
function turnOff() {
|
|
15658
|
+
panel.hide();
|
|
15659
|
+
circleFillControl.picker.hide();
|
|
15660
|
+
circleStrokeControl.picker.hide();
|
|
15661
|
+
targetLayer = null;
|
|
14453
15662
|
}
|
|
14454
15663
|
|
|
14455
|
-
function
|
|
14456
|
-
|
|
14457
|
-
|
|
14458
|
-
|
|
15664
|
+
function closePanel() {
|
|
15665
|
+
turnOff();
|
|
15666
|
+
if (gui.interaction.getMode() == 'point_style') {
|
|
15667
|
+
gui.interaction.turnOff();
|
|
15668
|
+
}
|
|
14459
15669
|
}
|
|
14460
15670
|
|
|
14461
|
-
function
|
|
14462
|
-
|
|
15671
|
+
function updateControls() {
|
|
15672
|
+
syncTargetLayer();
|
|
15673
|
+
var representation = getPointRepresentation();
|
|
15674
|
+
updateCreateLabelsButton();
|
|
15675
|
+
title.text(representation == 'circle' ? 'Circle styles' : 'Point symbols');
|
|
15676
|
+
updateEditingStatus(getSelectionIds().length);
|
|
15677
|
+
toggleSection(noteSection, representation == 'unstyled');
|
|
15678
|
+
toggleSection(labelsSection, representation == 'unstyled');
|
|
15679
|
+
toggleSection(circlesSection, representation == 'unstyled' || representation == 'circle');
|
|
15680
|
+
toggleSection(symbolsSection, representation == 'unstyled' || representation == 'svg-symbol');
|
|
15681
|
+
toggleSection(labelNoteSection, representation == 'label');
|
|
15682
|
+
updateSectionBorders([noteSection, labelNoteSection, labelsSection, circlesSection, symbolsSection]);
|
|
15683
|
+
symbolNote.text(representation == 'svg-symbol' ?
|
|
15684
|
+
'This layer uses SVG symbols. Use the -symbols command in the console to create arrows and other symbols.' :
|
|
15685
|
+
'Use the -symbols command in the console to create arrows and other symbols.');
|
|
15686
|
+
updateCircleSection(representation);
|
|
15687
|
+
updateCircleControls(representation);
|
|
15688
|
+
}
|
|
15689
|
+
|
|
15690
|
+
function toggleSection(section, visible) {
|
|
15691
|
+
if (visible) {
|
|
15692
|
+
section.show();
|
|
15693
|
+
} else {
|
|
15694
|
+
section.hide();
|
|
15695
|
+
}
|
|
14463
15696
|
}
|
|
14464
15697
|
|
|
14465
|
-
function
|
|
14466
|
-
|
|
14467
|
-
|
|
14468
|
-
|
|
14469
|
-
|
|
14470
|
-
|
|
14471
|
-
hueCanvas = El('canvas').attr('width', '256').attr('height', '18').appendTo(hueWrap);
|
|
14472
|
-
hueMarker = makePickerMarker().appendTo(hueWrap);
|
|
14473
|
-
pickerHsbInputs = {};
|
|
14474
|
-
var hsbRow = El('div').addClass('label-color-picker-fields').appendTo(colorPicker);
|
|
14475
|
-
addPickerNumberInput(hsbRow, 'h', 'H');
|
|
14476
|
-
addPickerNumberInput(hsbRow, 's', 'S');
|
|
14477
|
-
addPickerNumberInput(hsbRow, 'b', 'B');
|
|
14478
|
-
El('button').appendTo(hsbRow).text('Close').on('click', closePickerColor);
|
|
14479
|
-
sbCanvas.on('mousedown', function(e) {
|
|
14480
|
-
startCanvasDrag(e, updateSbFromEvent);
|
|
15698
|
+
function updateSectionBorders(sections) {
|
|
15699
|
+
var foundFirst = false;
|
|
15700
|
+
sections.forEach(function(section) {
|
|
15701
|
+
var visible = section.visible();
|
|
15702
|
+
section.classed('point-style-first-visible', visible && !foundFirst);
|
|
15703
|
+
if (visible) foundFirst = true;
|
|
14481
15704
|
});
|
|
14482
|
-
|
|
14483
|
-
|
|
15705
|
+
}
|
|
15706
|
+
|
|
15707
|
+
function updateCircleSection(representation) {
|
|
15708
|
+
var showCreate = representation == 'unstyled';
|
|
15709
|
+
circleSectionLabel.classed('hidden', !showCreate);
|
|
15710
|
+
createCirclesRow.classed('hidden', !showCreate);
|
|
15711
|
+
editingRow.classed('hidden', representation != 'circle');
|
|
15712
|
+
circlesSection.findChild('.point-circle-note').classed('hidden', !showCreate);
|
|
15713
|
+
circleControlRows.forEach(function(row) {
|
|
15714
|
+
row.classed('hidden', showCreate);
|
|
15715
|
+
});
|
|
15716
|
+
}
|
|
15717
|
+
|
|
15718
|
+
function updateCircleControls(representation) {
|
|
15719
|
+
var radius = getCommonValue('r');
|
|
15720
|
+
var fill = getCommonValue('fill');
|
|
15721
|
+
var stroke = getCommonValue('stroke');
|
|
15722
|
+
var fillOpacity = getCommonValue('fill-opacity');
|
|
15723
|
+
var strokeOpacity = getCommonValue('stroke-opacity');
|
|
15724
|
+
var strokeWidth = getCommonValue('stroke-width');
|
|
15725
|
+
setCircleRadius(radius);
|
|
15726
|
+
setCircleColor(circleFillControl, fill);
|
|
15727
|
+
setCircleColor(circleStrokeControl, stroke);
|
|
15728
|
+
circleFillOpacityInput.node().value = formatOpacityPct(fillOpacity === '' ? 1 : fillOpacity);
|
|
15729
|
+
circleStrokeOpacityInput.node().value = formatOpacityPct(strokeOpacity === '' ? 1 : strokeOpacity);
|
|
15730
|
+
setCircleStrokeWidth(strokeWidth === '' ? 0 : strokeWidth);
|
|
15731
|
+
if (representation != 'circle' && representation != 'unstyled') {
|
|
15732
|
+
setCircleRadius(defaultCircleRadius);
|
|
15733
|
+
setCircleColor(circleFillControl, '');
|
|
15734
|
+
setCircleColor(circleStrokeControl, '');
|
|
15735
|
+
circleFillOpacityInput.node().value = '100%';
|
|
15736
|
+
circleStrokeOpacityInput.node().value = '100%';
|
|
15737
|
+
setCircleStrokeWidth(0);
|
|
15738
|
+
}
|
|
15739
|
+
}
|
|
15740
|
+
|
|
15741
|
+
function renderCreateFields() {
|
|
15742
|
+
var lyr = getActiveLayer();
|
|
15743
|
+
var records = lyr && lyr.data ? lyr.data.getRecords() : [];
|
|
15744
|
+
var fields = lyr && lyr.data ? lyr.data.getFields().filter(function(field) {
|
|
15745
|
+
return internal.getColumnType(field, records) == 'string';
|
|
15746
|
+
}) : [];
|
|
15747
|
+
var value = createFieldSelect.node().value;
|
|
15748
|
+
createFieldSelect.empty();
|
|
15749
|
+
El('option').attr('value', '').appendTo(createFieldSelect).text('');
|
|
15750
|
+
fields.forEach(function(field) {
|
|
15751
|
+
El('option').attr('value', field).appendTo(createFieldSelect).text(field);
|
|
14484
15752
|
});
|
|
14485
|
-
|
|
15753
|
+
createFieldSelect.node().disabled = fields.length === 0;
|
|
15754
|
+
createFieldSelect.node().value = fields.indexOf(value) > -1 ? value : '';
|
|
14486
15755
|
}
|
|
14487
15756
|
|
|
14488
|
-
function
|
|
14489
|
-
|
|
14490
|
-
El('span').appendTo(wrapper).text(label);
|
|
14491
|
-
pickerHsbInputs[name] = El('input')
|
|
14492
|
-
.attr('type', 'text')
|
|
14493
|
-
.appendTo(wrapper)
|
|
14494
|
-
.on('change', function() {
|
|
14495
|
-
var h = parseNumberField(pickerHsbInputs.h.node().value);
|
|
14496
|
-
var s = parseNumberField(pickerHsbInputs.s.node().value);
|
|
14497
|
-
var b = parseNumberField(pickerHsbInputs.b.node().value);
|
|
14498
|
-
if (!isFinite(h) || !isFinite(s) || !isFinite(b)) return;
|
|
14499
|
-
setPickerColor({
|
|
14500
|
-
h: degreesToByte(h),
|
|
14501
|
-
s: pctToByte(s),
|
|
14502
|
-
b: pctToByte(b)
|
|
14503
|
-
});
|
|
14504
|
-
commitPickerColor();
|
|
14505
|
-
});
|
|
15757
|
+
function updateCreateLabelsButton() {
|
|
15758
|
+
createLabelsBtn.node().disabled = createExprInput.node().value.trim() === '';
|
|
14506
15759
|
}
|
|
14507
15760
|
|
|
14508
|
-
function
|
|
14509
|
-
|
|
14510
|
-
|
|
14511
|
-
|
|
14512
|
-
|
|
14513
|
-
|
|
14514
|
-
|
|
15761
|
+
function createLabels() {
|
|
15762
|
+
var expr = createExprInput.node().value.trim();
|
|
15763
|
+
var cmd;
|
|
15764
|
+
if (!expr || !gui.console) return;
|
|
15765
|
+
cmd = createCopyCheckbox.node().checked ?
|
|
15766
|
+
'-filter true + name=labels -style label-text=' + quoteCommandValue(expr) :
|
|
15767
|
+
'-style label-text=' + quoteCommandValue(expr);
|
|
15768
|
+
runGuiEditCommand(gui, cmd, {
|
|
15769
|
+
title: 'Create labels',
|
|
15770
|
+
onSuccess: openLabelStyles
|
|
15771
|
+
});
|
|
14515
15772
|
}
|
|
14516
15773
|
|
|
14517
|
-
function
|
|
14518
|
-
|
|
15774
|
+
function openLabelStyles() {
|
|
15775
|
+
var active = gui.model.getActiveLayer();
|
|
15776
|
+
if (active && active.layer && internal.layerHasLabels(active.layer) &&
|
|
15777
|
+
gui.labelTool && gui.labelTool.open) {
|
|
15778
|
+
gui.labelTool.open(active.layer, active.dataset);
|
|
15779
|
+
} else {
|
|
15780
|
+
updateControls();
|
|
15781
|
+
}
|
|
15782
|
+
}
|
|
15783
|
+
|
|
15784
|
+
function createSimpleCircles() {
|
|
15785
|
+
runCommand('-style r=' + defaultCreatedCircleRadius +
|
|
15786
|
+
' fill=' + quoteCommandValue(defaultCircleFill) +
|
|
15787
|
+
' fill-opacity=1 stroke-opacity=1 stroke-width=0', 'Create circles');
|
|
15788
|
+
}
|
|
15789
|
+
|
|
15790
|
+
function applyCircleStyles() {
|
|
15791
|
+
var representation = getPointRepresentation();
|
|
15792
|
+
var radius = getCircleRadius();
|
|
15793
|
+
var fill = circleFillControl.input.node().value.trim();
|
|
15794
|
+
var fillOpacity = parseOpacityValue(circleFillOpacityInput.node().value);
|
|
15795
|
+
var stroke = circleStrokeControl.input.node().value.trim();
|
|
15796
|
+
var strokeOpacity = parseOpacityValue(circleStrokeOpacityInput.node().value);
|
|
15797
|
+
var strokeWidth = getCircleStrokeWidth();
|
|
15798
|
+
var args;
|
|
15799
|
+
if (!gui.console || !(representation == 'unstyled' || representation == 'circle') ||
|
|
15800
|
+
(radius !== null && !(radius >= 0)) || fillOpacity === null || strokeOpacity === null || strokeWidth === null) return;
|
|
15801
|
+
if (radius !== null && radius > 0 && !fill && !stroke && styleFieldIsUnset('fill') && styleFieldIsUnset('stroke')) {
|
|
15802
|
+
fill = defaultCircleFill;
|
|
15803
|
+
setCircleColor(circleFillControl, fill);
|
|
15804
|
+
}
|
|
15805
|
+
args = [
|
|
15806
|
+
'fill-opacity=' + fillOpacity,
|
|
15807
|
+
'stroke-opacity=' + strokeOpacity,
|
|
15808
|
+
'stroke-width=' + strokeWidth
|
|
15809
|
+
];
|
|
15810
|
+
if (radius !== null) args.unshift('r=' + radius);
|
|
15811
|
+
if (fill) args.push('fill=' + quoteCommandValue(fill));
|
|
15812
|
+
if (stroke) args.push('stroke=' + quoteCommandValue(stroke));
|
|
15813
|
+
runStyleCommand(args, 'Create circles');
|
|
14519
15814
|
}
|
|
14520
15815
|
|
|
14521
|
-
function
|
|
14522
|
-
|
|
14523
|
-
|
|
14524
|
-
|
|
14525
|
-
|
|
14526
|
-
|
|
14527
|
-
|
|
14528
|
-
|
|
14529
|
-
function onmove(evt) {
|
|
14530
|
-
update(evt);
|
|
14531
|
-
}
|
|
14532
|
-
function onup() {
|
|
14533
|
-
document.removeEventListener('mousemove', onmove);
|
|
14534
|
-
document.removeEventListener('mouseup', onup);
|
|
14535
|
-
colorPicker.removeClass('dragging-color');
|
|
14536
|
-
El('body').removeClass('dragging-color-picker');
|
|
14537
|
-
commitPickerColor();
|
|
15816
|
+
function runStyleCommand(args, title) {
|
|
15817
|
+
syncTargetLayer();
|
|
15818
|
+
var ids = getTargetIds();
|
|
15819
|
+
var parts = ['-style'].concat(args);
|
|
15820
|
+
if (!targetLayer || ids.length === 0) return;
|
|
15821
|
+
addTargetOption(parts);
|
|
15822
|
+
if (ids.length < internal.getFeatureCount(targetLayer)) {
|
|
15823
|
+
parts.push('ids=' + ids.join(','));
|
|
14538
15824
|
}
|
|
15825
|
+
runCommand(parts.join(' '), title);
|
|
14539
15826
|
}
|
|
14540
15827
|
|
|
14541
|
-
function
|
|
14542
|
-
|
|
14543
|
-
|
|
14544
|
-
|
|
14545
|
-
s: p.x,
|
|
14546
|
-
b: 255 - p.y
|
|
15828
|
+
function runCommand(cmd, title) {
|
|
15829
|
+
runGuiEditCommand(gui, cmd, {
|
|
15830
|
+
title: title,
|
|
15831
|
+
onSuccess: updateControls
|
|
14547
15832
|
});
|
|
14548
15833
|
}
|
|
14549
15834
|
|
|
14550
|
-
function
|
|
14551
|
-
var
|
|
14552
|
-
|
|
14553
|
-
|
|
14554
|
-
|
|
14555
|
-
b: pickerColor.b
|
|
14556
|
-
});
|
|
15835
|
+
function getCircleRadius() {
|
|
15836
|
+
var str = String(circleRadiusClickText.value()).trim();
|
|
15837
|
+
var radius = Number(str);
|
|
15838
|
+
if (str === '') return null;
|
|
15839
|
+
return isFinite(radius) && radius >= 0 ? radius : defaultCircleRadius;
|
|
14557
15840
|
}
|
|
14558
15841
|
|
|
14559
|
-
function
|
|
14560
|
-
var
|
|
14561
|
-
return
|
|
14562
|
-
x: clamp(Math.round((evt.clientX - rect.left) / rect.width * (canvas.width - 1)), 0, canvas.width - 1),
|
|
14563
|
-
y: clamp(Math.round((evt.clientY - rect.top) / rect.height * (canvas.height - 1)), 0, canvas.height - 1)
|
|
14564
|
-
};
|
|
15842
|
+
function getCircleRadiusForNudge() {
|
|
15843
|
+
var radius = getCircleRadius();
|
|
15844
|
+
return radius === null ? getMostCommonNumberValue('r', defaultCircleRadius) : radius;
|
|
14565
15845
|
}
|
|
14566
15846
|
|
|
14567
|
-
function
|
|
14568
|
-
|
|
14569
|
-
h: clamp(Math.round(hsb.h), 0, 255),
|
|
14570
|
-
s: clamp(Math.round(hsb.s), 0, 255),
|
|
14571
|
-
b: clamp(Math.round(hsb.b), 0, 255)
|
|
14572
|
-
};
|
|
14573
|
-
drawColorPicker();
|
|
14574
|
-
updatePickerFields();
|
|
15847
|
+
function setCircleRadius(value) {
|
|
15848
|
+
circleRadiusClickText.value(value === '' ? '' : formatNumberValue(value));
|
|
14575
15849
|
}
|
|
14576
15850
|
|
|
14577
|
-
function
|
|
14578
|
-
var
|
|
14579
|
-
|
|
14580
|
-
pickerHsbInputs.s.node().value = byteToPct(pickerColor.s) + '%';
|
|
14581
|
-
pickerHsbInputs.b.node().value = byteToPct(pickerColor.b) + '%';
|
|
14582
|
-
colorInput.node().value = hex;
|
|
14583
|
-
colorChit.css('background-color', hex);
|
|
15851
|
+
function getCircleStrokeWidth() {
|
|
15852
|
+
var width = Number(circleStrokeWidthClickText.value());
|
|
15853
|
+
return isFinite(width) && width >= 0 ? width : 0;
|
|
14584
15854
|
}
|
|
14585
15855
|
|
|
14586
|
-
function
|
|
14587
|
-
|
|
14588
|
-
drawSaturationBrightnessCanvas();
|
|
14589
|
-
drawHueCanvas();
|
|
15856
|
+
function setCircleStrokeWidth(value) {
|
|
15857
|
+
circleStrokeWidthClickText.value(formatNumberValue(value));
|
|
14590
15858
|
}
|
|
14591
15859
|
|
|
14592
|
-
function
|
|
14593
|
-
var
|
|
14594
|
-
var
|
|
14595
|
-
|
|
14596
|
-
|
|
14597
|
-
|
|
14598
|
-
for (var x=0; x<256; x++) {
|
|
14599
|
-
var rgb = hsbToRgb({
|
|
14600
|
-
h: pickerColor.h,
|
|
14601
|
-
s: x,
|
|
14602
|
-
b: 255 - y
|
|
14603
|
-
});
|
|
14604
|
-
data[i++] = rgb.r;
|
|
14605
|
-
data[i++] = rgb.g;
|
|
14606
|
-
data[i++] = rgb.b;
|
|
14607
|
-
data[i++] = 255;
|
|
15860
|
+
function getNextStrokeWidth(value, direction) {
|
|
15861
|
+
var baseSteps = [0, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4];
|
|
15862
|
+
var i;
|
|
15863
|
+
if (direction > 0) {
|
|
15864
|
+
for (i=0; i<baseSteps.length; i++) {
|
|
15865
|
+
if (value < baseSteps[i]) return baseSteps[i];
|
|
14608
15866
|
}
|
|
15867
|
+
return Math.floor(value) + 1;
|
|
14609
15868
|
}
|
|
14610
|
-
|
|
14611
|
-
|
|
15869
|
+
for (i=baseSteps.length - 1; i>=0; i--) {
|
|
15870
|
+
if (value > baseSteps[i]) return baseSteps[i];
|
|
15871
|
+
}
|
|
15872
|
+
return baseSteps[0];
|
|
14612
15873
|
}
|
|
14613
15874
|
|
|
14614
|
-
function
|
|
14615
|
-
var
|
|
14616
|
-
var
|
|
14617
|
-
|
|
14618
|
-
|
|
14619
|
-
|
|
14620
|
-
for (var x=0; x<256; x++) {
|
|
14621
|
-
var rgb = hsbToRgb({h: x, s: 255, b: 255});
|
|
14622
|
-
data[i++] = rgb.r;
|
|
14623
|
-
data[i++] = rgb.g;
|
|
14624
|
-
data[i++] = rgb.b;
|
|
14625
|
-
data[i++] = 255;
|
|
15875
|
+
function getNextCircleRadius(value, direction) {
|
|
15876
|
+
var baseSteps = [0, 0.5, 1, 1.5, 2, 2.5, 3, 4, 5];
|
|
15877
|
+
var i;
|
|
15878
|
+
if (direction > 0) {
|
|
15879
|
+
for (i=0; i<baseSteps.length; i++) {
|
|
15880
|
+
if (value < baseSteps[i]) return baseSteps[i];
|
|
14626
15881
|
}
|
|
15882
|
+
return Math.floor(value) + 1;
|
|
14627
15883
|
}
|
|
14628
|
-
|
|
14629
|
-
|
|
15884
|
+
for (i=baseSteps.length - 1; i>=0; i--) {
|
|
15885
|
+
if (value > baseSteps[i]) return baseSteps[i];
|
|
15886
|
+
}
|
|
15887
|
+
return baseSteps[0];
|
|
14630
15888
|
}
|
|
14631
15889
|
|
|
14632
|
-
function
|
|
14633
|
-
|
|
15890
|
+
function getPointRepresentation() {
|
|
15891
|
+
var lyr = targetLayer || getActiveLayer();
|
|
15892
|
+
var table = lyr && lyr.data;
|
|
15893
|
+
if (table && table.fieldExists('svg-symbol')) return 'svg-symbol';
|
|
15894
|
+
if (table && table.fieldExists('label-text')) return 'label';
|
|
15895
|
+
if (table && table.fieldExists('r')) return 'circle';
|
|
15896
|
+
return 'unstyled';
|
|
14634
15897
|
}
|
|
14635
15898
|
|
|
14636
|
-
function
|
|
14637
|
-
|
|
15899
|
+
function getCommonValue(field) {
|
|
15900
|
+
var table = targetLayer && targetLayer.data;
|
|
15901
|
+
var records = table && table.getRecords();
|
|
15902
|
+
var ids = getTargetIds();
|
|
15903
|
+
var value, val;
|
|
15904
|
+
if (!records || ids.length === 0) return '';
|
|
15905
|
+
for (var i=0; i<ids.length; i++) {
|
|
15906
|
+
val = records[ids[i]] && records[ids[i]][field];
|
|
15907
|
+
if (i === 0) {
|
|
15908
|
+
value = val;
|
|
15909
|
+
} else if (val != value) {
|
|
15910
|
+
return '';
|
|
15911
|
+
}
|
|
15912
|
+
}
|
|
15913
|
+
return value === undefined || value === null ? '' : value;
|
|
14638
15914
|
}
|
|
14639
15915
|
|
|
14640
|
-
function
|
|
14641
|
-
var
|
|
14642
|
-
|
|
15916
|
+
function getMostCommonNumberValue(field, defaultValue) {
|
|
15917
|
+
var table = targetLayer && targetLayer.data;
|
|
15918
|
+
var records = table && table.getRecords();
|
|
15919
|
+
var ids = getTargetIds();
|
|
15920
|
+
var counts = {};
|
|
15921
|
+
var bestValue = null;
|
|
15922
|
+
var bestCount = 0;
|
|
15923
|
+
var val, key;
|
|
15924
|
+
if (!records || ids.length === 0) return defaultValue;
|
|
15925
|
+
for (var i=0; i<ids.length; i++) {
|
|
15926
|
+
val = Number(records[ids[i]] && records[ids[i]][field]);
|
|
15927
|
+
if (!isFinite(val)) continue;
|
|
15928
|
+
key = String(val);
|
|
15929
|
+
counts[key] = (counts[key] || 0) + 1;
|
|
15930
|
+
if (counts[key] > bestCount) {
|
|
15931
|
+
bestCount = counts[key];
|
|
15932
|
+
bestValue = val;
|
|
15933
|
+
}
|
|
15934
|
+
}
|
|
15935
|
+
return bestValue === null ? defaultValue : bestValue;
|
|
14643
15936
|
}
|
|
14644
15937
|
|
|
14645
|
-
function
|
|
14646
|
-
|
|
15938
|
+
function styleFieldIsUnset(field) {
|
|
15939
|
+
var table = targetLayer && targetLayer.data;
|
|
15940
|
+
var records = table && table.getRecords();
|
|
15941
|
+
var ids = getTargetIds();
|
|
15942
|
+
var val;
|
|
15943
|
+
if (!records || ids.length === 0) return true;
|
|
15944
|
+
for (var i=0; i<ids.length; i++) {
|
|
15945
|
+
val = records[ids[i]] && records[ids[i]][field];
|
|
15946
|
+
if (val !== undefined && val !== null && val !== '') return false;
|
|
15947
|
+
}
|
|
15948
|
+
return true;
|
|
14647
15949
|
}
|
|
14648
15950
|
|
|
14649
|
-
function
|
|
14650
|
-
|
|
14651
|
-
|
|
14652
|
-
|
|
14653
|
-
|
|
14654
|
-
|
|
14655
|
-
|
|
14656
|
-
|
|
14657
|
-
|
|
15951
|
+
function addTargetOption(parts) {
|
|
15952
|
+
if (getActiveLayer() != targetLayer) {
|
|
15953
|
+
parts.push('target=' + internal.formatOptionValue(internal.getLayerTargetId(gui.model, targetLayer)));
|
|
15954
|
+
}
|
|
15955
|
+
}
|
|
15956
|
+
|
|
15957
|
+
function getSelectionIds() {
|
|
15958
|
+
return hit ? hit.getSelectionIds() : [];
|
|
15959
|
+
}
|
|
15960
|
+
|
|
15961
|
+
function getTargetIds() {
|
|
15962
|
+
var ids = getSelectionIds();
|
|
15963
|
+
if (!targetLayer) return [];
|
|
15964
|
+
return ids.length > 0 ? ids : getAllFeatureIds(targetLayer);
|
|
14658
15965
|
}
|
|
14659
15966
|
|
|
14660
|
-
function
|
|
14661
|
-
var
|
|
14662
|
-
var
|
|
14663
|
-
|
|
14664
|
-
var max = Math.max(r, g, b);
|
|
14665
|
-
var min = Math.min(r, g, b);
|
|
14666
|
-
var d = max - min;
|
|
14667
|
-
var h = 0;
|
|
14668
|
-
if (d) {
|
|
14669
|
-
if (max == r) h = ((g - b) / d) % 6;
|
|
14670
|
-
else if (max == g) h = (b - r) / d + 2;
|
|
14671
|
-
else h = (r - g) / d + 4;
|
|
14672
|
-
h *= 60;
|
|
14673
|
-
if (h < 0) h += 360;
|
|
15967
|
+
function getAllFeatureIds(lyr) {
|
|
15968
|
+
var ids = [];
|
|
15969
|
+
for (var i=0, n=internal.getFeatureCount(lyr); i<n; i++) {
|
|
15970
|
+
ids.push(i);
|
|
14674
15971
|
}
|
|
14675
|
-
return
|
|
14676
|
-
h: Math.round(h / 360 * 255),
|
|
14677
|
-
s: Math.round(max === 0 ? 0 : d / max * 255),
|
|
14678
|
-
b: max
|
|
14679
|
-
};
|
|
15972
|
+
return ids;
|
|
14680
15973
|
}
|
|
14681
15974
|
|
|
14682
|
-
function
|
|
14683
|
-
|
|
14684
|
-
|
|
14685
|
-
return val.toString(16).padStart(2, '0');
|
|
14686
|
-
}).join('');
|
|
15975
|
+
function clearSelection() {
|
|
15976
|
+
if (hit) hit.clearSelection();
|
|
15977
|
+
updateControls();
|
|
14687
15978
|
}
|
|
14688
15979
|
|
|
14689
|
-
function
|
|
14690
|
-
|
|
14691
|
-
|
|
14692
|
-
var v = hsb.b / 255;
|
|
14693
|
-
var c = v * s;
|
|
14694
|
-
var x = c * (1 - Math.abs((h / 60) % 2 - 1));
|
|
14695
|
-
var m = v - c;
|
|
14696
|
-
var rgb = h < 60 ? [c, x, 0] :
|
|
14697
|
-
h < 120 ? [x, c, 0] :
|
|
14698
|
-
h < 180 ? [0, c, x] :
|
|
14699
|
-
h < 240 ? [0, x, c] :
|
|
14700
|
-
h < 300 ? [x, 0, c] : [c, 0, x];
|
|
14701
|
-
return {
|
|
14702
|
-
r: Math.round((rgb[0] + m) * 255),
|
|
14703
|
-
g: Math.round((rgb[1] + m) * 255),
|
|
14704
|
-
b: Math.round((rgb[2] + m) * 255)
|
|
14705
|
-
};
|
|
15980
|
+
function updateEditingStatus(count) {
|
|
15981
|
+
editingStatus.text(count > 0 ? 'Editing: ' + count + ' selected' : 'Editing: all');
|
|
15982
|
+
clearLink.classed('hidden', count === 0);
|
|
14706
15983
|
}
|
|
14707
15984
|
|
|
14708
|
-
function
|
|
14709
|
-
|
|
15985
|
+
function setCircleColor(control, color) {
|
|
15986
|
+
control.input.node().value = color;
|
|
15987
|
+
control.chit.css('background-color', isHexColor(color) ? color : 'transparent');
|
|
14710
15988
|
}
|
|
14711
15989
|
|
|
14712
|
-
function
|
|
14713
|
-
|
|
15990
|
+
function parseOpacityValue(str) {
|
|
15991
|
+
var pct = Number(String(str).replace('%', '').trim());
|
|
15992
|
+
if (!isFinite(pct)) return null;
|
|
15993
|
+
return Math.max(0, Math.min(100, pct)) / 100;
|
|
14714
15994
|
}
|
|
14715
15995
|
|
|
14716
|
-
function
|
|
14717
|
-
|
|
15996
|
+
function parsePositiveNumber(str) {
|
|
15997
|
+
if (String(str).trim() === '') return null;
|
|
15998
|
+
var val = Number(String(str).trim());
|
|
15999
|
+
return isFinite(val) && val >= 0 ? val : null;
|
|
14718
16000
|
}
|
|
14719
16001
|
|
|
14720
|
-
function
|
|
14721
|
-
|
|
16002
|
+
function formatOpacityPct(val) {
|
|
16003
|
+
val = Number(val);
|
|
16004
|
+
return isFinite(val) ? Math.round(Math.max(0, Math.min(1, val)) * 100) + '%' : '';
|
|
14722
16005
|
}
|
|
14723
16006
|
|
|
14724
|
-
function
|
|
14725
|
-
|
|
16007
|
+
function formatNumberValue(val) {
|
|
16008
|
+
val = Number(val);
|
|
16009
|
+
return isFinite(val) ? String(val) : '';
|
|
14726
16010
|
}
|
|
14727
16011
|
|
|
14728
|
-
function
|
|
14729
|
-
return
|
|
16012
|
+
function getFieldExpression(field) {
|
|
16013
|
+
return 'd[' + JSON.stringify(field) + ']';
|
|
14730
16014
|
}
|
|
14731
16015
|
|
|
14732
|
-
function
|
|
14733
|
-
var
|
|
14734
|
-
|
|
16016
|
+
function getActiveLayer() {
|
|
16017
|
+
var active = gui.model.getActiveLayer();
|
|
16018
|
+
return active && active.layer;
|
|
16019
|
+
}
|
|
16020
|
+
|
|
16021
|
+
function syncTargetLayer() {
|
|
14735
16022
|
var lyr = getActiveLayer();
|
|
14736
|
-
|
|
14737
|
-
if (
|
|
14738
|
-
|
|
14739
|
-
|
|
14740
|
-
});
|
|
14741
|
-
gui.dispatchEvent('data_preupdate', {ids: ids});
|
|
14742
|
-
if (hasNewFields) {
|
|
14743
|
-
table.captureSchemaBefore({operation: 'label-style', fields: fields});
|
|
14744
|
-
} else {
|
|
14745
|
-
table.captureFieldsBefore(fields, {operation: 'label-style'});
|
|
14746
|
-
}
|
|
14747
|
-
updateRecords(ids, table, updateRecord);
|
|
14748
|
-
if (hasNewFields) {
|
|
14749
|
-
table.markSchemaChanged({operation: 'label-style'});
|
|
16023
|
+
if (lyr == targetLayer) return;
|
|
16024
|
+
if (layerCanBeStyled(lyr)) {
|
|
16025
|
+
targetLayer = lyr;
|
|
16026
|
+
if (hit) hit.clearSelection();
|
|
14750
16027
|
} else {
|
|
14751
|
-
|
|
16028
|
+
targetLayer = null;
|
|
14752
16029
|
}
|
|
14753
|
-
gui.dispatchEvent('data_postupdate', {ids: ids});
|
|
14754
|
-
gui.model.updated({style: true, same_table: true});
|
|
14755
|
-
updatePendingStyleHistory(lyr, ids, fields);
|
|
14756
|
-
setTimeout(updateSelectionDisplay, 0);
|
|
14757
|
-
updateControls();
|
|
14758
|
-
updateSelectionDisplay();
|
|
14759
16030
|
}
|
|
14760
16031
|
|
|
14761
|
-
function
|
|
14762
|
-
|
|
14763
|
-
|
|
14764
|
-
var rec = records[id] || {};
|
|
14765
|
-
updateRecord(rec);
|
|
14766
|
-
records[id] = rec;
|
|
14767
|
-
});
|
|
16032
|
+
function modelSelectLayer(lyr, dataset) {
|
|
16033
|
+
if (lyr) lyr.hidden = false;
|
|
16034
|
+
gui.model.selectLayer(lyr, dataset);
|
|
14768
16035
|
}
|
|
14769
16036
|
|
|
14770
|
-
function
|
|
14771
|
-
|
|
14772
|
-
|
|
14773
|
-
var textNode = getTextNodeById(id);
|
|
14774
|
-
if (textNode) {
|
|
14775
|
-
textNode.classList.add('label-style-selected');
|
|
14776
|
-
}
|
|
14777
|
-
});
|
|
16037
|
+
function modeMatchesActiveLayer(mode) {
|
|
16038
|
+
var lyr = getActiveLayer();
|
|
16039
|
+
return mode == 'point_style' && layerCanBeStyled(lyr);
|
|
14778
16040
|
}
|
|
14779
16041
|
|
|
14780
|
-
function
|
|
14781
|
-
|
|
14782
|
-
var container = lyr && lyr.gui && lyr.gui.svg_container;
|
|
14783
|
-
if (!container) return;
|
|
14784
|
-
container.querySelectorAll('.label-style-selected').forEach(function(node) {
|
|
14785
|
-
node.classList.remove('label-style-selected');
|
|
14786
|
-
});
|
|
16042
|
+
function layerCanBeStyled(lyr) {
|
|
16043
|
+
return !!(lyr && lyr.geometry_type == 'point');
|
|
14787
16044
|
}
|
|
14788
16045
|
|
|
14789
|
-
function
|
|
14790
|
-
|
|
14791
|
-
var container = lyr && lyr.gui && lyr.gui.svg_container;
|
|
14792
|
-
var symbol = container && container.querySelector('[data-id="' + id + '"]');
|
|
14793
|
-
if (!symbol) return null;
|
|
14794
|
-
return symbol.tagName == 'text' ? symbol : symbol.querySelector('text');
|
|
16046
|
+
function quoteCommandValue(str) {
|
|
16047
|
+
return "'" + String(str).replace(/'/g, "\\'") + "'";
|
|
14795
16048
|
}
|
|
14796
|
-
|
|
14797
16049
|
}
|
|
14798
16050
|
|
|
14799
16051
|
function Model(gui) {
|
|
@@ -15438,6 +16690,7 @@
|
|
|
15438
16690
|
var targetLayer;
|
|
15439
16691
|
var hitTest;
|
|
15440
16692
|
var pinnedOn; // used in multi-edit mode (selection) for toggling pinning behavior
|
|
16693
|
+
var suppressChangeEvent = false;
|
|
15441
16694
|
|
|
15442
16695
|
// event priority is higher than navigation, so stopping propagation disables
|
|
15443
16696
|
// pan navigation
|
|
@@ -15514,7 +16767,8 @@
|
|
|
15514
16767
|
|
|
15515
16768
|
function selectable() {
|
|
15516
16769
|
var mode = interactionMode();
|
|
15517
|
-
return mode == 'selection' || mode == 'label_style'
|
|
16770
|
+
return mode == 'selection' || mode == 'label_style' ||
|
|
16771
|
+
mode == 'point_style' || mode == 'line_style' || mode == 'polygon_style';
|
|
15518
16772
|
}
|
|
15519
16773
|
|
|
15520
16774
|
function pinnable() {
|
|
@@ -15532,7 +16786,8 @@
|
|
|
15532
16786
|
var mode = interactionMode();
|
|
15533
16787
|
// click used to pin popup and select features
|
|
15534
16788
|
return mode == 'data' || mode == 'info' || mode == 'selection' ||
|
|
15535
|
-
mode == 'label_style' || mode == '
|
|
16789
|
+
mode == 'label_style' || mode == 'point_style' || mode == 'line_style' || mode == 'polygon_style' ||
|
|
16790
|
+
mode == 'rectangles' || mode == 'edit_points';
|
|
15536
16791
|
}
|
|
15537
16792
|
|
|
15538
16793
|
self.getHitId = function() {
|
|
@@ -15656,12 +16911,13 @@
|
|
|
15656
16911
|
// make sure popup is unpinned and turned off when switching editing modes
|
|
15657
16912
|
// (some modes do not support pinning)
|
|
15658
16913
|
gui.on('interaction_mode_change', function(e) {
|
|
15659
|
-
|
|
16914
|
+
clearSelectionSilently();
|
|
15660
16915
|
if (gui.interaction.modeUsesHitDetection(e.mode)) {
|
|
15661
16916
|
turnOn(e.mode);
|
|
15662
16917
|
} else {
|
|
15663
16918
|
turnOff();
|
|
15664
16919
|
}
|
|
16920
|
+
gui.dispatchEvent('map-needs-refresh');
|
|
15665
16921
|
});
|
|
15666
16922
|
|
|
15667
16923
|
gui.on('undo_redo_pre', function() {
|
|
@@ -15685,7 +16941,7 @@
|
|
|
15685
16941
|
|
|
15686
16942
|
// TODO: move pinning to inspection control?
|
|
15687
16943
|
if (clickable()) {
|
|
15688
|
-
updateSelectionState(convertClickDataToSelectionData(hitTest(e)));
|
|
16944
|
+
updateSelectionState(convertClickDataToSelectionData(hitTest(e), e));
|
|
15689
16945
|
}
|
|
15690
16946
|
|
|
15691
16947
|
if (pinned && interactionMode() == 'edit_points') {
|
|
@@ -15727,7 +16983,7 @@
|
|
|
15727
16983
|
|
|
15728
16984
|
// Translates feature hit data from a mouse click into feature selection data
|
|
15729
16985
|
// hitData: hit data from a mouse click
|
|
15730
|
-
function convertClickDataToSelectionData(hitData) {
|
|
16986
|
+
function convertClickDataToSelectionData(hitData, e) {
|
|
15731
16987
|
// mergeCurrentState(hitData);
|
|
15732
16988
|
// TOGGLE pinned state under some conditions
|
|
15733
16989
|
var id = hitData.ids.length > 0 ? hitData.ids[0] : -1;
|
|
@@ -15744,13 +17000,32 @@
|
|
|
15744
17000
|
}
|
|
15745
17001
|
if (selectable()) {
|
|
15746
17002
|
if (id > -1) {
|
|
15747
|
-
selectionIds =
|
|
17003
|
+
selectionIds = styleSelectionMode() ?
|
|
17004
|
+
selectStyleFeature(id, e) :
|
|
17005
|
+
toggleId(id, selectionIds);
|
|
15748
17006
|
}
|
|
15749
17007
|
hitData.ids = selectionIds;
|
|
15750
17008
|
}
|
|
15751
17009
|
return hitData;
|
|
15752
17010
|
}
|
|
15753
17011
|
|
|
17012
|
+
function styleSelectionMode() {
|
|
17013
|
+
var mode = interactionMode();
|
|
17014
|
+
return mode == 'label_style' || mode == 'point_style' ||
|
|
17015
|
+
mode == 'line_style' || mode == 'polygon_style';
|
|
17016
|
+
}
|
|
17017
|
+
|
|
17018
|
+
function selectStyleFeature(id, e) {
|
|
17019
|
+
return eventUsesAdditiveSelection(e) ?
|
|
17020
|
+
toggleId(id, selectionIds) :
|
|
17021
|
+
[id];
|
|
17022
|
+
}
|
|
17023
|
+
|
|
17024
|
+
function eventUsesAdditiveSelection(e) {
|
|
17025
|
+
var original = e && e.originalEvent || e;
|
|
17026
|
+
return !!(original && original.shiftKey);
|
|
17027
|
+
}
|
|
17028
|
+
|
|
15754
17029
|
function mergeSelectionModeHoverData(hitData) {
|
|
15755
17030
|
if (hitData.ids.length === 0 || selectionIds.includes(hitData.ids[0])) {
|
|
15756
17031
|
hitData.ids = selectionIds;
|
|
@@ -15806,11 +17081,17 @@
|
|
|
15806
17081
|
|
|
15807
17082
|
storedData = newData;
|
|
15808
17083
|
gui.container.findChild('.map-layers').classed('symbol-hit', nonEmpty);
|
|
15809
|
-
if (active) {
|
|
17084
|
+
if (active && !suppressChangeEvent) {
|
|
15810
17085
|
triggerChangeEvent();
|
|
15811
17086
|
}
|
|
15812
17087
|
}
|
|
15813
17088
|
|
|
17089
|
+
function clearSelectionSilently() {
|
|
17090
|
+
suppressChangeEvent = true;
|
|
17091
|
+
self.clearSelection();
|
|
17092
|
+
suppressChangeEvent = false;
|
|
17093
|
+
}
|
|
17094
|
+
|
|
15814
17095
|
// check if an event is used in the current interaction mode
|
|
15815
17096
|
function eventIsEnabled(type) {
|
|
15816
17097
|
var mode = interactionMode();
|
|
@@ -16850,7 +18131,9 @@
|
|
|
16850
18131
|
|
|
16851
18132
|
function useBoxZoom() {
|
|
16852
18133
|
var mode = gui.getMode();
|
|
16853
|
-
|
|
18134
|
+
var interactionMode = gui.interaction && gui.interaction.getMode();
|
|
18135
|
+
return !'selection_tool,box_tool,rectangle_tool,drawing_tool'.includes(mode) &&
|
|
18136
|
+
!'label_style,point_style,line_style,polygon_style'.includes(interactionMode);
|
|
16854
18137
|
}
|
|
16855
18138
|
|
|
16856
18139
|
function getBoxData(e1, e2) {
|
|
@@ -17472,6 +18755,30 @@
|
|
|
17472
18755
|
strokeWidth: 2.5
|
|
17473
18756
|
}
|
|
17474
18757
|
},
|
|
18758
|
+
styleSelectionStyles = {
|
|
18759
|
+
polygon: {
|
|
18760
|
+
fillColor: null,
|
|
18761
|
+
strokeColor: 'rgb(255, 198, 0)',
|
|
18762
|
+
strokeOpacity: 0.38,
|
|
18763
|
+
strokeWidth: 5,
|
|
18764
|
+
strokeOverlay: true,
|
|
18765
|
+
batchOverlay: true
|
|
18766
|
+
}, polyline: {
|
|
18767
|
+
fillColor: null,
|
|
18768
|
+
strokeColor: 'rgb(255, 198, 0)',
|
|
18769
|
+
strokeOpacity: 0.38,
|
|
18770
|
+
strokeWidth: 5,
|
|
18771
|
+
strokeOverlay: true,
|
|
18772
|
+
batchOverlay: true
|
|
18773
|
+
}, point: {
|
|
18774
|
+
fillColor: null,
|
|
18775
|
+
strokeColor: 'rgb(255, 198, 0)',
|
|
18776
|
+
strokeOpacity: 0.38,
|
|
18777
|
+
strokeWidth: 5,
|
|
18778
|
+
strokeOverlay: true,
|
|
18779
|
+
batchOverlay: true
|
|
18780
|
+
}
|
|
18781
|
+
},
|
|
17475
18782
|
// currently not used -- selection hover is not styled
|
|
17476
18783
|
selectionHoverStyles = {
|
|
17477
18784
|
polygon: {
|
|
@@ -17522,11 +18829,22 @@
|
|
|
17522
18829
|
return [lyr];
|
|
17523
18830
|
}
|
|
17524
18831
|
layers = [];
|
|
18832
|
+
if (styleOpts.interactionMode == 'line_style' || styleOpts.interactionMode == 'polygon_style' ||
|
|
18833
|
+
styleOpts.interactionMode == 'point_style') {
|
|
18834
|
+
ids = hitData.ids || [];
|
|
18835
|
+
if (ids.length > 0) {
|
|
18836
|
+
lyr = getOverlayLayer(activeLyr, ids);
|
|
18837
|
+
outlineStyle = getSelectionStyle(displayLyr.geometry_type, styleOpts);
|
|
18838
|
+
lyr.gui.style = getOverlayStyle(activeLyr, ids, outlineStyle);
|
|
18839
|
+
layers.push(lyr);
|
|
18840
|
+
}
|
|
18841
|
+
return layers;
|
|
18842
|
+
}
|
|
17525
18843
|
// layer containing selected features, not including hover or pinned feature
|
|
17526
18844
|
ids = utils$1.difference(hitData.ids || [], [hitData.id]);
|
|
17527
18845
|
if (ids.length > 0) {
|
|
17528
18846
|
lyr = getOverlayLayer(activeLyr, ids);
|
|
17529
|
-
outlineStyle =
|
|
18847
|
+
outlineStyle = getSelectionStyle(displayLyr.geometry_type, styleOpts);
|
|
17530
18848
|
lyr.gui.style = getOverlayStyle(activeLyr, ids, outlineStyle);
|
|
17531
18849
|
layers.push(lyr);
|
|
17532
18850
|
}
|
|
@@ -17558,32 +18876,58 @@
|
|
|
17558
18876
|
return;
|
|
17559
18877
|
}
|
|
17560
18878
|
var idx = ids[i];
|
|
18879
|
+
if (outlineStyle.strokeOverlay) {
|
|
18880
|
+
delete style.strokeWidth;
|
|
18881
|
+
delete style.strokeColor;
|
|
18882
|
+
}
|
|
17561
18883
|
baseStyler(style, idx);
|
|
17562
18884
|
if (geomType == 'point') {
|
|
17563
|
-
if (
|
|
17564
|
-
style.radius
|
|
17565
|
-
|
|
17566
|
-
|
|
18885
|
+
if (outlineStyle.strokeOverlay) {
|
|
18886
|
+
if (style.radius > 0) {
|
|
18887
|
+
style.radius += (style.strokeWidth || 0) / 2 + outlineStyle.strokeWidth / 2;
|
|
18888
|
+
}
|
|
18889
|
+
style.fillColor = null;
|
|
18890
|
+
style.strokeColor = outlineStyle.strokeColor;
|
|
18891
|
+
style.strokeWidth = outlineStyle.strokeWidth;
|
|
18892
|
+
} else {
|
|
18893
|
+
if (style.radius > 0) {
|
|
18894
|
+
style.radius += 0.8;
|
|
18895
|
+
if (style.strokeWidth > 0) {
|
|
18896
|
+
style.strokeColor = outlineStyle.dotColor;
|
|
18897
|
+
}
|
|
17567
18898
|
}
|
|
18899
|
+
style.fillColor = outlineStyle.dotColor;
|
|
17568
18900
|
}
|
|
17569
|
-
style.fillColor = outlineStyle.dotColor;
|
|
17570
18901
|
} else {
|
|
17571
18902
|
style.strokeColor = outlineStyle.strokeColor;
|
|
17572
18903
|
style.fillColor = outlineStyle.fillColor;
|
|
17573
|
-
style.strokeWidth =
|
|
18904
|
+
style.strokeWidth = outlineStyle.strokeOverlay ?
|
|
18905
|
+
(style.strokeWidth || 0) + outlineStyle.strokeWidth :
|
|
18906
|
+
Math.max(outlineStyle.strokeWidth, style.strokeWidth || 0);
|
|
17574
18907
|
}
|
|
17575
18908
|
style.opacity = 1;
|
|
17576
18909
|
style.fillOpacity = 1;
|
|
17577
|
-
style.strokeOpacity = 1;
|
|
18910
|
+
style.strokeOpacity = outlineStyle.strokeOpacity >= 0 ? outlineStyle.strokeOpacity : 1;
|
|
17578
18911
|
};
|
|
17579
18912
|
var style = Object.assign({}, baseStyle, {ids, overlay: true, type: 'styled', styler});
|
|
17580
|
-
if (
|
|
18913
|
+
if (outlineStyle.batchOverlay) {
|
|
18914
|
+
style.batchOverlay = true;
|
|
18915
|
+
}
|
|
18916
|
+
if (baseStyle.dotSize > 0 && outlineStyle.dotSize > 0) {
|
|
17581
18917
|
// dot size must be a static property (not applied by styler function)
|
|
17582
18918
|
style.dotSize = outlineStyle.dotSize;
|
|
17583
18919
|
}
|
|
17584
18920
|
return style;
|
|
17585
18921
|
}
|
|
17586
18922
|
|
|
18923
|
+
function getSelectionStyle(geomType, styleOpts) {
|
|
18924
|
+
if (styleOpts.interactionMode == 'line_style' || styleOpts.interactionMode == 'polygon_style' ||
|
|
18925
|
+
styleOpts.interactionMode == 'point_style') {
|
|
18926
|
+
return styleSelectionStyles[geomType] || selectionStyles[geomType];
|
|
18927
|
+
}
|
|
18928
|
+
return selectionStyles[geomType];
|
|
18929
|
+
}
|
|
18930
|
+
|
|
17587
18931
|
// style for vertex edit mode
|
|
17588
18932
|
function getVertexStyle(o) {
|
|
17589
18933
|
return {
|
|
@@ -19914,21 +21258,24 @@
|
|
|
19914
21258
|
var draw = getShapePencil(arcs, _ext);
|
|
19915
21259
|
var key, item, shp;
|
|
19916
21260
|
var styler = style.styler || null;
|
|
21261
|
+
var drawStyle = styler ? utils$1.defaults({}, style) : style;
|
|
19917
21262
|
for (var i=0; i<shapes.length; i++) {
|
|
19918
21263
|
shp = shapes[i];
|
|
19919
21264
|
if (!shp || filter && !filter(i)) continue;
|
|
19920
21265
|
if (styler) {
|
|
19921
|
-
styler(
|
|
21266
|
+
styler(drawStyle, i);
|
|
19922
21267
|
}
|
|
19923
|
-
if (
|
|
21268
|
+
if (!drawStyle.batchOverlay && (drawStyle.overlay ||
|
|
21269
|
+
drawStyle.opacity < 1 || drawStyle.fillOpacity < 1 ||
|
|
21270
|
+
drawStyle.strokeOpacity < 1 || drawStyle.fillEffect)) {
|
|
19924
21271
|
// don't batch shapes with opacity, in case they overlap
|
|
19925
|
-
drawPaths([shp], startPath, draw,
|
|
21272
|
+
drawPaths([shp], startPath, draw, drawStyle);
|
|
19926
21273
|
continue;
|
|
19927
21274
|
}
|
|
19928
|
-
key = getStyleKey(
|
|
21275
|
+
key = getStyleKey(drawStyle);
|
|
19929
21276
|
if (key in styleIndex === false) {
|
|
19930
21277
|
styleIndex[key] = {
|
|
19931
|
-
style: utils$1.defaults({},
|
|
21278
|
+
style: utils$1.defaults({}, drawStyle),
|
|
19932
21279
|
shapes: []
|
|
19933
21280
|
};
|
|
19934
21281
|
}
|
|
@@ -22294,6 +23641,8 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
22294
23641
|
gui.interaction = new InteractionMode(gui);
|
|
22295
23642
|
gui.editToolbar = new EditToolbar(gui);
|
|
22296
23643
|
gui.labelTool = new LabelTool(gui);
|
|
23644
|
+
gui.layerStyleTool = new LayerStyleTool(gui);
|
|
23645
|
+
gui.pointStyleTool = new PointStyleTool(gui);
|
|
22297
23646
|
|
|
22298
23647
|
gui.showProgressMessage = function(msg) {
|
|
22299
23648
|
if (!gui.progressMessage) {
|