@theseam/ui-common 0.3.1 → 0.3.4
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/bundles/theseam-ui-common-dynamic.umd.js +1 -0
- package/bundles/theseam-ui-common-dynamic.umd.js.map +1 -1
- package/bundles/theseam-ui-common-form-field.umd.js +1 -1
- package/bundles/theseam-ui-common-form-field.umd.js.map +1 -1
- package/bundles/theseam-ui-common-google-maps.umd.js +2202 -0
- package/bundles/theseam-ui-common-google-maps.umd.js.map +1 -0
- package/bundles/theseam-ui-common-menu.umd.js +1 -0
- package/bundles/theseam-ui-common-menu.umd.js.map +1 -1
- package/bundles/theseam-ui-common-modal.umd.js +21 -1
- package/bundles/theseam-ui-common-modal.umd.js.map +1 -1
- package/bundles/theseam-ui-common-utils.umd.js +610 -136
- package/bundles/theseam-ui-common-utils.umd.js.map +1 -1
- package/bundles/theseam-ui-common-widget.umd.js +3 -1
- package/bundles/theseam-ui-common-widget.umd.js.map +1 -1
- package/esm2015/dynamic/evaluators/jexl-evaluator/jexl-evaluator.js +2 -1
- package/esm2015/form-field/input.directive.js +2 -2
- package/esm2015/google-maps/google-maps/google-maps.component.js +261 -0
- package/esm2015/google-maps/google-maps-contextmenu.js +113 -0
- package/esm2015/google-maps/google-maps-controls.service.js +70 -0
- package/esm2015/google-maps/google-maps-feature-helpers.js +177 -0
- package/esm2015/google-maps/google-maps-places-autocomplete/google-maps-places-autocomplete.component.js +195 -0
- package/esm2015/google-maps/google-maps-places-autocomplete/google-maps-places-autocomplete.directive.js +163 -0
- package/esm2015/google-maps/google-maps-recenter-button-control/google-maps-recenter-button-control.component.js +57 -0
- package/esm2015/google-maps/google-maps-upload-button-control/google-maps-upload-button-control.component.js +119 -0
- package/esm2015/google-maps/google-maps.module.js +45 -0
- package/esm2015/google-maps/google-maps.service.js +344 -0
- package/esm2015/google-maps/map-control.component.js +65 -0
- package/esm2015/google-maps/map-controls-service.js +4 -0
- package/esm2015/google-maps/map-file-drop/map-file-drop.component.js +135 -0
- package/esm2015/google-maps/map-value-manager.service.js +46 -0
- package/esm2015/google-maps/public-api.js +14 -0
- package/esm2015/google-maps/theseam-ui-common-google-maps.js +6 -0
- package/esm2015/menu/menu-toggle.directive.js +2 -1
- package/esm2015/modal/modal-ref.js +22 -2
- package/esm2015/utils/geo-json/coerce-feature-collection.js +44 -0
- package/esm2015/utils/geo-json/geo-json-to-area.js +11 -0
- package/esm2015/utils/geo-json/is-feature-collection.validator.js +21 -0
- package/esm2015/utils/geo-json/is-only-geometry-types.js +23 -0
- package/esm2015/utils/geo-json/is-only-geometry-types.validator.js +32 -0
- package/esm2015/utils/geo-json/merge-polygons.js +35 -0
- package/esm2015/utils/geo-json/no-inner-rings.validator.js +63 -0
- package/esm2015/utils/geo-json/no-kinks.validator.js +39 -0
- package/esm2015/utils/geo-json/read-geo-file.js +99 -0
- package/esm2015/utils/geo-json/split-multi-polygons.js +29 -0
- package/esm2015/utils/is-null-or-undefined.js +1 -1
- package/esm2015/utils/public-api.js +11 -1
- package/esm2015/widget/widget-content-components/widget-tile/widget-tile.component.js +4 -2
- package/fesm2015/theseam-ui-common-dynamic.js +1 -0
- package/fesm2015/theseam-ui-common-dynamic.js.map +1 -1
- package/fesm2015/theseam-ui-common-form-field.js +1 -1
- package/fesm2015/theseam-ui-common-form-field.js.map +1 -1
- package/fesm2015/theseam-ui-common-google-maps.js +1729 -0
- package/fesm2015/theseam-ui-common-google-maps.js.map +1 -0
- package/fesm2015/theseam-ui-common-menu.js +1 -0
- package/fesm2015/theseam-ui-common-menu.js.map +1 -1
- package/fesm2015/theseam-ui-common-modal.js +21 -1
- package/fesm2015/theseam-ui-common-modal.js.map +1 -1
- package/fesm2015/theseam-ui-common-utils.js +477 -94
- package/fesm2015/theseam-ui-common-utils.js.map +1 -1
- package/fesm2015/theseam-ui-common-widget.js +3 -1
- package/fesm2015/theseam-ui-common-widget.js.map +1 -1
- package/form-field/theseam-ui-common-form-field.metadata.json +1 -1
- package/google-maps/google-maps/google-maps.component.d.ts +89 -0
- package/google-maps/google-maps-contextmenu.d.ts +15 -0
- package/google-maps/google-maps-controls.service.d.ts +23 -0
- package/google-maps/google-maps-feature-helpers.d.ts +37 -0
- package/google-maps/google-maps-places-autocomplete/google-maps-places-autocomplete.component.d.ts +104 -0
- package/google-maps/google-maps-places-autocomplete/google-maps-places-autocomplete.directive.d.ts +80 -0
- package/google-maps/google-maps-recenter-button-control/google-maps-recenter-button-control.component.d.ts +21 -0
- package/google-maps/google-maps-upload-button-control/google-maps-upload-button-control.component.d.ts +34 -0
- package/google-maps/google-maps.module.d.ts +2 -0
- package/google-maps/google-maps.service.d.ts +53 -0
- package/google-maps/map-control.component.d.ts +20 -0
- package/google-maps/map-controls-service.d.ts +13 -0
- package/google-maps/map-file-drop/map-file-drop.component.d.ts +34 -0
- package/google-maps/map-value-manager.service.d.ts +18 -0
- package/google-maps/package.json +11 -0
- package/google-maps/public-api.d.ts +13 -0
- package/google-maps/theseam-ui-common-google-maps.d.ts +5 -0
- package/google-maps/theseam-ui-common-google-maps.metadata.json +1 -0
- package/modal/modal-ref.d.ts +1 -0
- package/modal/theseam-ui-common-modal.metadata.json +1 -1
- package/package.json +17 -10
- package/utils/geo-json/coerce-feature-collection.d.ts +2 -0
- package/utils/geo-json/geo-json-to-area.d.ts +6 -0
- package/utils/geo-json/is-feature-collection.validator.d.ts +3 -0
- package/utils/geo-json/is-only-geometry-types.d.ts +5 -0
- package/utils/geo-json/is-only-geometry-types.validator.d.ts +4 -0
- package/utils/geo-json/merge-polygons.d.ts +9 -0
- package/utils/geo-json/no-inner-rings.validator.d.ts +10 -0
- package/utils/geo-json/no-kinks.validator.d.ts +3 -0
- package/utils/geo-json/read-geo-file.d.ts +7 -0
- package/utils/geo-json/split-multi-polygons.d.ts +8 -0
- package/utils/is-null-or-undefined.d.ts +1 -1
- package/utils/public-api.d.ts +10 -0
- package/utils/theseam-ui-common-utils.metadata.json +1 -1
- package/widget/styles/_variables.scss +1 -0
- package/widget/theseam-ui-common-widget.metadata.json +1 -1
- package/widget/widget-content-components/widget-tile/widget-tile.component.d.ts +2 -0
- package/widget/widget-content-components/widget-tile/widget-tile.component.scss +1 -1
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { switchMap, startWith, map, distinctUntilChanged, mapTo, filter, take, pairwise, toArray, tap, shareReplay, publishReplay, refCount, skip } from 'rxjs/operators';
|
|
2
2
|
import { of, merge, interval, from, combineLatest, Observable, isObservable, BehaviorSubject, Subject } from 'rxjs';
|
|
3
|
-
import
|
|
3
|
+
import area from '@turf/area';
|
|
4
|
+
import { convertArea } from '@turf/helpers';
|
|
5
|
+
import kinks from '@turf/kinks';
|
|
6
|
+
import { __awaiter, __rest } from 'tslib';
|
|
7
|
+
import { isDevMode } from '@angular/core';
|
|
4
8
|
import fileType from '@marklb/file-type';
|
|
9
|
+
import shp from 'shpjs';
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
12
|
*
|
|
@@ -307,6 +312,476 @@ function isEmptyUrlRoute(activatedRoute) {
|
|
|
307
312
|
return activatedRoute.snapshot.url.length === 0;
|
|
308
313
|
}
|
|
309
314
|
|
|
315
|
+
// TODO: Make this more thorough and maybe error on unrecognized.
|
|
316
|
+
function coerceFeatureCollection(value) {
|
|
317
|
+
return parseValue(value);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Parses the value to a FeatureCollection object or null if it is not a
|
|
321
|
+
* FeatureCollection.
|
|
322
|
+
*/
|
|
323
|
+
function parseValue(value) {
|
|
324
|
+
const _value = parseStringValue(value);
|
|
325
|
+
if (isFeatureCollectionValue(_value)) {
|
|
326
|
+
return _value;
|
|
327
|
+
}
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Tries to parse the value to an object, in case the value is a stringified
|
|
332
|
+
* json.
|
|
333
|
+
*/
|
|
334
|
+
function parseStringValue(value) {
|
|
335
|
+
if (typeof value === 'string') {
|
|
336
|
+
try {
|
|
337
|
+
return JSON.parse(value);
|
|
338
|
+
}
|
|
339
|
+
catch (_a) {
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return value;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Checks if the value is a FeatureCollection.
|
|
347
|
+
*
|
|
348
|
+
* NOTE: This is not a thorough FeatureCollection check. It only checks that the
|
|
349
|
+
* value is an object resembling a GeoJSON.FeatureCollection, enough for the
|
|
350
|
+
* validator.
|
|
351
|
+
*/
|
|
352
|
+
function isFeatureCollectionValue(value) {
|
|
353
|
+
if (value === undefined || value === null) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
return value.type === 'FeatureCollection' && Array.isArray(value.features);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
*
|
|
361
|
+
*/
|
|
362
|
+
function geoJsonToArea(geoJson, units = 'acres') {
|
|
363
|
+
const area_mSqr = area(geoJson);
|
|
364
|
+
const acres = convertArea(area_mSqr, 'meters', units);
|
|
365
|
+
return acres;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const IS_FEATURE_COLLECTION_VALIDATOR_NAME = 'is-feature-collection';
|
|
369
|
+
function isFeatureCollectionValidator() {
|
|
370
|
+
return (control) => {
|
|
371
|
+
// Don't need to validate if there isn't a value. Use `Validators.required` for that.
|
|
372
|
+
if (isEmptyInputValue(control.value)) {
|
|
373
|
+
return null; // don't validate empty values to allow optional controls
|
|
374
|
+
}
|
|
375
|
+
const value = coerceFeatureCollection(control.value);
|
|
376
|
+
if (value === null) {
|
|
377
|
+
return {
|
|
378
|
+
[IS_FEATURE_COLLECTION_VALIDATOR_NAME]: {
|
|
379
|
+
reason: `Must be a FeatureCollection.`,
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
return null;
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Returns true if the GeoJSON is only specifies geometries.
|
|
389
|
+
*/
|
|
390
|
+
function isOnlyGeometryTypes(featureCollection, types) {
|
|
391
|
+
if (types.length === 0) {
|
|
392
|
+
if (featureCollection.features.length > 0) {
|
|
393
|
+
// If no types are specified then there can't be any specified types found.
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
// If no types are specified and there are no features then there is
|
|
398
|
+
// nothing to say a specified type isn't found.
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
for (const f of featureCollection.features) {
|
|
403
|
+
if (types.indexOf(f.geometry.type) === -1) {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const IS_ONLY_GEOMETRY_TYPES_VALIDATOR_NAME = 'is-only-geometry-types';
|
|
411
|
+
function isOnlyGeometryTypesValidator(types) {
|
|
412
|
+
return (control) => {
|
|
413
|
+
// Don't need to validate if there isn't a value. Use `Validators.required` for that.
|
|
414
|
+
if (isEmptyInputValue(control.value)) {
|
|
415
|
+
return null; // don't validate empty values to allow optional controls
|
|
416
|
+
}
|
|
417
|
+
const value = coerceFeatureCollection(control.value);
|
|
418
|
+
if (value === null) {
|
|
419
|
+
// If there isn't a FeatureCollection then there is nothing to validate.
|
|
420
|
+
// Use 'isFeatureCollection' to validate the value is a FeatureCollection.
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
if (!isOnlyGeometryTypes(value, types)) {
|
|
424
|
+
const typesNotAllowed = value.features
|
|
425
|
+
.map(f => f.geometry.type)
|
|
426
|
+
.filter(t => types.indexOf(t) === -1);
|
|
427
|
+
const distinctTypesNotAllowed = Array.from(new Set(typesNotAllowed));
|
|
428
|
+
return {
|
|
429
|
+
[IS_ONLY_GEOMETRY_TYPES_VALIDATOR_NAME]: {
|
|
430
|
+
reason: `Only geometry type${(types.length === 1 ? '' : 's')} ${types.join(', ')} allowed.`,
|
|
431
|
+
notAllowedGeometryTypesFound: distinctTypesNotAllowed,
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
return null;
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Merge Polygon and MultiPolygon geometries into a single MultiPolygon. Any
|
|
441
|
+
* properties, other than 'coordinates', of the Polygons and MultiPolygons will
|
|
442
|
+
* be lost.
|
|
443
|
+
*
|
|
444
|
+
* NOTE: Polygons and MultPolygons in a GeometryCollection will not be merged.
|
|
445
|
+
*/
|
|
446
|
+
function mergePolygons(featureCollection) {
|
|
447
|
+
const multiPolygon = {
|
|
448
|
+
type: 'MultiPolygon',
|
|
449
|
+
coordinates: [],
|
|
450
|
+
};
|
|
451
|
+
for (let i = 0; i < featureCollection.features.length; i++) {
|
|
452
|
+
const f = featureCollection.features[i];
|
|
453
|
+
if (f.geometry.type === 'Polygon') {
|
|
454
|
+
multiPolygon.coordinates.push(f.geometry.coordinates);
|
|
455
|
+
featureCollection.features.splice(i, 1);
|
|
456
|
+
i--;
|
|
457
|
+
}
|
|
458
|
+
else if (f.geometry.type === 'MultiPolygon') {
|
|
459
|
+
multiPolygon.coordinates.push(...f.geometry.coordinates);
|
|
460
|
+
featureCollection.features.splice(i, 1);
|
|
461
|
+
i--;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
if (multiPolygon.coordinates.length > 0) {
|
|
465
|
+
const feature = {
|
|
466
|
+
type: 'Feature',
|
|
467
|
+
geometry: multiPolygon,
|
|
468
|
+
properties: {},
|
|
469
|
+
};
|
|
470
|
+
featureCollection.features.push(feature);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const NO_INNER_RINGS_VALIDATOR_NAME = 'no-inner-rings';
|
|
475
|
+
/**
|
|
476
|
+
* Validates that a FeatureCollection does not contain any Polygon with inner
|
|
477
|
+
* rings("holes").
|
|
478
|
+
*
|
|
479
|
+
* NOTE: Only considers Polygon and MultiPolygon. Does not consider
|
|
480
|
+
* GeometryCollection.
|
|
481
|
+
*/
|
|
482
|
+
function noInnerRingsValidator() {
|
|
483
|
+
return (control) => {
|
|
484
|
+
// Don't need to validate if there isn't a value. Use `Validators.required` for that.
|
|
485
|
+
if (isEmptyInputValue(control.value)) {
|
|
486
|
+
return null; // don't validate empty values to allow optional controls
|
|
487
|
+
}
|
|
488
|
+
const value = coerceFeatureCollection(control.value);
|
|
489
|
+
if (value === null) {
|
|
490
|
+
// If there isn't a FeatureCollection then there is nothing to validate.
|
|
491
|
+
// Use 'isFeatureCollection' to validate the value is a FeatureCollection.
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
if (hasInnerRing(value)) {
|
|
495
|
+
return {
|
|
496
|
+
[NO_INNER_RINGS_VALIDATOR_NAME]: {
|
|
497
|
+
reason: `A shape cannot have an inner ring.`
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
return null;
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Checks if a FeatureCollection contains any geometries with an inner
|
|
506
|
+
* ring("hole").
|
|
507
|
+
*
|
|
508
|
+
* NOTE: Does not consider GeometryCollection.
|
|
509
|
+
*/
|
|
510
|
+
function hasInnerRing(featureCollection) {
|
|
511
|
+
for (const f of featureCollection.features) {
|
|
512
|
+
// The spec says the right-hand rule must be followed, but also specifies
|
|
513
|
+
// that tools should not reject polygons that do not follow the right-hand
|
|
514
|
+
// rule. It does specify that the first ring must be the exterior ring and
|
|
515
|
+
// the others must be the interior. So, this should be safe to just check
|
|
516
|
+
// if there are multiple rings, instead of checking their winding orders.
|
|
517
|
+
//
|
|
518
|
+
// Polygon spec: https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.6
|
|
519
|
+
if (f.geometry.type === 'Polygon') {
|
|
520
|
+
if (f.geometry.coordinates.length > 1) {
|
|
521
|
+
return true;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
else if (f.geometry.type === 'MultiPolygon') {
|
|
525
|
+
for (const coords of f.geometry.coordinates) {
|
|
526
|
+
if (coords.length > 1) {
|
|
527
|
+
return true;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const kinkableGeometryTypes = ['LineString', 'MultiLineString', 'MultiPolygon', 'Polygon'];
|
|
536
|
+
const NO_KINKS_VALIDATOR_NAME = 'no-kinks';
|
|
537
|
+
function noKinksValidator() {
|
|
538
|
+
return (control) => {
|
|
539
|
+
// Don't need to validate if there isn't a value. Use `Validators.required` for that.
|
|
540
|
+
if (isEmptyInputValue(control.value)) {
|
|
541
|
+
return null; // don't validate empty values to allow optional controls
|
|
542
|
+
}
|
|
543
|
+
const value = coerceFeatureCollection(control.value);
|
|
544
|
+
if (value === null) {
|
|
545
|
+
return null;
|
|
546
|
+
}
|
|
547
|
+
const kinksFound = [];
|
|
548
|
+
for (const f of value.features) {
|
|
549
|
+
if (kinkableGeometryTypes.indexOf(f.geometry.type) !== -1) {
|
|
550
|
+
const _kinks = kinks(f);
|
|
551
|
+
if (_kinks.features.length > 0) {
|
|
552
|
+
kinksFound.push({
|
|
553
|
+
feature: f,
|
|
554
|
+
kinks: _kinks,
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if (kinksFound.length > 0) {
|
|
560
|
+
return {
|
|
561
|
+
[NO_KINKS_VALIDATOR_NAME]: {
|
|
562
|
+
reason: 'Paths should not intersect themself.',
|
|
563
|
+
featuresWithKink: kinksFound,
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
return null;
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// import { Buffer } from 'buffer/'
|
|
572
|
+
const Buffer$1 = require('buffer/').Buffer;
|
|
573
|
+
function readFileAsync(file) {
|
|
574
|
+
return new Promise((resolve, reject) => {
|
|
575
|
+
const reader = new FileReader();
|
|
576
|
+
reader.onload = () => {
|
|
577
|
+
resolve(reader.result);
|
|
578
|
+
};
|
|
579
|
+
reader.readAsArrayBuffer(file);
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
function readFileAsDataUrlAsync(file) {
|
|
583
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
584
|
+
return new Promise((resolve, reject) => {
|
|
585
|
+
const reader = new FileReader();
|
|
586
|
+
reader.onload = () => {
|
|
587
|
+
resolve(reader.result);
|
|
588
|
+
};
|
|
589
|
+
reader.readAsDataURL(file);
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
function fileBufferToBlob(fileBuffer, defaultMime = 'application/octet-stream') {
|
|
594
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
595
|
+
const fType = fileType(fileBuffer);
|
|
596
|
+
const mime = (fType) ? fType.mime : defaultMime;
|
|
597
|
+
const blob = new Blob([fileBuffer], { type: mime });
|
|
598
|
+
return blob;
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
function fileBufferToObjectUrl(fileBuffer, defaultMime = 'application/octet-stream') {
|
|
602
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
603
|
+
const file = yield fileBufferToBlob(fileBuffer, defaultMime);
|
|
604
|
+
const fileURL = URL.createObjectURL(file);
|
|
605
|
+
return fileURL;
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
function fileDataFromBuffer(fileBuffer, defaultMime = 'application/octet-stream') {
|
|
609
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
610
|
+
const _fileBuffer = Buffer$1.from(fileBuffer);
|
|
611
|
+
const fType = fileType(_fileBuffer);
|
|
612
|
+
const ext = fType && fType.ext || undefined;
|
|
613
|
+
const mime = fType ? fType.mime : defaultMime;
|
|
614
|
+
const blob = new Blob([_fileBuffer], { type: mime });
|
|
615
|
+
const fileData = { ext, mime, blob };
|
|
616
|
+
return fileData;
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
function openBlob(blob, target, filename) {
|
|
620
|
+
// NOTE: IE and MSEdge do not allow Blob resources as a source for
|
|
621
|
+
// tabs or iframes. msSaveOrOpenBlob is used as a workaround. I
|
|
622
|
+
// haven't been able to find a way to just open the Blob file in
|
|
623
|
+
// another tab yet for IE or MSEdge.
|
|
624
|
+
if (window.navigator.msSaveOrOpenBlob) {
|
|
625
|
+
window.navigator.msSaveOrOpenBlob(blob, filename);
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
const url = URL.createObjectURL(blob);
|
|
629
|
+
const win = window.open(url, target);
|
|
630
|
+
// TODO: Consider if always setting opener to null is to restrictive
|
|
631
|
+
// if (win && target && target.toLowerCase() === '_blank') {
|
|
632
|
+
// win.opener = null
|
|
633
|
+
// }
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/** Returns object without property */
|
|
638
|
+
function withoutProperty(obj, propName) {
|
|
639
|
+
const _a = obj, _b = propName, _ = _a[_b], without = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
|
|
640
|
+
return without;
|
|
641
|
+
}
|
|
642
|
+
/** Returns object without properties */
|
|
643
|
+
function withoutProperties(obj, propNames) {
|
|
644
|
+
let without = obj;
|
|
645
|
+
for (const propName of propNames) {
|
|
646
|
+
without = withoutProperty(without, propName);
|
|
647
|
+
}
|
|
648
|
+
return without;
|
|
649
|
+
}
|
|
650
|
+
/** Delete property of object */
|
|
651
|
+
function deleteProperty(obj, propName) {
|
|
652
|
+
if (obj.hasOwnProperty(propName)) {
|
|
653
|
+
delete obj[propName];
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
/** Delete properties of object */
|
|
657
|
+
function deleteProperties(obj, propNames) {
|
|
658
|
+
for (const propName of propNames) {
|
|
659
|
+
deleteProperty(obj, propName);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const Buffer = require('buffer/').Buffer;
|
|
664
|
+
/**
|
|
665
|
+
* Reads a File, or buffer of file content, in GeoJSON or ESRI Shapefile format
|
|
666
|
+
* and returns a GeoJSON `FeatureCollection`.
|
|
667
|
+
*/
|
|
668
|
+
function readGeoFile(fileOrBuffer) {
|
|
669
|
+
var _a;
|
|
670
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
671
|
+
const buffer = yield coerceFileOrBufferToBuffer(fileOrBuffer);
|
|
672
|
+
if (isShpFile(buffer)) {
|
|
673
|
+
return yield parseShpFile(buffer);
|
|
674
|
+
}
|
|
675
|
+
else if (((_a = fileType(buffer)) === null || _a === void 0 ? void 0 : _a.mime) === 'application/zip') {
|
|
676
|
+
try {
|
|
677
|
+
return yield parseShpZip(buffer);
|
|
678
|
+
}
|
|
679
|
+
catch (e) {
|
|
680
|
+
// NOTE: If 'shpjs' updates or we switch to a fork, where it doesn't use
|
|
681
|
+
// node buffers, then we can remove this rethrow.
|
|
682
|
+
if (isDevMode()) {
|
|
683
|
+
if (e.message === 'nodebuffer is not supported by this platform') {
|
|
684
|
+
console.warn('Try adding Buffer polyfill.\n' +
|
|
685
|
+
'Install: npm install buffer\n' +
|
|
686
|
+
'Add `global.Buffer = global.Buffer || require(\'buffer\').Buffer` to "src/polyfills.ts"');
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
throw e;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return parseGeoJson(buffer);
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
function coerceFileOrBufferToBuffer(fileOrBuffer) {
|
|
696
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
697
|
+
if (fileOrBuffer instanceof File) {
|
|
698
|
+
const arrBuf = yield readFileAsync(fileOrBuffer);
|
|
699
|
+
return Buffer.from(arrBuf);
|
|
700
|
+
}
|
|
701
|
+
return Buffer.from(fileOrBuffer);
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
// NOTE: Our current version of file-type does not detect shp files. We can
|
|
705
|
+
// remove this function when file-types is upgraded.
|
|
706
|
+
function isShpFile(buffer) {
|
|
707
|
+
const header = [0x27, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
|
|
708
|
+
const offset = 2;
|
|
709
|
+
if (buffer.length < (header.length + offset)) {
|
|
710
|
+
return false;
|
|
711
|
+
}
|
|
712
|
+
for (let i = 0; i < header.length; i++) {
|
|
713
|
+
if (header[i] !== buffer[i + offset]) {
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
return true;
|
|
718
|
+
}
|
|
719
|
+
function parseShpFile(buffer) {
|
|
720
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
721
|
+
const geometries = yield shp.parseShp(buffer, undefined);
|
|
722
|
+
const featCollection = {
|
|
723
|
+
type: 'FeatureCollection',
|
|
724
|
+
features: geometries.map(geom => ({
|
|
725
|
+
type: 'Feature',
|
|
726
|
+
geometry: geom,
|
|
727
|
+
properties: {}
|
|
728
|
+
}))
|
|
729
|
+
};
|
|
730
|
+
return featCollection;
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
function parseShpZip(buffer) {
|
|
734
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
735
|
+
let featCollection = yield shp.parseZip(buffer, undefined);
|
|
736
|
+
if (Array.isArray(featCollection)) {
|
|
737
|
+
if (featCollection.length === 0) {
|
|
738
|
+
throw Error(`Shape data not found.`);
|
|
739
|
+
}
|
|
740
|
+
else if (featCollection.length > 1) {
|
|
741
|
+
throw Error(`Multiple shape files not supported.`);
|
|
742
|
+
}
|
|
743
|
+
featCollection = featCollection[0];
|
|
744
|
+
}
|
|
745
|
+
return withoutProperty(featCollection, 'fileName');
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
function parseGeoJson(buffer) {
|
|
749
|
+
const json = JSON.parse(buffer.toString());
|
|
750
|
+
if ((json === null || json === void 0 ? void 0 : json.type) === 'FeatureCollection' && Array.isArray(json === null || json === void 0 ? void 0 : json.features)) {
|
|
751
|
+
return json;
|
|
752
|
+
}
|
|
753
|
+
throw Error(`Unable to parse as GeoJSON.`);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* Split all MultiPolygon into Polygon. Any properties, other than
|
|
758
|
+
* 'coordinates', of the MultiPolygons will be lost.
|
|
759
|
+
*
|
|
760
|
+
* NOTE: MultiPolygons in a GeometryCollection will not be split.
|
|
761
|
+
*/
|
|
762
|
+
function splitMultiPolygons(featureCollection) {
|
|
763
|
+
for (let i = 0; i < featureCollection.features.length; i++) {
|
|
764
|
+
if (featureCollection.features[i]) {
|
|
765
|
+
const geometry = featureCollection.features[i].geometry;
|
|
766
|
+
if (geometry.type === 'MultiPolygon') {
|
|
767
|
+
const features = splitMultPolygon(geometry).map(p => ({
|
|
768
|
+
type: 'Feature',
|
|
769
|
+
geometry: p,
|
|
770
|
+
properties: {},
|
|
771
|
+
}));
|
|
772
|
+
featureCollection.features.splice(i, 1, ...features);
|
|
773
|
+
i += Math.max(features.length - 1, 0);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
function splitMultPolygon(multiPolygon) {
|
|
779
|
+
return multiPolygon.coordinates.map(c => ({
|
|
780
|
+
type: 'Polygon',
|
|
781
|
+
coordinates: c,
|
|
782
|
+
}));
|
|
783
|
+
}
|
|
784
|
+
|
|
310
785
|
// Based on source: https://github.com/sindresorhus/array-move/blob/main/index.js
|
|
311
786
|
/**
|
|
312
787
|
Moves the item to the new position in the input array. Useful for huge arrays
|
|
@@ -441,98 +916,6 @@ function loadStyleSheet(path) {
|
|
|
441
916
|
});
|
|
442
917
|
}
|
|
443
918
|
|
|
444
|
-
/** Returns object without property */
|
|
445
|
-
function withoutProperty(obj, propName) {
|
|
446
|
-
const _a = obj, _b = propName, _ = _a[_b], without = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
|
|
447
|
-
return without;
|
|
448
|
-
}
|
|
449
|
-
/** Returns object without properties */
|
|
450
|
-
function withoutProperties(obj, propNames) {
|
|
451
|
-
let without = obj;
|
|
452
|
-
for (const propName of propNames) {
|
|
453
|
-
without = withoutProperty(without, propName);
|
|
454
|
-
}
|
|
455
|
-
return without;
|
|
456
|
-
}
|
|
457
|
-
/** Delete property of object */
|
|
458
|
-
function deleteProperty(obj, propName) {
|
|
459
|
-
if (obj.hasOwnProperty(propName)) {
|
|
460
|
-
delete obj[propName];
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
/** Delete properties of object */
|
|
464
|
-
function deleteProperties(obj, propNames) {
|
|
465
|
-
for (const propName of propNames) {
|
|
466
|
-
deleteProperty(obj, propName);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
// import { Buffer } from 'buffer/'
|
|
471
|
-
const Buffer = require('buffer/').Buffer;
|
|
472
|
-
function readFileAsync(file) {
|
|
473
|
-
return new Promise((resolve, reject) => {
|
|
474
|
-
const reader = new FileReader();
|
|
475
|
-
reader.onload = () => {
|
|
476
|
-
resolve(reader.result);
|
|
477
|
-
};
|
|
478
|
-
reader.readAsArrayBuffer(file);
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
function readFileAsDataUrlAsync(file) {
|
|
482
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
483
|
-
return new Promise((resolve, reject) => {
|
|
484
|
-
const reader = new FileReader();
|
|
485
|
-
reader.onload = () => {
|
|
486
|
-
resolve(reader.result);
|
|
487
|
-
};
|
|
488
|
-
reader.readAsDataURL(file);
|
|
489
|
-
});
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
function fileBufferToBlob(fileBuffer, defaultMime = 'application/octet-stream') {
|
|
493
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
494
|
-
const fType = fileType(fileBuffer);
|
|
495
|
-
const mime = (fType) ? fType.mime : defaultMime;
|
|
496
|
-
const blob = new Blob([fileBuffer], { type: mime });
|
|
497
|
-
return blob;
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
function fileBufferToObjectUrl(fileBuffer, defaultMime = 'application/octet-stream') {
|
|
501
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
502
|
-
const file = yield fileBufferToBlob(fileBuffer, defaultMime);
|
|
503
|
-
const fileURL = URL.createObjectURL(file);
|
|
504
|
-
return fileURL;
|
|
505
|
-
});
|
|
506
|
-
}
|
|
507
|
-
function fileDataFromBuffer(fileBuffer, defaultMime = 'application/octet-stream') {
|
|
508
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
509
|
-
const _fileBuffer = Buffer.from(fileBuffer);
|
|
510
|
-
const fType = fileType(_fileBuffer);
|
|
511
|
-
const ext = fType && fType.ext || undefined;
|
|
512
|
-
const mime = fType ? fType.mime : defaultMime;
|
|
513
|
-
const blob = new Blob([_fileBuffer], { type: mime });
|
|
514
|
-
const fileData = { ext, mime, blob };
|
|
515
|
-
return fileData;
|
|
516
|
-
});
|
|
517
|
-
}
|
|
518
|
-
function openBlob(blob, target, filename) {
|
|
519
|
-
// NOTE: IE and MSEdge do not allow Blob resources as a source for
|
|
520
|
-
// tabs or iframes. msSaveOrOpenBlob is used as a workaround. I
|
|
521
|
-
// haven't been able to find a way to just open the Blob file in
|
|
522
|
-
// another tab yet for IE or MSEdge.
|
|
523
|
-
if (window.navigator.msSaveOrOpenBlob) {
|
|
524
|
-
window.navigator.msSaveOrOpenBlob(blob, filename);
|
|
525
|
-
}
|
|
526
|
-
else {
|
|
527
|
-
const url = URL.createObjectURL(blob);
|
|
528
|
-
const win = window.open(url, target);
|
|
529
|
-
// TODO: Consider if always setting opener to null is to restrictive
|
|
530
|
-
// if (win && target && target.toLowerCase() === '_blank') {
|
|
531
|
-
// win.opener = null
|
|
532
|
-
// }
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
919
|
function notNullOrUndefined(value) {
|
|
537
920
|
return value !== null && value !== undefined;
|
|
538
921
|
}
|
|
@@ -881,5 +1264,5 @@ function fractionalDigitsCount(value) {
|
|
|
881
1264
|
* Generated bundle index. Do not edit.
|
|
882
1265
|
*/
|
|
883
1266
|
|
|
884
|
-
export { PollingTickerOptions, Refreshable, activatedRoutesWithDataProperty, arrayMoveImmutable, arrayMoveMutable, calcPercentage, createPadding, deleteProperties, deleteProperty, fileBufferToBlob, fileBufferToObjectUrl, fileDataFromBuffer, fractionalDigitsCount, getAttribute, getClosestWidgetCdkDrag, getControlName, getControlPath, hasAttribute, hasProperty, hasRequiredControl, isAbsoluteUrl, isEmptyInputValue, isEmptyUrlRoute, isNullOrUndefined, isNumeric, leafChildRoute, loadStyle, loadStyleSheet, mapEach, notNullOrUndefined, observeControlIsDifferent, observeControlStatus, observeControlValid, observeControlValue, observeControlValueChange, observeQueryList, openBlob, padEnd, padStart, phoneNumberMask, pollingTicker, readFileAsDataUrlAsync, readFileAsync, routeSnapshotPathFull, routeSnapshotPathRelative, subscriberCount, tapFirst, toggleAttribute, waitOnConditionAsync, waitOnNonPendingStatus, willHaveDataProp, withoutProperties, withoutProperty, wrapIntoObservable, ɵ0 };
|
|
1267
|
+
export { IS_FEATURE_COLLECTION_VALIDATOR_NAME, IS_ONLY_GEOMETRY_TYPES_VALIDATOR_NAME, NO_INNER_RINGS_VALIDATOR_NAME, NO_KINKS_VALIDATOR_NAME, PollingTickerOptions, Refreshable, activatedRoutesWithDataProperty, arrayMoveImmutable, arrayMoveMutable, calcPercentage, coerceFeatureCollection, createPadding, deleteProperties, deleteProperty, fileBufferToBlob, fileBufferToObjectUrl, fileDataFromBuffer, fractionalDigitsCount, geoJsonToArea, getAttribute, getClosestWidgetCdkDrag, getControlName, getControlPath, hasAttribute, hasProperty, hasRequiredControl, isAbsoluteUrl, isEmptyInputValue, isEmptyUrlRoute, isFeatureCollectionValidator, isNullOrUndefined, isNumeric, isOnlyGeometryTypes, isOnlyGeometryTypesValidator, leafChildRoute, loadStyle, loadStyleSheet, mapEach, mergePolygons, noInnerRingsValidator, noKinksValidator, notNullOrUndefined, observeControlIsDifferent, observeControlStatus, observeControlValid, observeControlValue, observeControlValueChange, observeQueryList, openBlob, padEnd, padStart, phoneNumberMask, pollingTicker, readFileAsDataUrlAsync, readFileAsync, readGeoFile, routeSnapshotPathFull, routeSnapshotPathRelative, splitMultiPolygons, subscriberCount, tapFirst, toggleAttribute, waitOnConditionAsync, waitOnNonPendingStatus, willHaveDataProp, withoutProperties, withoutProperty, wrapIntoObservable, ɵ0 };
|
|
885
1268
|
//# sourceMappingURL=theseam-ui-common-utils.js.map
|