mapshaper 0.7.17 → 0.7.18
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 +33 -12
- package/package.json +2 -2
- package/www/index.html +1 -1
- package/www/mapshaper-gui.js +2625 -1304
- package/www/mapshaper.js +33 -12
- package/www/page.css +239 -2
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,1625 @@
|
|
|
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
|
-
var lyr = internal.copyLayer(srcLyr);
|
|
13904
|
-
delete lyr.gui;
|
|
13905
|
-
lyr.name = 'labels';
|
|
13906
|
-
return lyr;
|
|
13907
|
-
}
|
|
14873
|
+
}
|
|
13908
14874
|
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
|
|
13912
|
-
|
|
13913
|
-
|
|
13914
|
-
|
|
14875
|
+
var savedStylesKey = 'layer_style_presets';
|
|
14876
|
+
var styleFields = ['stroke', 'stroke-width', 'stroke-opacity', 'fill', 'fill-opacity'];
|
|
14877
|
+
|
|
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
|
+
});
|
|
15056
|
+
}
|
|
15057
|
+
|
|
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
|
+
});
|
|
14032
15074
|
}
|
|
14033
15075
|
|
|
14034
|
-
function
|
|
14035
|
-
|
|
15076
|
+
function updateControls() {
|
|
15077
|
+
var geom = targetLayer && targetLayer.geometry_type;
|
|
15078
|
+
var manualIds = getSelectionIds();
|
|
15079
|
+
if (!targetLayer) return;
|
|
15080
|
+
title.text(geom == 'polygon' ? 'Polygon styles' : 'Line styles');
|
|
15081
|
+
updateEditingStatus(manualIds.length);
|
|
15082
|
+
strokeControl.row.show();
|
|
15083
|
+
fillControl.row.classed('hidden', geom != 'polygon');
|
|
15084
|
+
updateColorControl(strokeControl);
|
|
15085
|
+
updateColorControl(fillControl);
|
|
15086
|
+
updateStrokeWidthControl();
|
|
15087
|
+
updateNumberControl(strokeOpacityInput, 'stroke-opacity', 1, formatOpacityPct);
|
|
15088
|
+
updateNumberControl(fillOpacityInput, 'fill-opacity', 1, formatOpacityPct);
|
|
15089
|
+
randomFillBtn.classed('hidden', geom != 'polygon');
|
|
15090
|
+
presetControl.render();
|
|
15091
|
+
updateSavedStyleControls();
|
|
14036
15092
|
}
|
|
14037
15093
|
|
|
14038
|
-
function
|
|
14039
|
-
|
|
14040
|
-
|
|
14041
|
-
|
|
15094
|
+
function updateColorControl(control) {
|
|
15095
|
+
var value = getCommonStyleValue(control.field);
|
|
15096
|
+
setColorControlValue(control, value);
|
|
15097
|
+
if (isHexColor(value)) {
|
|
15098
|
+
control.picker.setColor(value);
|
|
15099
|
+
} else {
|
|
15100
|
+
control.picker.hide();
|
|
14042
15101
|
}
|
|
14043
|
-
return true;
|
|
14044
15102
|
}
|
|
14045
15103
|
|
|
14046
|
-
function
|
|
14047
|
-
|
|
14048
|
-
|
|
14049
|
-
if (copyLyr) {
|
|
14050
|
-
cmd += '-filter true + name=' + internal.formatOptionValue(copyLyr.name) + ' ';
|
|
14051
|
-
}
|
|
14052
|
-
cmd += '-style label-text=' + quoteCommandValue(expr);
|
|
14053
|
-
gui.session.consoleCommands(cmd);
|
|
15104
|
+
function setColorControlValue(control, value) {
|
|
15105
|
+
control.input.node().value = value || '';
|
|
15106
|
+
control.chit.css('background-color', isHexColor(value) ? value : 'transparent');
|
|
14054
15107
|
}
|
|
14055
15108
|
|
|
14056
|
-
function
|
|
14057
|
-
|
|
15109
|
+
function updateNumberControl(input, field, defaultValue, formatter) {
|
|
15110
|
+
var value = getCommonStyleValue(field);
|
|
15111
|
+
input.node().value = formatter(value === '' || value === undefined || value === null ? defaultValue : value);
|
|
14058
15112
|
}
|
|
14059
15113
|
|
|
14060
|
-
function
|
|
14061
|
-
var
|
|
14062
|
-
|
|
14063
|
-
|
|
14064
|
-
|
|
14065
|
-
|
|
15114
|
+
function updateStrokeWidthControl() {
|
|
15115
|
+
var value = getCommonStyleValue('stroke-width');
|
|
15116
|
+
strokeWidthClickText.value(formatNumberValue(value === '' || value === undefined || value === null ? getDefaultStrokeWidth() : value));
|
|
15117
|
+
}
|
|
15118
|
+
|
|
15119
|
+
function nudgeStrokeWidth(direction) {
|
|
15120
|
+
var value = Number(getCommonStyleValue('stroke-width'));
|
|
15121
|
+
if (!isFinite(value)) value = getDefaultStrokeWidth();
|
|
15122
|
+
applyStrokeWidthStyle(getNextStrokeWidth(value, direction));
|
|
15123
|
+
}
|
|
15124
|
+
|
|
15125
|
+
function getNextStrokeWidth(value, direction) {
|
|
15126
|
+
var baseSteps = [0, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4];
|
|
15127
|
+
var i;
|
|
15128
|
+
if (direction > 0) {
|
|
15129
|
+
for (i=0; i<baseSteps.length; i++) {
|
|
15130
|
+
if (value < baseSteps[i]) return baseSteps[i];
|
|
15131
|
+
}
|
|
15132
|
+
return Math.floor(value) + 1;
|
|
14066
15133
|
}
|
|
14067
|
-
|
|
14068
|
-
|
|
14069
|
-
hit.addSelectionIds(ids);
|
|
15134
|
+
for (i=baseSteps.length - 1; i>=0; i--) {
|
|
15135
|
+
if (value > baseSteps[i]) return baseSteps[i];
|
|
14070
15136
|
}
|
|
14071
|
-
|
|
14072
|
-
updateControls();
|
|
15137
|
+
return baseSteps[0];
|
|
14073
15138
|
}
|
|
14074
15139
|
|
|
14075
|
-
function
|
|
14076
|
-
|
|
14077
|
-
updateSelectionDisplay();
|
|
14078
|
-
updateControls();
|
|
15140
|
+
function applyLayerStyle(field, value) {
|
|
15141
|
+
runStyleCommand([[field, value]]);
|
|
14079
15142
|
}
|
|
14080
15143
|
|
|
14081
|
-
function
|
|
14082
|
-
var
|
|
14083
|
-
|
|
15144
|
+
function applyColorControlStyle(control, color) {
|
|
15145
|
+
var styles = [[control.field, color]];
|
|
15146
|
+
if (control.field == 'stroke' && strokeWidthIsUnsetForTargets()) {
|
|
15147
|
+
styles.push(['stroke-width', 1]);
|
|
15148
|
+
}
|
|
15149
|
+
runStyleCommand(styles);
|
|
14084
15150
|
}
|
|
14085
15151
|
|
|
14086
|
-
function
|
|
14087
|
-
var
|
|
14088
|
-
|
|
15152
|
+
function applyStrokeWidthStyle(value) {
|
|
15153
|
+
var styles = [['stroke-width', value]];
|
|
15154
|
+
if (value > 0 && styleFieldIsUnsetForTargets('stroke')) {
|
|
15155
|
+
styles.push(['stroke', strokeControl.defaultColor]);
|
|
15156
|
+
}
|
|
15157
|
+
runStyleCommand(styles);
|
|
14089
15158
|
}
|
|
14090
15159
|
|
|
14091
|
-
function
|
|
14092
|
-
|
|
15160
|
+
function runStyleCommand(styles, opts) {
|
|
15161
|
+
var parts = ['-style'];
|
|
15162
|
+
var ids = getTargetIds();
|
|
15163
|
+
if (!gui.console || !targetLayer || ids.length === 0) return;
|
|
15164
|
+
if (!opts || !opts.preservePreset) {
|
|
15165
|
+
presetControl.clearSelection();
|
|
15166
|
+
}
|
|
15167
|
+
styles.forEach(function(style) {
|
|
15168
|
+
parts.push(style[0] + '=' + quoteCommandValue(style[1]));
|
|
15169
|
+
});
|
|
15170
|
+
addTargetOption(parts);
|
|
15171
|
+
if (ids.length < internal.getFeatureCount(targetLayer)) {
|
|
15172
|
+
parts.push('ids=' + ids.join(','));
|
|
15173
|
+
}
|
|
15174
|
+
runCommand(parts.join(' '), 'Style layer');
|
|
14093
15175
|
}
|
|
14094
15176
|
|
|
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 : '');
|
|
15177
|
+
function applyDefaultLineStyle() {
|
|
15178
|
+
var styles = [];
|
|
15179
|
+
if (!targetLayer || targetLayer.geometry_type != 'polyline') return;
|
|
15180
|
+
if (styleFieldIsUnsetForTargets('stroke-width')) {
|
|
15181
|
+
styles.push(['stroke-width', 1]);
|
|
15182
|
+
}
|
|
15183
|
+
if (styles.length > 0) {
|
|
15184
|
+
runStyleCommand(styles);
|
|
15185
|
+
}
|
|
14117
15186
|
}
|
|
14118
15187
|
|
|
14119
|
-
function
|
|
14120
|
-
var
|
|
14121
|
-
|
|
14122
|
-
|
|
14123
|
-
|
|
14124
|
-
}
|
|
15188
|
+
function applyRandomFillColors() {
|
|
15189
|
+
var cmd = '-classify colors=random non-adjacent';
|
|
15190
|
+
if (!gui.console || !targetLayer || targetLayer.geometry_type != 'polygon') return;
|
|
15191
|
+
if (getActiveLayer() != targetLayer) {
|
|
15192
|
+
cmd += ' target=' + internal.formatOptionValue(internal.getLayerTargetId(gui.model, targetLayer));
|
|
15193
|
+
}
|
|
15194
|
+
presetControl.clearSelection();
|
|
15195
|
+
runCommand(cmd, 'Random fill colors');
|
|
14125
15196
|
}
|
|
14126
15197
|
|
|
14127
|
-
function
|
|
14128
|
-
|
|
14129
|
-
|
|
14130
|
-
|
|
14131
|
-
setPanelButtonDisabled(btn, disabled);
|
|
15198
|
+
function runCommand(cmd, title) {
|
|
15199
|
+
runGuiEditCommand(gui, cmd, {
|
|
15200
|
+
title: title,
|
|
15201
|
+
onDone: updateControls
|
|
14132
15202
|
});
|
|
14133
15203
|
}
|
|
14134
15204
|
|
|
14135
|
-
function
|
|
14136
|
-
var
|
|
14137
|
-
|
|
14138
|
-
|
|
14139
|
-
|
|
14140
|
-
|
|
14141
|
-
|
|
14142
|
-
|
|
15205
|
+
function applyStyleObject(style) {
|
|
15206
|
+
var styles = [];
|
|
15207
|
+
styleFields.forEach(function(field) {
|
|
15208
|
+
if (field in style) {
|
|
15209
|
+
styles.push([field, style[field]]);
|
|
15210
|
+
}
|
|
15211
|
+
});
|
|
15212
|
+
if (styles.length > 0) {
|
|
15213
|
+
runStyleCommand(styles, {preservePreset: true});
|
|
14143
15214
|
}
|
|
14144
|
-
fontStyleSelect.node().disabled = disabled;
|
|
14145
|
-
fontStyleSelect.node().value = fontStyleVal && fontWeightVal ?
|
|
14146
|
-
fontStyleVal + '|' + fontWeightVal : '';
|
|
14147
15215
|
}
|
|
14148
15216
|
|
|
14149
|
-
function
|
|
14150
|
-
var
|
|
14151
|
-
|
|
14152
|
-
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
|
|
14156
|
-
|
|
15217
|
+
function getCurrentStyle() {
|
|
15218
|
+
var style = {};
|
|
15219
|
+
addStyleValue(style, 'stroke', getControlValue(strokeControl.input));
|
|
15220
|
+
addStyleValue(style, 'stroke-width', parsePositiveNumber(strokeWidthClickText.value()));
|
|
15221
|
+
addStyleValue(style, 'stroke-opacity', parseOpacityValue(strokeOpacityInput.node().value));
|
|
15222
|
+
if (targetLayer && targetLayer.geometry_type == 'polygon') {
|
|
15223
|
+
addStyleValue(style, 'fill', getControlValue(fillControl.input));
|
|
15224
|
+
addStyleValue(style, 'fill-opacity', parseOpacityValue(fillOpacityInput.node().value));
|
|
14157
15225
|
}
|
|
14158
|
-
|
|
14159
|
-
|
|
14160
|
-
|
|
14161
|
-
|
|
15226
|
+
return style;
|
|
15227
|
+
}
|
|
15228
|
+
|
|
15229
|
+
function addStyleValue(style, field, value) {
|
|
15230
|
+
if (value || value === 0) {
|
|
15231
|
+
style[field] = value;
|
|
14162
15232
|
}
|
|
14163
15233
|
}
|
|
14164
15234
|
|
|
14165
|
-
function
|
|
14166
|
-
|
|
14167
|
-
cssInput.node().value = cssVal || '';
|
|
15235
|
+
function getControlValue(input) {
|
|
15236
|
+
return input.node().value.trim();
|
|
14168
15237
|
}
|
|
14169
15238
|
|
|
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
|
-
});
|
|
15239
|
+
function updateSavedStyleControls() {
|
|
15240
|
+
presetControl.update();
|
|
14176
15241
|
}
|
|
14177
15242
|
|
|
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
|
-
});
|
|
15243
|
+
function getStyleType() {
|
|
15244
|
+
return targetLayer && targetLayer.geometry_type == 'polygon' ? 'polygon' : 'line';
|
|
14184
15245
|
}
|
|
14185
15246
|
|
|
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
|
-
});
|
|
15247
|
+
function getSortKey(item) {
|
|
15248
|
+
return (item.type || '') + '\t' + String(item.name || '').toLowerCase() + '\t' + (item.id || '');
|
|
14192
15249
|
}
|
|
14193
15250
|
|
|
14194
|
-
function
|
|
14195
|
-
var
|
|
14196
|
-
|
|
14197
|
-
|
|
14198
|
-
|
|
15251
|
+
function clearLayerStyle() {
|
|
15252
|
+
var parts = ['-style clear'];
|
|
15253
|
+
if (!gui.console || !targetLayer) return;
|
|
15254
|
+
presetControl.clearSelection();
|
|
15255
|
+
addTargetOption(parts);
|
|
15256
|
+
runCommand(parts.join(' '), 'Clear style');
|
|
15257
|
+
}
|
|
15258
|
+
|
|
15259
|
+
function addTargetOption(parts) {
|
|
15260
|
+
if (getActiveLayer() != targetLayer) {
|
|
15261
|
+
parts.push('target=' + internal.formatOptionValue(internal.getLayerTargetId(gui.model, targetLayer)));
|
|
15262
|
+
}
|
|
15263
|
+
}
|
|
15264
|
+
|
|
15265
|
+
function getCommonStyleValue(field, idsArg) {
|
|
15266
|
+
var records = targetLayer && targetLayer.data && targetLayer.data.getRecords();
|
|
15267
|
+
var ids;
|
|
15268
|
+
var value, val;
|
|
15269
|
+
if (!records) return '';
|
|
15270
|
+
ids = idsArg || getTargetIds();
|
|
15271
|
+
if (ids.length === 0) return '';
|
|
14199
15272
|
for (var i=0; i<ids.length; i++) {
|
|
14200
15273
|
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
15274
|
if (i === 0) {
|
|
14211
15275
|
value = val;
|
|
14212
15276
|
} else if (val != value) {
|
|
14213
15277
|
return '';
|
|
14214
15278
|
}
|
|
14215
15279
|
}
|
|
14216
|
-
return
|
|
15280
|
+
return value;
|
|
15281
|
+
}
|
|
15282
|
+
|
|
15283
|
+
function strokeWidthIsUnsetForTargets() {
|
|
15284
|
+
return styleFieldIsUnsetForTargets('stroke-width');
|
|
15285
|
+
}
|
|
15286
|
+
|
|
15287
|
+
function styleFieldIsUnsetForTargets(field) {
|
|
15288
|
+
var records = targetLayer && targetLayer.data && targetLayer.data.getRecords();
|
|
15289
|
+
var ids = getTargetIds();
|
|
15290
|
+
var val;
|
|
15291
|
+
if (!records) return true;
|
|
15292
|
+
for (var i=0; i<ids.length; i++) {
|
|
15293
|
+
val = records[ids[i]] && records[ids[i]][field];
|
|
15294
|
+
if (val !== undefined && val !== null && val !== '') {
|
|
15295
|
+
return false;
|
|
15296
|
+
}
|
|
15297
|
+
}
|
|
15298
|
+
return ids.length > 0;
|
|
15299
|
+
}
|
|
15300
|
+
|
|
15301
|
+
function getDefaultStrokeWidth() {
|
|
15302
|
+
return targetLayer && targetLayer.geometry_type == 'polyline' ? 1 : 0;
|
|
15303
|
+
}
|
|
15304
|
+
|
|
15305
|
+
function getAllFeatureIds(lyr) {
|
|
15306
|
+
var ids = [];
|
|
15307
|
+
for (var i=0, n=internal.getFeatureCount(lyr); i<n; i++) {
|
|
15308
|
+
ids.push(i);
|
|
15309
|
+
}
|
|
15310
|
+
return ids;
|
|
14217
15311
|
}
|
|
14218
15312
|
|
|
14219
|
-
function
|
|
14220
|
-
|
|
14221
|
-
rec[fontField] = fontName;
|
|
14222
|
-
});
|
|
15313
|
+
function getSelectionIds() {
|
|
15314
|
+
return hit ? hit.getSelectionIds() : [];
|
|
14223
15315
|
}
|
|
14224
15316
|
|
|
14225
|
-
function
|
|
15317
|
+
function getTargetIds() {
|
|
14226
15318
|
var ids = getSelectionIds();
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
size = Math.max(1, size + delta);
|
|
14230
|
-
applyStyleFields([fontSizeField], function(rec) {
|
|
14231
|
-
rec[fontSizeField] = size;
|
|
14232
|
-
});
|
|
15319
|
+
if (!targetLayer) return [];
|
|
15320
|
+
return ids.length > 0 ? ids : getAllFeatureIds(targetLayer);
|
|
14233
15321
|
}
|
|
14234
15322
|
|
|
14235
|
-
function
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
applyStyleFields([fontStyleField, fontWeightField], function(rec) {
|
|
14239
|
-
rec[fontStyleField] = variant.style;
|
|
14240
|
-
rec[fontWeightField] = variant.weight;
|
|
14241
|
-
});
|
|
15323
|
+
function clearSelection() {
|
|
15324
|
+
if (hit) hit.clearSelection();
|
|
15325
|
+
updateControls();
|
|
14242
15326
|
}
|
|
14243
15327
|
|
|
14244
|
-
function
|
|
14245
|
-
|
|
14246
|
-
|
|
14247
|
-
});
|
|
15328
|
+
function updateEditingStatus(count) {
|
|
15329
|
+
editingStatus.text(count > 0 ? 'Editing: ' + count + ' selected' : 'Editing: all');
|
|
15330
|
+
clearLink.classed('hidden', count === 0);
|
|
14248
15331
|
}
|
|
14249
15332
|
|
|
14250
|
-
function
|
|
14251
|
-
|
|
14252
|
-
|
|
14253
|
-
});
|
|
15333
|
+
function getActiveLayer() {
|
|
15334
|
+
var active = gui.model.getActiveLayer();
|
|
15335
|
+
return active && active.layer;
|
|
14254
15336
|
}
|
|
14255
15337
|
|
|
14256
|
-
function
|
|
14257
|
-
|
|
15338
|
+
function closePanel() {
|
|
15339
|
+
turnOff();
|
|
15340
|
+
if (gui.interaction.getMode() == 'line_style' || gui.interaction.getMode() == 'polygon_style') {
|
|
15341
|
+
gui.interaction.turnOff();
|
|
15342
|
+
}
|
|
14258
15343
|
}
|
|
14259
15344
|
|
|
14260
|
-
function
|
|
14261
|
-
|
|
14262
|
-
var el = popup.container();
|
|
14263
|
-
el.addClass('option-menu');
|
|
14264
|
-
el.html(`<div><input type="text" class="style-name text-input" placeholder="style name"></div>
|
|
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
|
-
});
|
|
15345
|
+
function layerCanBeStyled(lyr) {
|
|
15346
|
+
return !!(lyr && (lyr.geometry_type == 'polyline' || lyr.geometry_type == 'polygon'));
|
|
14280
15347
|
}
|
|
14281
15348
|
|
|
14282
|
-
function
|
|
14283
|
-
var
|
|
14284
|
-
|
|
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
|
-
}
|
|
15349
|
+
function modeMatchesActiveLayer(mode) {
|
|
15350
|
+
var lyr = getActiveLayer();
|
|
15351
|
+
return mode == 'line_style' && lyr && lyr.geometry_type == 'polyline' ||
|
|
15352
|
+
mode == 'polygon_style' && lyr && lyr.geometry_type == 'polygon';
|
|
14303
15353
|
}
|
|
14304
15354
|
|
|
14305
|
-
|
|
14306
|
-
|
|
14307
|
-
|
|
14308
|
-
if (!name) return;
|
|
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();
|
|
15355
|
+
function modelSelectLayer(lyr, dataset) {
|
|
15356
|
+
if (lyr) lyr.hidden = false;
|
|
15357
|
+
gui.model.selectLayer(lyr, dataset);
|
|
14316
15358
|
}
|
|
14317
15359
|
|
|
14318
|
-
function
|
|
14319
|
-
var
|
|
14320
|
-
|
|
14321
|
-
|
|
14322
|
-
if (!item) return;
|
|
14323
|
-
applyStyleObject(item.style);
|
|
15360
|
+
function parseOpacityValue(str) {
|
|
15361
|
+
var pct = Number(String(str).replace('%', '').trim());
|
|
15362
|
+
if (!isFinite(pct)) return null;
|
|
15363
|
+
return Math.max(0, Math.min(100, pct)) / 100;
|
|
14324
15364
|
}
|
|
14325
15365
|
|
|
14326
|
-
function
|
|
14327
|
-
var
|
|
14328
|
-
return
|
|
15366
|
+
function parsePositiveNumber(str) {
|
|
15367
|
+
var val = Number(String(str).trim());
|
|
15368
|
+
return isFinite(val) && val >= 0 ? val : null;
|
|
14329
15369
|
}
|
|
14330
15370
|
|
|
14331
|
-
function
|
|
14332
|
-
|
|
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();
|
|
15371
|
+
function formatOpacityPct(val) {
|
|
15372
|
+
val = val === '' || val === undefined || val === null ? 1 : Number(val);
|
|
15373
|
+
return isFinite(val) ? Math.round(Math.max(0, Math.min(1, val)) * 100) + '%' : '';
|
|
14341
15374
|
}
|
|
14342
15375
|
|
|
14343
|
-
function
|
|
14344
|
-
|
|
14345
|
-
|
|
14346
|
-
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
|
|
14350
|
-
|
|
15376
|
+
function formatNumberValue(val) {
|
|
15377
|
+
val = Number(val);
|
|
15378
|
+
return isFinite(val) ? String(val) : '';
|
|
15379
|
+
}
|
|
15380
|
+
|
|
15381
|
+
function quoteCommandValue(str) {
|
|
15382
|
+
return "'" + String(str).replace(/'/g, "\\'") + "'";
|
|
15383
|
+
}
|
|
15384
|
+
}
|
|
15385
|
+
|
|
15386
|
+
var defaultCircleRadius = 0;
|
|
15387
|
+
var defaultCreatedCircleRadius = 3;
|
|
15388
|
+
var defaultCircleFill = '#000000';
|
|
15389
|
+
|
|
15390
|
+
function PointStyleTool(gui) {
|
|
15391
|
+
var parent = gui.container.findChild('.mshp-main-map');
|
|
15392
|
+
var panel = El('div').addClass('label-style-panel point-style-panel rollover').appendTo(parent).hide();
|
|
15393
|
+
var title, noteSection, labelsSection, circlesSection, symbolsSection, labelNoteSection;
|
|
15394
|
+
var circleSectionLabel;
|
|
15395
|
+
var symbolNote;
|
|
15396
|
+
var createFieldSelect, createExprInput, createCopyCheckbox, createLabelsBtn;
|
|
15397
|
+
var editingRow, editingStatus, clearLink;
|
|
15398
|
+
var createCirclesRow;
|
|
15399
|
+
var circleControlRows = [];
|
|
15400
|
+
var circleRadiusClickText, circleFillControl, circleStrokeControl;
|
|
15401
|
+
var circleFillOpacityInput, circleStrokeOpacityInput, circleStrokeWidthClickText;
|
|
15402
|
+
var targetLayer = null;
|
|
15403
|
+
var hit = null;
|
|
15404
|
+
|
|
15405
|
+
initPanel();
|
|
15406
|
+
|
|
15407
|
+
this.open = function(lyr, dataset) {
|
|
15408
|
+
if (!layerCanBeStyled(lyr)) return;
|
|
15409
|
+
if (!gui.map.isActiveLayer(lyr)) {
|
|
15410
|
+
modelSelectLayer(lyr, dataset);
|
|
14351
15411
|
}
|
|
14352
|
-
|
|
14353
|
-
|
|
14354
|
-
|
|
14355
|
-
|
|
14356
|
-
|
|
14357
|
-
|
|
14358
|
-
|
|
15412
|
+
gui.interaction.setMode('point_style');
|
|
15413
|
+
};
|
|
15414
|
+
|
|
15415
|
+
gui.on('interaction_mode_change', function(e) {
|
|
15416
|
+
if (modeMatchesActiveLayer(e.mode)) {
|
|
15417
|
+
turnOn();
|
|
15418
|
+
} else {
|
|
15419
|
+
turnOff();
|
|
14359
15420
|
}
|
|
14360
|
-
|
|
14361
|
-
}
|
|
15421
|
+
});
|
|
14362
15422
|
|
|
14363
|
-
|
|
14364
|
-
if (
|
|
14365
|
-
|
|
15423
|
+
gui.model.on('update', function() {
|
|
15424
|
+
if (panel.visible() && !modeMatchesActiveLayer(gui.interaction.getMode())) {
|
|
15425
|
+
gui.interaction.turnOff();
|
|
15426
|
+
} else if (panel.visible()) {
|
|
15427
|
+
updateControls();
|
|
14366
15428
|
}
|
|
15429
|
+
});
|
|
15430
|
+
|
|
15431
|
+
hit = gui.map.getHitControl && gui.map.getHitControl();
|
|
15432
|
+
if (hit) {
|
|
15433
|
+
hit.on('change', function(e) {
|
|
15434
|
+
if (e.mode == 'point_style') {
|
|
15435
|
+
updateControls();
|
|
15436
|
+
}
|
|
15437
|
+
});
|
|
14367
15438
|
}
|
|
14368
15439
|
|
|
14369
|
-
function
|
|
14370
|
-
var
|
|
14371
|
-
|
|
15440
|
+
function initPanel() {
|
|
15441
|
+
var header = El('div').addClass('label-style-panel-title').appendTo(panel);
|
|
15442
|
+
title = El('span').appendTo(header).text('Point symbols');
|
|
15443
|
+
El('button').addClass('label-style-close').appendTo(header).text('×').on('click', closePanel);
|
|
15444
|
+
|
|
15445
|
+
initNoteSections();
|
|
15446
|
+
initCreateLabelsSection();
|
|
15447
|
+
initCreateCirclesSection();
|
|
15448
|
+
initSymbolsSection();
|
|
14372
15449
|
}
|
|
14373
15450
|
|
|
14374
|
-
function
|
|
14375
|
-
|
|
14376
|
-
|
|
14377
|
-
|
|
14378
|
-
|
|
14379
|
-
|
|
15451
|
+
function initNoteSections() {
|
|
15452
|
+
noteSection = El('div').addClass('point-style-section point-style-note-section').appendTo(panel);
|
|
15453
|
+
El('div').addClass('point-style-note').appendTo(noteSection).text('This layer contains unstyled points.');
|
|
15454
|
+
|
|
15455
|
+
labelNoteSection = El('div').addClass('point-style-section point-label-note-section').appendTo(panel);
|
|
15456
|
+
El('div').addClass('point-style-note').appendTo(labelNoteSection)
|
|
15457
|
+
.text('This layer is rendered as labels. Use the label style tool to edit label styles.');
|
|
14380
15458
|
}
|
|
14381
15459
|
|
|
14382
|
-
function
|
|
14383
|
-
|
|
14384
|
-
|
|
14385
|
-
|
|
15460
|
+
function initCreateLabelsSection() {
|
|
15461
|
+
labelsSection = El('div').addClass('point-style-section').appendTo(panel);
|
|
15462
|
+
El('div').addClass('label-style-row-label').appendTo(labelsSection).text('Labels');
|
|
15463
|
+
|
|
15464
|
+
var fieldRow = El('label').addClass('label-style-row').appendTo(labelsSection);
|
|
15465
|
+
El('span').appendTo(fieldRow).text('Label field');
|
|
15466
|
+
createFieldSelect = El('select').appendTo(fieldRow).on('change', function() {
|
|
15467
|
+
var field = createFieldSelect.node().value;
|
|
15468
|
+
if (field) {
|
|
15469
|
+
createExprInput.node().value = getFieldExpression(field);
|
|
15470
|
+
}
|
|
15471
|
+
updateCreateLabelsButton();
|
|
14386
15472
|
});
|
|
14387
|
-
return out;
|
|
14388
|
-
}
|
|
14389
15473
|
|
|
14390
|
-
|
|
14391
|
-
|
|
14392
|
-
|
|
14393
|
-
|
|
14394
|
-
|
|
14395
|
-
|
|
14396
|
-
|
|
14397
|
-
|
|
15474
|
+
var exprRow = El('label').addClass('label-style-row label-create-expression-row').appendTo(labelsSection);
|
|
15475
|
+
El('span').appendTo(exprRow).text('or expression');
|
|
15476
|
+
createExprInput = El('input')
|
|
15477
|
+
.attr('type', 'text')
|
|
15478
|
+
.appendTo(exprRow)
|
|
15479
|
+
.on('input', updateCreateLabelsButton)
|
|
15480
|
+
.on('change', updateCreateLabelsButton);
|
|
15481
|
+
|
|
15482
|
+
var btnRow = El('div').addClass('label-style-row point-create-labels-row').appendTo(labelsSection);
|
|
15483
|
+
createLabelsBtn = El('button').appendTo(btnRow).text('Create').on('click', createLabels);
|
|
15484
|
+
var copyLabel = El('label').addClass('point-create-copy-label').appendTo(btnRow);
|
|
15485
|
+
createCopyCheckbox = El('input').attr('type', 'checkbox').appendTo(copyLabel);
|
|
15486
|
+
El('span').appendTo(copyLabel).text('as new layer');
|
|
15487
|
+
}
|
|
15488
|
+
|
|
15489
|
+
function initCreateCirclesSection() {
|
|
15490
|
+
circlesSection = El('div').addClass('point-style-section point-circle-section').appendTo(panel);
|
|
15491
|
+
circleSectionLabel = El('div').addClass('label-style-row-label').appendTo(circlesSection).text('Circles');
|
|
15492
|
+
El('div').addClass('point-style-note point-circle-note').appendTo(circlesSection)
|
|
15493
|
+
.text('Use the -style command in the console to create proportional circles.');
|
|
15494
|
+
|
|
15495
|
+
createCirclesRow = El('div').addClass('label-style-row point-create-circles-row').appendTo(circlesSection);
|
|
15496
|
+
El('button').appendTo(createCirclesRow).text('Create').on('click', createSimpleCircles);
|
|
15497
|
+
El('span').appendTo(createCirclesRow).text('simple circles');
|
|
15498
|
+
|
|
15499
|
+
editingRow = El('div').addClass('label-style-row label-style-selection-row point-style-selection-row').appendTo(circlesSection);
|
|
15500
|
+
editingStatus = El('span').addClass('label-editing-status').appendTo(editingRow);
|
|
15501
|
+
clearLink = El('span').addClass('label-editing-clear colored-text').appendTo(editingRow).text('deselect').on('click', clearSelection);
|
|
15502
|
+
|
|
15503
|
+
var fillRow = El('div').addClass('label-style-row point-symbol-row').appendTo(circlesSection);
|
|
15504
|
+
circleFillControl = addCircleColorControl(fillRow, 'Fill');
|
|
15505
|
+
circleFillOpacityInput = addCircleNumberControl(fillRow, 'Opacity', '100%');
|
|
15506
|
+
circleControlRows.push(fillRow);
|
|
15507
|
+
|
|
15508
|
+
var strokeRow = El('div').addClass('label-style-row point-symbol-row').appendTo(circlesSection);
|
|
15509
|
+
circleStrokeControl = addCircleColorControl(strokeRow, 'Stroke');
|
|
15510
|
+
circleStrokeOpacityInput = addCircleNumberControl(strokeRow, 'Opacity', '100%');
|
|
15511
|
+
circleControlRows.push(strokeRow);
|
|
15512
|
+
|
|
15513
|
+
var sizeRow = El('div').addClass('label-style-row point-symbol-size-row').appendTo(circlesSection);
|
|
15514
|
+
addCircleStepperControl(sizeRow, 'Stroke width', function() {
|
|
15515
|
+
return getCircleStrokeWidth();
|
|
15516
|
+
}, function(direction) {
|
|
15517
|
+
setCircleStrokeWidth(getNextStrokeWidth(getCircleStrokeWidth(), direction));
|
|
15518
|
+
applyCircleStyles();
|
|
15519
|
+
}, function(value) {
|
|
15520
|
+
setCircleStrokeWidth(value);
|
|
15521
|
+
applyCircleStyles();
|
|
15522
|
+
}, function(clickText) {
|
|
15523
|
+
circleStrokeWidthClickText = clickText;
|
|
15524
|
+
});
|
|
15525
|
+
|
|
15526
|
+
addCircleStepperControl(sizeRow, 'Radius', function() {
|
|
15527
|
+
return getCircleRadiusForNudge();
|
|
15528
|
+
}, function(direction) {
|
|
15529
|
+
setCircleRadius(getNextCircleRadius(getCircleRadiusForNudge(), direction));
|
|
15530
|
+
applyCircleStyles();
|
|
15531
|
+
}, function(value) {
|
|
15532
|
+
setCircleRadius(value);
|
|
15533
|
+
applyCircleStyles();
|
|
15534
|
+
}, function(clickText, text) {
|
|
15535
|
+
circleRadiusClickText = clickText;
|
|
15536
|
+
text.addClass('label-icon-size-value');
|
|
15537
|
+
});
|
|
15538
|
+
circleControlRows.push(sizeRow);
|
|
15539
|
+
}
|
|
15540
|
+
|
|
15541
|
+
function initSymbolsSection() {
|
|
15542
|
+
symbolsSection = El('div').addClass('point-style-section point-symbol-info-section').appendTo(panel);
|
|
15543
|
+
El('div').addClass('label-style-row-label').appendTo(symbolsSection).text('Symbols');
|
|
15544
|
+
symbolNote = El('div').addClass('point-style-note').appendTo(symbolsSection)
|
|
15545
|
+
.text('Use the -symbols command in the console to create arrows and other symbols.');
|
|
15546
|
+
}
|
|
15547
|
+
|
|
15548
|
+
function addCircleColorControl(row, label) {
|
|
15549
|
+
var colorCell = El('div').addClass('point-symbol-color-cell label-color-row').appendTo(row);
|
|
15550
|
+
var control = {};
|
|
15551
|
+
El('span').appendTo(colorCell).text(label);
|
|
15552
|
+
control.chit = makePanelButton(colorCell, '', function() {
|
|
15553
|
+
control.picker.toggle();
|
|
15554
|
+
}).addClass('label-color-chit');
|
|
15555
|
+
control.input = El('input').attr('type', 'text').appendTo(colorCell).on('change', function() {
|
|
15556
|
+
var color = control.input.node().value.trim();
|
|
15557
|
+
if (isHexColor(color)) {
|
|
15558
|
+
control.picker.setColor(color);
|
|
14398
15559
|
}
|
|
14399
|
-
|
|
14400
|
-
}
|
|
14401
|
-
|
|
14402
|
-
|
|
14403
|
-
|
|
14404
|
-
|
|
14405
|
-
|
|
14406
|
-
|
|
14407
|
-
|
|
14408
|
-
|
|
15560
|
+
applyCircleStyles();
|
|
15561
|
+
});
|
|
15562
|
+
control.picker = new ColorPicker(colorCell, {
|
|
15563
|
+
presetRows: layerColorPresetRows,
|
|
15564
|
+
onPreview: function(hex) {
|
|
15565
|
+
setCircleColor(control, hex);
|
|
15566
|
+
},
|
|
15567
|
+
onChange: function(hex) {
|
|
15568
|
+
setCircleColor(control, hex);
|
|
15569
|
+
applyCircleStyles();
|
|
15570
|
+
}
|
|
15571
|
+
});
|
|
15572
|
+
setCircleColor(control, '');
|
|
15573
|
+
return control;
|
|
15574
|
+
}
|
|
15575
|
+
|
|
15576
|
+
function addCircleStepperControl(row, label, getValue, nudgeValue, setValue, capture) {
|
|
15577
|
+
var control;
|
|
15578
|
+
var buttonRow;
|
|
15579
|
+
var text;
|
|
15580
|
+
var clickText;
|
|
15581
|
+
control = El('div').addClass('point-symbol-stepper-control').appendTo(row);
|
|
15582
|
+
El('span').appendTo(control).text(label);
|
|
15583
|
+
buttonRow = El('div').addClass('layer-stepper-control').appendTo(control);
|
|
15584
|
+
makePanelButton(buttonRow, '−', function() {
|
|
15585
|
+
nudgeValue(-1);
|
|
15586
|
+
});
|
|
15587
|
+
text = El('span').addClass('layer-stroke-width-value').appendTo(buttonRow);
|
|
15588
|
+
clickText = new ClickText2(text);
|
|
15589
|
+
clickText.on('change', function() {
|
|
15590
|
+
var value = parsePositiveNumber(clickText.value());
|
|
15591
|
+
if (value === null) {
|
|
15592
|
+
clickText.value(formatNumberValue(getValue()));
|
|
15593
|
+
return;
|
|
14409
15594
|
}
|
|
15595
|
+
setValue(value);
|
|
14410
15596
|
});
|
|
15597
|
+
makePanelButton(buttonRow, '+', function() {
|
|
15598
|
+
nudgeValue(1);
|
|
15599
|
+
});
|
|
15600
|
+
capture(clickText, text);
|
|
14411
15601
|
}
|
|
14412
15602
|
|
|
14413
|
-
function
|
|
14414
|
-
var
|
|
14415
|
-
|
|
14416
|
-
|
|
14417
|
-
|
|
14418
|
-
|
|
14419
|
-
|
|
15603
|
+
function addCircleNumberControl(row, label, value) {
|
|
15604
|
+
var control = El('label').addClass('layer-number-control').appendTo(row);
|
|
15605
|
+
var input;
|
|
15606
|
+
El('span').appendTo(control).text(label);
|
|
15607
|
+
input = El('input').attr('type', 'text').appendTo(control).on('change', applyCircleStyles);
|
|
15608
|
+
input.node().value = value;
|
|
15609
|
+
return input;
|
|
14420
15610
|
}
|
|
14421
15611
|
|
|
14422
|
-
function
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
15612
|
+
function makePanelButton(parent, label, action) {
|
|
15613
|
+
return El('div')
|
|
15614
|
+
.addClass('label-panel-btn')
|
|
15615
|
+
.attr('role', 'button')
|
|
15616
|
+
.attr('tabindex', '0')
|
|
15617
|
+
.appendTo(parent)
|
|
15618
|
+
.text(label)
|
|
15619
|
+
.on('click', function(e) {
|
|
15620
|
+
action(e);
|
|
15621
|
+
})
|
|
15622
|
+
.on('keydown', function(e) {
|
|
15623
|
+
if (e.key == 'Enter' || e.key == ' ') {
|
|
15624
|
+
e.preventDefault();
|
|
15625
|
+
action(e);
|
|
15626
|
+
}
|
|
15627
|
+
});
|
|
14426
15628
|
}
|
|
14427
15629
|
|
|
14428
|
-
function
|
|
14429
|
-
|
|
14430
|
-
|
|
14431
|
-
|
|
14432
|
-
|
|
14433
|
-
|
|
14434
|
-
|
|
14435
|
-
|
|
14436
|
-
|
|
14437
|
-
|
|
14438
|
-
}
|
|
14439
|
-
});
|
|
15630
|
+
function turnOn() {
|
|
15631
|
+
targetLayer = getActiveLayer();
|
|
15632
|
+
if (getPointRepresentation() == 'label' && gui.labelTool && gui.labelTool.open) {
|
|
15633
|
+
gui.labelTool.open(targetLayer);
|
|
15634
|
+
targetLayer = null;
|
|
15635
|
+
return;
|
|
15636
|
+
}
|
|
15637
|
+
renderCreateFields();
|
|
15638
|
+
updateControls();
|
|
15639
|
+
panel.show();
|
|
14440
15640
|
}
|
|
14441
15641
|
|
|
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
|
-
});
|
|
15642
|
+
function turnOff() {
|
|
15643
|
+
panel.hide();
|
|
15644
|
+
circleFillControl.picker.hide();
|
|
15645
|
+
circleStrokeControl.picker.hide();
|
|
15646
|
+
targetLayer = null;
|
|
14453
15647
|
}
|
|
14454
15648
|
|
|
14455
|
-
function
|
|
14456
|
-
|
|
14457
|
-
|
|
14458
|
-
|
|
15649
|
+
function closePanel() {
|
|
15650
|
+
turnOff();
|
|
15651
|
+
if (gui.interaction.getMode() == 'point_style') {
|
|
15652
|
+
gui.interaction.turnOff();
|
|
15653
|
+
}
|
|
14459
15654
|
}
|
|
14460
15655
|
|
|
14461
|
-
function
|
|
14462
|
-
|
|
15656
|
+
function updateControls() {
|
|
15657
|
+
var representation = getPointRepresentation();
|
|
15658
|
+
updateCreateLabelsButton();
|
|
15659
|
+
title.text(representation == 'circle' ? 'Circle styles' : 'Point symbols');
|
|
15660
|
+
updateEditingStatus(getSelectionIds().length);
|
|
15661
|
+
toggleSection(noteSection, representation == 'unstyled');
|
|
15662
|
+
toggleSection(labelsSection, representation == 'unstyled');
|
|
15663
|
+
toggleSection(circlesSection, representation == 'unstyled' || representation == 'circle');
|
|
15664
|
+
toggleSection(symbolsSection, representation == 'unstyled' || representation == 'svg-symbol');
|
|
15665
|
+
toggleSection(labelNoteSection, representation == 'label');
|
|
15666
|
+
updateSectionBorders([noteSection, labelNoteSection, labelsSection, circlesSection, symbolsSection]);
|
|
15667
|
+
symbolNote.text(representation == 'svg-symbol' ?
|
|
15668
|
+
'This layer uses SVG symbols. Use the -symbols command in the console to create arrows and other symbols.' :
|
|
15669
|
+
'Use the -symbols command in the console to create arrows and other symbols.');
|
|
15670
|
+
updateCircleSection(representation);
|
|
15671
|
+
updateCircleControls(representation);
|
|
15672
|
+
}
|
|
15673
|
+
|
|
15674
|
+
function toggleSection(section, visible) {
|
|
15675
|
+
if (visible) {
|
|
15676
|
+
section.show();
|
|
15677
|
+
} else {
|
|
15678
|
+
section.hide();
|
|
15679
|
+
}
|
|
14463
15680
|
}
|
|
14464
15681
|
|
|
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);
|
|
15682
|
+
function updateSectionBorders(sections) {
|
|
15683
|
+
var foundFirst = false;
|
|
15684
|
+
sections.forEach(function(section) {
|
|
15685
|
+
var visible = section.visible();
|
|
15686
|
+
section.classed('point-style-first-visible', visible && !foundFirst);
|
|
15687
|
+
if (visible) foundFirst = true;
|
|
14481
15688
|
});
|
|
14482
|
-
|
|
14483
|
-
|
|
15689
|
+
}
|
|
15690
|
+
|
|
15691
|
+
function updateCircleSection(representation) {
|
|
15692
|
+
var showCreate = representation == 'unstyled';
|
|
15693
|
+
circleSectionLabel.classed('hidden', !showCreate);
|
|
15694
|
+
createCirclesRow.classed('hidden', !showCreate);
|
|
15695
|
+
editingRow.classed('hidden', representation != 'circle');
|
|
15696
|
+
circlesSection.findChild('.point-circle-note').classed('hidden', !showCreate);
|
|
15697
|
+
circleControlRows.forEach(function(row) {
|
|
15698
|
+
row.classed('hidden', showCreate);
|
|
15699
|
+
});
|
|
15700
|
+
}
|
|
15701
|
+
|
|
15702
|
+
function updateCircleControls(representation) {
|
|
15703
|
+
var radius = getCommonValue('r');
|
|
15704
|
+
var fill = getCommonValue('fill');
|
|
15705
|
+
var stroke = getCommonValue('stroke');
|
|
15706
|
+
var fillOpacity = getCommonValue('fill-opacity');
|
|
15707
|
+
var strokeOpacity = getCommonValue('stroke-opacity');
|
|
15708
|
+
var strokeWidth = getCommonValue('stroke-width');
|
|
15709
|
+
setCircleRadius(radius);
|
|
15710
|
+
setCircleColor(circleFillControl, fill);
|
|
15711
|
+
setCircleColor(circleStrokeControl, stroke);
|
|
15712
|
+
circleFillOpacityInput.node().value = formatOpacityPct(fillOpacity === '' ? 1 : fillOpacity);
|
|
15713
|
+
circleStrokeOpacityInput.node().value = formatOpacityPct(strokeOpacity === '' ? 1 : strokeOpacity);
|
|
15714
|
+
setCircleStrokeWidth(strokeWidth === '' ? 0 : strokeWidth);
|
|
15715
|
+
if (representation != 'circle' && representation != 'unstyled') {
|
|
15716
|
+
setCircleRadius(defaultCircleRadius);
|
|
15717
|
+
setCircleColor(circleFillControl, '');
|
|
15718
|
+
setCircleColor(circleStrokeControl, '');
|
|
15719
|
+
circleFillOpacityInput.node().value = '100%';
|
|
15720
|
+
circleStrokeOpacityInput.node().value = '100%';
|
|
15721
|
+
setCircleStrokeWidth(0);
|
|
15722
|
+
}
|
|
15723
|
+
}
|
|
15724
|
+
|
|
15725
|
+
function renderCreateFields() {
|
|
15726
|
+
var lyr = getActiveLayer();
|
|
15727
|
+
var records = lyr && lyr.data ? lyr.data.getRecords() : [];
|
|
15728
|
+
var fields = lyr && lyr.data ? lyr.data.getFields().filter(function(field) {
|
|
15729
|
+
return internal.getColumnType(field, records) == 'string';
|
|
15730
|
+
}) : [];
|
|
15731
|
+
var value = createFieldSelect.node().value;
|
|
15732
|
+
createFieldSelect.empty();
|
|
15733
|
+
El('option').attr('value', '').appendTo(createFieldSelect).text('');
|
|
15734
|
+
fields.forEach(function(field) {
|
|
15735
|
+
El('option').attr('value', field).appendTo(createFieldSelect).text(field);
|
|
14484
15736
|
});
|
|
14485
|
-
|
|
15737
|
+
createFieldSelect.node().disabled = fields.length === 0;
|
|
15738
|
+
createFieldSelect.node().value = fields.indexOf(value) > -1 ? value : '';
|
|
14486
15739
|
}
|
|
14487
15740
|
|
|
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
|
-
});
|
|
15741
|
+
function updateCreateLabelsButton() {
|
|
15742
|
+
createLabelsBtn.node().disabled = createExprInput.node().value.trim() === '';
|
|
14506
15743
|
}
|
|
14507
15744
|
|
|
14508
|
-
function
|
|
14509
|
-
|
|
14510
|
-
|
|
14511
|
-
|
|
14512
|
-
|
|
14513
|
-
|
|
14514
|
-
|
|
15745
|
+
function createLabels() {
|
|
15746
|
+
var expr = createExprInput.node().value.trim();
|
|
15747
|
+
var cmd;
|
|
15748
|
+
if (!expr || !gui.console) return;
|
|
15749
|
+
cmd = createCopyCheckbox.node().checked ?
|
|
15750
|
+
'-filter true + name=labels -style label-text=' + quoteCommandValue(expr) :
|
|
15751
|
+
'-style label-text=' + quoteCommandValue(expr);
|
|
15752
|
+
runGuiEditCommand(gui, cmd, {
|
|
15753
|
+
title: 'Create labels',
|
|
15754
|
+
onSuccess: openLabelStyles
|
|
15755
|
+
});
|
|
14515
15756
|
}
|
|
14516
15757
|
|
|
14517
|
-
function
|
|
14518
|
-
|
|
15758
|
+
function openLabelStyles() {
|
|
15759
|
+
var active = gui.model.getActiveLayer();
|
|
15760
|
+
if (active && active.layer && internal.layerHasLabels(active.layer) &&
|
|
15761
|
+
gui.labelTool && gui.labelTool.open) {
|
|
15762
|
+
gui.labelTool.open(active.layer, active.dataset);
|
|
15763
|
+
} else {
|
|
15764
|
+
updateControls();
|
|
15765
|
+
}
|
|
15766
|
+
}
|
|
15767
|
+
|
|
15768
|
+
function createSimpleCircles() {
|
|
15769
|
+
runCommand('-style r=' + defaultCreatedCircleRadius +
|
|
15770
|
+
' fill=' + quoteCommandValue(defaultCircleFill) +
|
|
15771
|
+
' fill-opacity=1 stroke-opacity=1 stroke-width=0', 'Create circles');
|
|
15772
|
+
}
|
|
15773
|
+
|
|
15774
|
+
function applyCircleStyles() {
|
|
15775
|
+
var representation = getPointRepresentation();
|
|
15776
|
+
var radius = getCircleRadius();
|
|
15777
|
+
var fill = circleFillControl.input.node().value.trim();
|
|
15778
|
+
var fillOpacity = parseOpacityValue(circleFillOpacityInput.node().value);
|
|
15779
|
+
var stroke = circleStrokeControl.input.node().value.trim();
|
|
15780
|
+
var strokeOpacity = parseOpacityValue(circleStrokeOpacityInput.node().value);
|
|
15781
|
+
var strokeWidth = getCircleStrokeWidth();
|
|
15782
|
+
var args;
|
|
15783
|
+
if (!gui.console || !(representation == 'unstyled' || representation == 'circle') ||
|
|
15784
|
+
(radius !== null && !(radius >= 0)) || fillOpacity === null || strokeOpacity === null || strokeWidth === null) return;
|
|
15785
|
+
if (radius !== null && radius > 0 && !fill && !stroke && styleFieldIsUnset('fill') && styleFieldIsUnset('stroke')) {
|
|
15786
|
+
fill = defaultCircleFill;
|
|
15787
|
+
setCircleColor(circleFillControl, fill);
|
|
15788
|
+
}
|
|
15789
|
+
args = [
|
|
15790
|
+
'fill-opacity=' + fillOpacity,
|
|
15791
|
+
'stroke-opacity=' + strokeOpacity,
|
|
15792
|
+
'stroke-width=' + strokeWidth
|
|
15793
|
+
];
|
|
15794
|
+
if (radius !== null) args.unshift('r=' + radius);
|
|
15795
|
+
if (fill) args.push('fill=' + quoteCommandValue(fill));
|
|
15796
|
+
if (stroke) args.push('stroke=' + quoteCommandValue(stroke));
|
|
15797
|
+
runStyleCommand(args, 'Create circles');
|
|
14519
15798
|
}
|
|
14520
15799
|
|
|
14521
|
-
function
|
|
14522
|
-
var
|
|
14523
|
-
|
|
14524
|
-
|
|
14525
|
-
|
|
14526
|
-
|
|
14527
|
-
|
|
14528
|
-
evt.preventDefault();
|
|
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();
|
|
15800
|
+
function runStyleCommand(args, title) {
|
|
15801
|
+
var ids = getTargetIds();
|
|
15802
|
+
var parts = ['-style'].concat(args);
|
|
15803
|
+
if (!targetLayer || ids.length === 0) return;
|
|
15804
|
+
addTargetOption(parts);
|
|
15805
|
+
if (ids.length < internal.getFeatureCount(targetLayer)) {
|
|
15806
|
+
parts.push('ids=' + ids.join(','));
|
|
14538
15807
|
}
|
|
15808
|
+
runCommand(parts.join(' '), title);
|
|
14539
15809
|
}
|
|
14540
15810
|
|
|
14541
|
-
function
|
|
14542
|
-
|
|
14543
|
-
|
|
14544
|
-
|
|
14545
|
-
s: p.x,
|
|
14546
|
-
b: 255 - p.y
|
|
15811
|
+
function runCommand(cmd, title) {
|
|
15812
|
+
runGuiEditCommand(gui, cmd, {
|
|
15813
|
+
title: title,
|
|
15814
|
+
onSuccess: updateControls
|
|
14547
15815
|
});
|
|
14548
15816
|
}
|
|
14549
15817
|
|
|
14550
|
-
function
|
|
14551
|
-
var
|
|
14552
|
-
|
|
14553
|
-
|
|
14554
|
-
|
|
14555
|
-
b: pickerColor.b
|
|
14556
|
-
});
|
|
15818
|
+
function getCircleRadius() {
|
|
15819
|
+
var str = String(circleRadiusClickText.value()).trim();
|
|
15820
|
+
var radius = Number(str);
|
|
15821
|
+
if (str === '') return null;
|
|
15822
|
+
return isFinite(radius) && radius >= 0 ? radius : defaultCircleRadius;
|
|
14557
15823
|
}
|
|
14558
15824
|
|
|
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
|
-
};
|
|
15825
|
+
function getCircleRadiusForNudge() {
|
|
15826
|
+
var radius = getCircleRadius();
|
|
15827
|
+
return radius === null ? getMostCommonNumberValue('r', defaultCircleRadius) : radius;
|
|
14565
15828
|
}
|
|
14566
15829
|
|
|
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();
|
|
15830
|
+
function setCircleRadius(value) {
|
|
15831
|
+
circleRadiusClickText.value(value === '' ? '' : formatNumberValue(value));
|
|
14575
15832
|
}
|
|
14576
15833
|
|
|
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);
|
|
15834
|
+
function getCircleStrokeWidth() {
|
|
15835
|
+
var width = Number(circleStrokeWidthClickText.value());
|
|
15836
|
+
return isFinite(width) && width >= 0 ? width : 0;
|
|
14584
15837
|
}
|
|
14585
15838
|
|
|
14586
|
-
function
|
|
14587
|
-
|
|
14588
|
-
drawSaturationBrightnessCanvas();
|
|
14589
|
-
drawHueCanvas();
|
|
15839
|
+
function setCircleStrokeWidth(value) {
|
|
15840
|
+
circleStrokeWidthClickText.value(formatNumberValue(value));
|
|
14590
15841
|
}
|
|
14591
15842
|
|
|
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;
|
|
15843
|
+
function getNextStrokeWidth(value, direction) {
|
|
15844
|
+
var baseSteps = [0, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4];
|
|
15845
|
+
var i;
|
|
15846
|
+
if (direction > 0) {
|
|
15847
|
+
for (i=0; i<baseSteps.length; i++) {
|
|
15848
|
+
if (value < baseSteps[i]) return baseSteps[i];
|
|
14608
15849
|
}
|
|
15850
|
+
return Math.floor(value) + 1;
|
|
14609
15851
|
}
|
|
14610
|
-
|
|
14611
|
-
|
|
15852
|
+
for (i=baseSteps.length - 1; i>=0; i--) {
|
|
15853
|
+
if (value > baseSteps[i]) return baseSteps[i];
|
|
15854
|
+
}
|
|
15855
|
+
return baseSteps[0];
|
|
14612
15856
|
}
|
|
14613
15857
|
|
|
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;
|
|
15858
|
+
function getNextCircleRadius(value, direction) {
|
|
15859
|
+
var baseSteps = [0, 0.5, 1, 1.5, 2, 2.5, 3, 4, 5];
|
|
15860
|
+
var i;
|
|
15861
|
+
if (direction > 0) {
|
|
15862
|
+
for (i=0; i<baseSteps.length; i++) {
|
|
15863
|
+
if (value < baseSteps[i]) return baseSteps[i];
|
|
14626
15864
|
}
|
|
15865
|
+
return Math.floor(value) + 1;
|
|
14627
15866
|
}
|
|
14628
|
-
|
|
14629
|
-
|
|
15867
|
+
for (i=baseSteps.length - 1; i>=0; i--) {
|
|
15868
|
+
if (value > baseSteps[i]) return baseSteps[i];
|
|
15869
|
+
}
|
|
15870
|
+
return baseSteps[0];
|
|
14630
15871
|
}
|
|
14631
15872
|
|
|
14632
|
-
function
|
|
14633
|
-
|
|
15873
|
+
function getPointRepresentation() {
|
|
15874
|
+
var lyr = targetLayer || getActiveLayer();
|
|
15875
|
+
var table = lyr && lyr.data;
|
|
15876
|
+
if (table && table.fieldExists('svg-symbol')) return 'svg-symbol';
|
|
15877
|
+
if (table && table.fieldExists('label-text')) return 'label';
|
|
15878
|
+
if (table && table.fieldExists('r')) return 'circle';
|
|
15879
|
+
return 'unstyled';
|
|
14634
15880
|
}
|
|
14635
15881
|
|
|
14636
|
-
function
|
|
14637
|
-
|
|
15882
|
+
function getCommonValue(field) {
|
|
15883
|
+
var table = targetLayer && targetLayer.data;
|
|
15884
|
+
var records = table && table.getRecords();
|
|
15885
|
+
var ids = getTargetIds();
|
|
15886
|
+
var value, val;
|
|
15887
|
+
if (!records || ids.length === 0) return '';
|
|
15888
|
+
for (var i=0; i<ids.length; i++) {
|
|
15889
|
+
val = records[ids[i]] && records[ids[i]][field];
|
|
15890
|
+
if (i === 0) {
|
|
15891
|
+
value = val;
|
|
15892
|
+
} else if (val != value) {
|
|
15893
|
+
return '';
|
|
15894
|
+
}
|
|
15895
|
+
}
|
|
15896
|
+
return value === undefined || value === null ? '' : value;
|
|
14638
15897
|
}
|
|
14639
15898
|
|
|
14640
|
-
function
|
|
14641
|
-
var
|
|
14642
|
-
|
|
15899
|
+
function getMostCommonNumberValue(field, defaultValue) {
|
|
15900
|
+
var table = targetLayer && targetLayer.data;
|
|
15901
|
+
var records = table && table.getRecords();
|
|
15902
|
+
var ids = getTargetIds();
|
|
15903
|
+
var counts = {};
|
|
15904
|
+
var bestValue = null;
|
|
15905
|
+
var bestCount = 0;
|
|
15906
|
+
var val, key;
|
|
15907
|
+
if (!records || ids.length === 0) return defaultValue;
|
|
15908
|
+
for (var i=0; i<ids.length; i++) {
|
|
15909
|
+
val = Number(records[ids[i]] && records[ids[i]][field]);
|
|
15910
|
+
if (!isFinite(val)) continue;
|
|
15911
|
+
key = String(val);
|
|
15912
|
+
counts[key] = (counts[key] || 0) + 1;
|
|
15913
|
+
if (counts[key] > bestCount) {
|
|
15914
|
+
bestCount = counts[key];
|
|
15915
|
+
bestValue = val;
|
|
15916
|
+
}
|
|
15917
|
+
}
|
|
15918
|
+
return bestValue === null ? defaultValue : bestValue;
|
|
14643
15919
|
}
|
|
14644
15920
|
|
|
14645
|
-
function
|
|
14646
|
-
|
|
15921
|
+
function styleFieldIsUnset(field) {
|
|
15922
|
+
var table = targetLayer && targetLayer.data;
|
|
15923
|
+
var records = table && table.getRecords();
|
|
15924
|
+
var ids = getTargetIds();
|
|
15925
|
+
var val;
|
|
15926
|
+
if (!records || ids.length === 0) return true;
|
|
15927
|
+
for (var i=0; i<ids.length; i++) {
|
|
15928
|
+
val = records[ids[i]] && records[ids[i]][field];
|
|
15929
|
+
if (val !== undefined && val !== null && val !== '') return false;
|
|
15930
|
+
}
|
|
15931
|
+
return true;
|
|
14647
15932
|
}
|
|
14648
15933
|
|
|
14649
|
-
function
|
|
14650
|
-
|
|
14651
|
-
|
|
14652
|
-
|
|
14653
|
-
marker.css({
|
|
14654
|
-
left: x - 8,
|
|
14655
|
-
top: y - 8
|
|
14656
|
-
});
|
|
14657
|
-
marker.findChild('circle').attr('stroke', getMarkerColor(rgb));
|
|
15934
|
+
function addTargetOption(parts) {
|
|
15935
|
+
if (getActiveLayer() != targetLayer) {
|
|
15936
|
+
parts.push('target=' + internal.formatOptionValue(internal.getLayerTargetId(gui.model, targetLayer)));
|
|
15937
|
+
}
|
|
14658
15938
|
}
|
|
14659
15939
|
|
|
14660
|
-
function
|
|
14661
|
-
|
|
14662
|
-
var g = parseInt(hex.substr(3, 2), 16);
|
|
14663
|
-
var b = parseInt(hex.substr(5, 2), 16);
|
|
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;
|
|
14674
|
-
}
|
|
14675
|
-
return {
|
|
14676
|
-
h: Math.round(h / 360 * 255),
|
|
14677
|
-
s: Math.round(max === 0 ? 0 : d / max * 255),
|
|
14678
|
-
b: max
|
|
14679
|
-
};
|
|
15940
|
+
function getSelectionIds() {
|
|
15941
|
+
return hit ? hit.getSelectionIds() : [];
|
|
14680
15942
|
}
|
|
14681
15943
|
|
|
14682
|
-
function
|
|
14683
|
-
var
|
|
14684
|
-
|
|
14685
|
-
|
|
14686
|
-
}).join('');
|
|
15944
|
+
function getTargetIds() {
|
|
15945
|
+
var ids = getSelectionIds();
|
|
15946
|
+
if (!targetLayer) return [];
|
|
15947
|
+
return ids.length > 0 ? ids : getAllFeatureIds(targetLayer);
|
|
14687
15948
|
}
|
|
14688
15949
|
|
|
14689
|
-
function
|
|
14690
|
-
var
|
|
14691
|
-
var
|
|
14692
|
-
|
|
14693
|
-
|
|
14694
|
-
|
|
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
|
-
};
|
|
15950
|
+
function getAllFeatureIds(lyr) {
|
|
15951
|
+
var ids = [];
|
|
15952
|
+
for (var i=0, n=internal.getFeatureCount(lyr); i<n; i++) {
|
|
15953
|
+
ids.push(i);
|
|
15954
|
+
}
|
|
15955
|
+
return ids;
|
|
14706
15956
|
}
|
|
14707
15957
|
|
|
14708
|
-
function
|
|
14709
|
-
|
|
15958
|
+
function clearSelection() {
|
|
15959
|
+
if (hit) hit.clearSelection();
|
|
15960
|
+
updateControls();
|
|
14710
15961
|
}
|
|
14711
15962
|
|
|
14712
|
-
function
|
|
14713
|
-
|
|
15963
|
+
function updateEditingStatus(count) {
|
|
15964
|
+
editingStatus.text(count > 0 ? 'Editing: ' + count + ' selected' : 'Editing: all');
|
|
15965
|
+
clearLink.classed('hidden', count === 0);
|
|
14714
15966
|
}
|
|
14715
15967
|
|
|
14716
|
-
function
|
|
14717
|
-
|
|
15968
|
+
function setCircleColor(control, color) {
|
|
15969
|
+
control.input.node().value = color;
|
|
15970
|
+
control.chit.css('background-color', isHexColor(color) ? color : 'transparent');
|
|
14718
15971
|
}
|
|
14719
15972
|
|
|
14720
|
-
function
|
|
14721
|
-
|
|
15973
|
+
function parseOpacityValue(str) {
|
|
15974
|
+
var pct = Number(String(str).replace('%', '').trim());
|
|
15975
|
+
if (!isFinite(pct)) return null;
|
|
15976
|
+
return Math.max(0, Math.min(100, pct)) / 100;
|
|
14722
15977
|
}
|
|
14723
15978
|
|
|
14724
|
-
function
|
|
14725
|
-
|
|
15979
|
+
function parsePositiveNumber(str) {
|
|
15980
|
+
if (String(str).trim() === '') return null;
|
|
15981
|
+
var val = Number(String(str).trim());
|
|
15982
|
+
return isFinite(val) && val >= 0 ? val : null;
|
|
14726
15983
|
}
|
|
14727
15984
|
|
|
14728
|
-
function
|
|
14729
|
-
|
|
15985
|
+
function formatOpacityPct(val) {
|
|
15986
|
+
val = Number(val);
|
|
15987
|
+
return isFinite(val) ? Math.round(Math.max(0, Math.min(1, val)) * 100) + '%' : '';
|
|
14730
15988
|
}
|
|
14731
15989
|
|
|
14732
|
-
function
|
|
14733
|
-
|
|
14734
|
-
|
|
14735
|
-
var lyr = getActiveLayer();
|
|
14736
|
-
var hasNewFields;
|
|
14737
|
-
if (!table || ids.length === 0) return;
|
|
14738
|
-
hasNewFields = fields.some(function(field) {
|
|
14739
|
-
return !table.fieldExists(field);
|
|
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'});
|
|
14750
|
-
} else {
|
|
14751
|
-
table.markFieldsChanged(fields, {operation: 'label-style'});
|
|
14752
|
-
}
|
|
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();
|
|
15990
|
+
function formatNumberValue(val) {
|
|
15991
|
+
val = Number(val);
|
|
15992
|
+
return isFinite(val) ? String(val) : '';
|
|
14759
15993
|
}
|
|
14760
15994
|
|
|
14761
|
-
function
|
|
14762
|
-
|
|
14763
|
-
ids.forEach(function(id) {
|
|
14764
|
-
var rec = records[id] || {};
|
|
14765
|
-
updateRecord(rec);
|
|
14766
|
-
records[id] = rec;
|
|
14767
|
-
});
|
|
15995
|
+
function getFieldExpression(field) {
|
|
15996
|
+
return 'd[' + JSON.stringify(field) + ']';
|
|
14768
15997
|
}
|
|
14769
15998
|
|
|
14770
|
-
function
|
|
14771
|
-
|
|
14772
|
-
|
|
14773
|
-
var textNode = getTextNodeById(id);
|
|
14774
|
-
if (textNode) {
|
|
14775
|
-
textNode.classList.add('label-style-selected');
|
|
14776
|
-
}
|
|
14777
|
-
});
|
|
15999
|
+
function getActiveLayer() {
|
|
16000
|
+
var active = gui.model.getActiveLayer();
|
|
16001
|
+
return active && active.layer;
|
|
14778
16002
|
}
|
|
14779
16003
|
|
|
14780
|
-
function
|
|
14781
|
-
|
|
14782
|
-
|
|
14783
|
-
if (!container) return;
|
|
14784
|
-
container.querySelectorAll('.label-style-selected').forEach(function(node) {
|
|
14785
|
-
node.classList.remove('label-style-selected');
|
|
14786
|
-
});
|
|
16004
|
+
function modelSelectLayer(lyr, dataset) {
|
|
16005
|
+
if (lyr) lyr.hidden = false;
|
|
16006
|
+
gui.model.selectLayer(lyr, dataset);
|
|
14787
16007
|
}
|
|
14788
16008
|
|
|
14789
|
-
function
|
|
14790
|
-
var lyr =
|
|
14791
|
-
|
|
14792
|
-
|
|
14793
|
-
|
|
14794
|
-
|
|
16009
|
+
function modeMatchesActiveLayer(mode) {
|
|
16010
|
+
var lyr = getActiveLayer();
|
|
16011
|
+
return mode == 'point_style' && layerCanBeStyled(lyr);
|
|
16012
|
+
}
|
|
16013
|
+
|
|
16014
|
+
function layerCanBeStyled(lyr) {
|
|
16015
|
+
return !!(lyr && lyr.geometry_type == 'point');
|
|
14795
16016
|
}
|
|
14796
16017
|
|
|
16018
|
+
function quoteCommandValue(str) {
|
|
16019
|
+
return "'" + String(str).replace(/'/g, "\\'") + "'";
|
|
16020
|
+
}
|
|
14797
16021
|
}
|
|
14798
16022
|
|
|
14799
16023
|
function Model(gui) {
|
|
@@ -15438,6 +16662,7 @@
|
|
|
15438
16662
|
var targetLayer;
|
|
15439
16663
|
var hitTest;
|
|
15440
16664
|
var pinnedOn; // used in multi-edit mode (selection) for toggling pinning behavior
|
|
16665
|
+
var suppressChangeEvent = false;
|
|
15441
16666
|
|
|
15442
16667
|
// event priority is higher than navigation, so stopping propagation disables
|
|
15443
16668
|
// pan navigation
|
|
@@ -15514,7 +16739,8 @@
|
|
|
15514
16739
|
|
|
15515
16740
|
function selectable() {
|
|
15516
16741
|
var mode = interactionMode();
|
|
15517
|
-
return mode == 'selection' || mode == 'label_style'
|
|
16742
|
+
return mode == 'selection' || mode == 'label_style' ||
|
|
16743
|
+
mode == 'point_style' || mode == 'line_style' || mode == 'polygon_style';
|
|
15518
16744
|
}
|
|
15519
16745
|
|
|
15520
16746
|
function pinnable() {
|
|
@@ -15532,7 +16758,8 @@
|
|
|
15532
16758
|
var mode = interactionMode();
|
|
15533
16759
|
// click used to pin popup and select features
|
|
15534
16760
|
return mode == 'data' || mode == 'info' || mode == 'selection' ||
|
|
15535
|
-
mode == 'label_style' || mode == '
|
|
16761
|
+
mode == 'label_style' || mode == 'point_style' || mode == 'line_style' || mode == 'polygon_style' ||
|
|
16762
|
+
mode == 'rectangles' || mode == 'edit_points';
|
|
15536
16763
|
}
|
|
15537
16764
|
|
|
15538
16765
|
self.getHitId = function() {
|
|
@@ -15656,12 +16883,13 @@
|
|
|
15656
16883
|
// make sure popup is unpinned and turned off when switching editing modes
|
|
15657
16884
|
// (some modes do not support pinning)
|
|
15658
16885
|
gui.on('interaction_mode_change', function(e) {
|
|
15659
|
-
|
|
16886
|
+
clearSelectionSilently();
|
|
15660
16887
|
if (gui.interaction.modeUsesHitDetection(e.mode)) {
|
|
15661
16888
|
turnOn(e.mode);
|
|
15662
16889
|
} else {
|
|
15663
16890
|
turnOff();
|
|
15664
16891
|
}
|
|
16892
|
+
gui.dispatchEvent('map-needs-refresh');
|
|
15665
16893
|
});
|
|
15666
16894
|
|
|
15667
16895
|
gui.on('undo_redo_pre', function() {
|
|
@@ -15685,7 +16913,7 @@
|
|
|
15685
16913
|
|
|
15686
16914
|
// TODO: move pinning to inspection control?
|
|
15687
16915
|
if (clickable()) {
|
|
15688
|
-
updateSelectionState(convertClickDataToSelectionData(hitTest(e)));
|
|
16916
|
+
updateSelectionState(convertClickDataToSelectionData(hitTest(e), e));
|
|
15689
16917
|
}
|
|
15690
16918
|
|
|
15691
16919
|
if (pinned && interactionMode() == 'edit_points') {
|
|
@@ -15727,7 +16955,7 @@
|
|
|
15727
16955
|
|
|
15728
16956
|
// Translates feature hit data from a mouse click into feature selection data
|
|
15729
16957
|
// hitData: hit data from a mouse click
|
|
15730
|
-
function convertClickDataToSelectionData(hitData) {
|
|
16958
|
+
function convertClickDataToSelectionData(hitData, e) {
|
|
15731
16959
|
// mergeCurrentState(hitData);
|
|
15732
16960
|
// TOGGLE pinned state under some conditions
|
|
15733
16961
|
var id = hitData.ids.length > 0 ? hitData.ids[0] : -1;
|
|
@@ -15744,13 +16972,32 @@
|
|
|
15744
16972
|
}
|
|
15745
16973
|
if (selectable()) {
|
|
15746
16974
|
if (id > -1) {
|
|
15747
|
-
selectionIds =
|
|
16975
|
+
selectionIds = styleSelectionMode() ?
|
|
16976
|
+
selectStyleFeature(id, e) :
|
|
16977
|
+
toggleId(id, selectionIds);
|
|
15748
16978
|
}
|
|
15749
16979
|
hitData.ids = selectionIds;
|
|
15750
16980
|
}
|
|
15751
16981
|
return hitData;
|
|
15752
16982
|
}
|
|
15753
16983
|
|
|
16984
|
+
function styleSelectionMode() {
|
|
16985
|
+
var mode = interactionMode();
|
|
16986
|
+
return mode == 'label_style' || mode == 'point_style' ||
|
|
16987
|
+
mode == 'line_style' || mode == 'polygon_style';
|
|
16988
|
+
}
|
|
16989
|
+
|
|
16990
|
+
function selectStyleFeature(id, e) {
|
|
16991
|
+
return eventUsesAdditiveSelection(e) ?
|
|
16992
|
+
toggleId(id, selectionIds) :
|
|
16993
|
+
[id];
|
|
16994
|
+
}
|
|
16995
|
+
|
|
16996
|
+
function eventUsesAdditiveSelection(e) {
|
|
16997
|
+
var original = e && e.originalEvent || e;
|
|
16998
|
+
return !!(original && original.shiftKey);
|
|
16999
|
+
}
|
|
17000
|
+
|
|
15754
17001
|
function mergeSelectionModeHoverData(hitData) {
|
|
15755
17002
|
if (hitData.ids.length === 0 || selectionIds.includes(hitData.ids[0])) {
|
|
15756
17003
|
hitData.ids = selectionIds;
|
|
@@ -15806,11 +17053,17 @@
|
|
|
15806
17053
|
|
|
15807
17054
|
storedData = newData;
|
|
15808
17055
|
gui.container.findChild('.map-layers').classed('symbol-hit', nonEmpty);
|
|
15809
|
-
if (active) {
|
|
17056
|
+
if (active && !suppressChangeEvent) {
|
|
15810
17057
|
triggerChangeEvent();
|
|
15811
17058
|
}
|
|
15812
17059
|
}
|
|
15813
17060
|
|
|
17061
|
+
function clearSelectionSilently() {
|
|
17062
|
+
suppressChangeEvent = true;
|
|
17063
|
+
self.clearSelection();
|
|
17064
|
+
suppressChangeEvent = false;
|
|
17065
|
+
}
|
|
17066
|
+
|
|
15814
17067
|
// check if an event is used in the current interaction mode
|
|
15815
17068
|
function eventIsEnabled(type) {
|
|
15816
17069
|
var mode = interactionMode();
|
|
@@ -16850,7 +18103,9 @@
|
|
|
16850
18103
|
|
|
16851
18104
|
function useBoxZoom() {
|
|
16852
18105
|
var mode = gui.getMode();
|
|
16853
|
-
|
|
18106
|
+
var interactionMode = gui.interaction && gui.interaction.getMode();
|
|
18107
|
+
return !'selection_tool,box_tool,rectangle_tool,drawing_tool'.includes(mode) &&
|
|
18108
|
+
!'label_style,point_style,line_style,polygon_style'.includes(interactionMode);
|
|
16854
18109
|
}
|
|
16855
18110
|
|
|
16856
18111
|
function getBoxData(e1, e2) {
|
|
@@ -17472,6 +18727,30 @@
|
|
|
17472
18727
|
strokeWidth: 2.5
|
|
17473
18728
|
}
|
|
17474
18729
|
},
|
|
18730
|
+
styleSelectionStyles = {
|
|
18731
|
+
polygon: {
|
|
18732
|
+
fillColor: null,
|
|
18733
|
+
strokeColor: 'rgb(255, 198, 0)',
|
|
18734
|
+
strokeOpacity: 0.38,
|
|
18735
|
+
strokeWidth: 5,
|
|
18736
|
+
strokeOverlay: true,
|
|
18737
|
+
batchOverlay: true
|
|
18738
|
+
}, polyline: {
|
|
18739
|
+
fillColor: null,
|
|
18740
|
+
strokeColor: 'rgb(255, 198, 0)',
|
|
18741
|
+
strokeOpacity: 0.38,
|
|
18742
|
+
strokeWidth: 5,
|
|
18743
|
+
strokeOverlay: true,
|
|
18744
|
+
batchOverlay: true
|
|
18745
|
+
}, point: {
|
|
18746
|
+
fillColor: null,
|
|
18747
|
+
strokeColor: 'rgb(255, 198, 0)',
|
|
18748
|
+
strokeOpacity: 0.38,
|
|
18749
|
+
strokeWidth: 5,
|
|
18750
|
+
strokeOverlay: true,
|
|
18751
|
+
batchOverlay: true
|
|
18752
|
+
}
|
|
18753
|
+
},
|
|
17475
18754
|
// currently not used -- selection hover is not styled
|
|
17476
18755
|
selectionHoverStyles = {
|
|
17477
18756
|
polygon: {
|
|
@@ -17522,11 +18801,22 @@
|
|
|
17522
18801
|
return [lyr];
|
|
17523
18802
|
}
|
|
17524
18803
|
layers = [];
|
|
18804
|
+
if (styleOpts.interactionMode == 'line_style' || styleOpts.interactionMode == 'polygon_style' ||
|
|
18805
|
+
styleOpts.interactionMode == 'point_style') {
|
|
18806
|
+
ids = hitData.ids || [];
|
|
18807
|
+
if (ids.length > 0) {
|
|
18808
|
+
lyr = getOverlayLayer(activeLyr, ids);
|
|
18809
|
+
outlineStyle = getSelectionStyle(displayLyr.geometry_type, styleOpts);
|
|
18810
|
+
lyr.gui.style = getOverlayStyle(activeLyr, ids, outlineStyle);
|
|
18811
|
+
layers.push(lyr);
|
|
18812
|
+
}
|
|
18813
|
+
return layers;
|
|
18814
|
+
}
|
|
17525
18815
|
// layer containing selected features, not including hover or pinned feature
|
|
17526
18816
|
ids = utils$1.difference(hitData.ids || [], [hitData.id]);
|
|
17527
18817
|
if (ids.length > 0) {
|
|
17528
18818
|
lyr = getOverlayLayer(activeLyr, ids);
|
|
17529
|
-
outlineStyle =
|
|
18819
|
+
outlineStyle = getSelectionStyle(displayLyr.geometry_type, styleOpts);
|
|
17530
18820
|
lyr.gui.style = getOverlayStyle(activeLyr, ids, outlineStyle);
|
|
17531
18821
|
layers.push(lyr);
|
|
17532
18822
|
}
|
|
@@ -17558,32 +18848,58 @@
|
|
|
17558
18848
|
return;
|
|
17559
18849
|
}
|
|
17560
18850
|
var idx = ids[i];
|
|
18851
|
+
if (outlineStyle.strokeOverlay) {
|
|
18852
|
+
delete style.strokeWidth;
|
|
18853
|
+
delete style.strokeColor;
|
|
18854
|
+
}
|
|
17561
18855
|
baseStyler(style, idx);
|
|
17562
18856
|
if (geomType == 'point') {
|
|
17563
|
-
if (
|
|
17564
|
-
style.radius
|
|
17565
|
-
|
|
17566
|
-
|
|
18857
|
+
if (outlineStyle.strokeOverlay) {
|
|
18858
|
+
if (style.radius > 0) {
|
|
18859
|
+
style.radius += (style.strokeWidth || 0) / 2 + outlineStyle.strokeWidth / 2;
|
|
18860
|
+
}
|
|
18861
|
+
style.fillColor = null;
|
|
18862
|
+
style.strokeColor = outlineStyle.strokeColor;
|
|
18863
|
+
style.strokeWidth = outlineStyle.strokeWidth;
|
|
18864
|
+
} else {
|
|
18865
|
+
if (style.radius > 0) {
|
|
18866
|
+
style.radius += 0.8;
|
|
18867
|
+
if (style.strokeWidth > 0) {
|
|
18868
|
+
style.strokeColor = outlineStyle.dotColor;
|
|
18869
|
+
}
|
|
17567
18870
|
}
|
|
18871
|
+
style.fillColor = outlineStyle.dotColor;
|
|
17568
18872
|
}
|
|
17569
|
-
style.fillColor = outlineStyle.dotColor;
|
|
17570
18873
|
} else {
|
|
17571
18874
|
style.strokeColor = outlineStyle.strokeColor;
|
|
17572
18875
|
style.fillColor = outlineStyle.fillColor;
|
|
17573
|
-
style.strokeWidth =
|
|
18876
|
+
style.strokeWidth = outlineStyle.strokeOverlay ?
|
|
18877
|
+
(style.strokeWidth || 0) + outlineStyle.strokeWidth :
|
|
18878
|
+
Math.max(outlineStyle.strokeWidth, style.strokeWidth || 0);
|
|
17574
18879
|
}
|
|
17575
18880
|
style.opacity = 1;
|
|
17576
18881
|
style.fillOpacity = 1;
|
|
17577
|
-
style.strokeOpacity = 1;
|
|
18882
|
+
style.strokeOpacity = outlineStyle.strokeOpacity >= 0 ? outlineStyle.strokeOpacity : 1;
|
|
17578
18883
|
};
|
|
17579
18884
|
var style = Object.assign({}, baseStyle, {ids, overlay: true, type: 'styled', styler});
|
|
17580
|
-
if (
|
|
18885
|
+
if (outlineStyle.batchOverlay) {
|
|
18886
|
+
style.batchOverlay = true;
|
|
18887
|
+
}
|
|
18888
|
+
if (baseStyle.dotSize > 0 && outlineStyle.dotSize > 0) {
|
|
17581
18889
|
// dot size must be a static property (not applied by styler function)
|
|
17582
18890
|
style.dotSize = outlineStyle.dotSize;
|
|
17583
18891
|
}
|
|
17584
18892
|
return style;
|
|
17585
18893
|
}
|
|
17586
18894
|
|
|
18895
|
+
function getSelectionStyle(geomType, styleOpts) {
|
|
18896
|
+
if (styleOpts.interactionMode == 'line_style' || styleOpts.interactionMode == 'polygon_style' ||
|
|
18897
|
+
styleOpts.interactionMode == 'point_style') {
|
|
18898
|
+
return styleSelectionStyles[geomType] || selectionStyles[geomType];
|
|
18899
|
+
}
|
|
18900
|
+
return selectionStyles[geomType];
|
|
18901
|
+
}
|
|
18902
|
+
|
|
17587
18903
|
// style for vertex edit mode
|
|
17588
18904
|
function getVertexStyle(o) {
|
|
17589
18905
|
return {
|
|
@@ -19914,21 +21230,24 @@
|
|
|
19914
21230
|
var draw = getShapePencil(arcs, _ext);
|
|
19915
21231
|
var key, item, shp;
|
|
19916
21232
|
var styler = style.styler || null;
|
|
21233
|
+
var drawStyle = styler ? utils$1.defaults({}, style) : style;
|
|
19917
21234
|
for (var i=0; i<shapes.length; i++) {
|
|
19918
21235
|
shp = shapes[i];
|
|
19919
21236
|
if (!shp || filter && !filter(i)) continue;
|
|
19920
21237
|
if (styler) {
|
|
19921
|
-
styler(
|
|
21238
|
+
styler(drawStyle, i);
|
|
19922
21239
|
}
|
|
19923
|
-
if (
|
|
21240
|
+
if (!drawStyle.batchOverlay && (drawStyle.overlay ||
|
|
21241
|
+
drawStyle.opacity < 1 || drawStyle.fillOpacity < 1 ||
|
|
21242
|
+
drawStyle.strokeOpacity < 1 || drawStyle.fillEffect)) {
|
|
19924
21243
|
// don't batch shapes with opacity, in case they overlap
|
|
19925
|
-
drawPaths([shp], startPath, draw,
|
|
21244
|
+
drawPaths([shp], startPath, draw, drawStyle);
|
|
19926
21245
|
continue;
|
|
19927
21246
|
}
|
|
19928
|
-
key = getStyleKey(
|
|
21247
|
+
key = getStyleKey(drawStyle);
|
|
19929
21248
|
if (key in styleIndex === false) {
|
|
19930
21249
|
styleIndex[key] = {
|
|
19931
|
-
style: utils$1.defaults({},
|
|
21250
|
+
style: utils$1.defaults({}, drawStyle),
|
|
19932
21251
|
shapes: []
|
|
19933
21252
|
};
|
|
19934
21253
|
}
|
|
@@ -22294,6 +23613,8 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
22294
23613
|
gui.interaction = new InteractionMode(gui);
|
|
22295
23614
|
gui.editToolbar = new EditToolbar(gui);
|
|
22296
23615
|
gui.labelTool = new LabelTool(gui);
|
|
23616
|
+
gui.layerStyleTool = new LayerStyleTool(gui);
|
|
23617
|
+
gui.pointStyleTool = new PointStyleTool(gui);
|
|
22297
23618
|
|
|
22298
23619
|
gui.showProgressMessage = function(msg) {
|
|
22299
23620
|
if (!gui.progressMessage) {
|