Commit 5e65f2a48a109b7359f29c8762fe419ee1b52d58
1 parent
5535c33d
trip-animation map provider & custom markers
Showing
15 changed files
with
630 additions
and
166 deletions
@@ -38,7 +38,8 @@ | @@ -38,7 +38,8 @@ | ||
38 | "src/app/shared/components/json-form/react/json-form.scss", | 38 | "src/app/shared/components/json-form/react/json-form.scss", |
39 | "node_modules/rc-select/assets/index.less", | 39 | "node_modules/rc-select/assets/index.less", |
40 | "node_modules/jstree-bootstrap-theme/dist/themes/proton/style.min.css", | 40 | "node_modules/jstree-bootstrap-theme/dist/themes/proton/style.min.css", |
41 | - "node_modules/leaflet/dist/leaflet.css" | 41 | + "node_modules/leaflet/dist/leaflet.css", |
42 | + "src/app/modules/home/components/widget/lib/maps/markers.scss" | ||
42 | ], | 43 | ], |
43 | "stylePreprocessorOptions": { | 44 | "stylePreprocessorOptions": { |
44 | "includePaths": [ | 45 | "includePaths": [ |
ui-ngx/src/app/core/schema-utils.ts
0 → 100644
1 | + | ||
2 | +export function initSchema() { | ||
3 | + return { | ||
4 | + schema: { | ||
5 | + type: "object", | ||
6 | + properties: {}, | ||
7 | + required: [] | ||
8 | + }, | ||
9 | + form: [], | ||
10 | + groupInfoes: [] | ||
11 | + }; | ||
12 | +} | ||
13 | + | ||
14 | +export function addGroupInfo(schema, title: string) { | ||
15 | + schema.groupInfoes.push({ | ||
16 | + "formIndex": schema.groupInfoes?.length || 0, | ||
17 | + "GroupTitle": title | ||
18 | + }); | ||
19 | +} | ||
20 | + | ||
21 | +export function addToSchema(schema, newSchema) { | ||
22 | + Object.assign(schema.schema.properties, newSchema.schema.properties); | ||
23 | + schema.schema.required = schema.schema.required.concat(newSchema.schema.required); | ||
24 | + schema.form.push(newSchema.form); | ||
25 | +} | ||
26 | + | ||
27 | +export function mergeSchemes(schemes: any[]) { | ||
28 | + return schemes.reduce((finalSchema, schema) => { | ||
29 | + return { | ||
30 | + schema: { | ||
31 | + properties: { | ||
32 | + ...finalSchema.schema.properties, | ||
33 | + ...schema.schema.properties | ||
34 | + }, | ||
35 | + required: [ | ||
36 | + ...finalSchema.schema.required, | ||
37 | + ...schema.schema.required | ||
38 | + ] | ||
39 | + }, | ||
40 | + form: [ | ||
41 | + ...finalSchema.form, | ||
42 | + ...schema.form | ||
43 | + ] | ||
44 | + } | ||
45 | + }, initSchema()); | ||
46 | +} | ||
47 | + | ||
48 | +export function addCondition(schema, condition: String) { | ||
49 | + schema.form = schema.form.map(element => { | ||
50 | + if (typeof element === 'string') { | ||
51 | + return { | ||
52 | + key: element, | ||
53 | + condition: condition | ||
54 | + } | ||
55 | + } | ||
56 | + if (typeof element == 'object') { | ||
57 | + if (element.condition) { | ||
58 | + element.condition += ' && ' + condition | ||
59 | + } | ||
60 | + else element.condition = condition; | ||
61 | + } | ||
62 | + return element; | ||
63 | + }); | ||
64 | + return schema; | ||
65 | +} |
@@ -452,54 +452,55 @@ export function aspectCache(imageUrl: string): Observable<number> { | @@ -452,54 +452,55 @@ export function aspectCache(imageUrl: string): Observable<number> { | ||
452 | export function parseArray(input: any[]): any[] { | 452 | export function parseArray(input: any[]): any[] { |
453 | let alliases: any = _(input).groupBy(el => el?.datasource?.aliasName).values().value(); | 453 | let alliases: any = _(input).groupBy(el => el?.datasource?.aliasName).values().value(); |
454 | return alliases.map((alliasArray, dsIndex) => | 454 | return alliases.map((alliasArray, dsIndex) => |
455 | - alliasArray[0].data.map((el, i) => { | ||
456 | - const obj = { | ||
457 | - aliasName: alliasArray[0]?.datasource?.aliasName, | ||
458 | - $datasource: alliasArray[0]?.datasource, | ||
459 | - dsIndex: dsIndex, | ||
460 | - time: el[0] | ||
461 | - }; | ||
462 | - alliasArray.forEach(el => { | ||
463 | - obj[el?.dataKey?.label] = el?.data[i][1]; | ||
464 | - obj[el?.dataKey?.label + '|ts'] = el?.data[0][0]; | ||
465 | - if (el?.dataKey?.label == 'type') { | ||
466 | - obj['deviceType'] = el?.data[0][1]; | ||
467 | - } | ||
468 | - }); | ||
469 | - return obj; | ||
470 | - }) | ||
471 | - ); | ||
472 | -} | ||
473 | - | ||
474 | -export function parseData(input: any[]): any[] { | ||
475 | - return _(input).groupBy(el => el?.datasource?.aliasName).values().value().map((alliasArray, i) => { | 455 | + alliasArray[0].data.map((el, i) => { |
476 | const obj = { | 456 | const obj = { |
477 | - aliasName: alliasArray[0]?.datasource?.aliasName, | ||
478 | - entityName: alliasArray[0]?.datasource?.entityName, | ||
479 | - $datasource: alliasArray[0]?.datasource, | ||
480 | - dsIndex: i | 457 | + aliasName: alliasArray[0]?.datasource?.aliasName, |
458 | + entityName: alliasArray[0]?.datasource?.entityName, | ||
459 | + $datasource: alliasArray[0]?.datasource, | ||
460 | + dsIndex: dsIndex, | ||
461 | + time: el[0] | ||
481 | }; | 462 | }; |
482 | alliasArray.forEach(el => { | 463 | alliasArray.forEach(el => { |
483 | - obj[el?.dataKey?.label] = el?.data[0][1]; | ||
484 | - obj[el?.dataKey?.label + '|ts'] = el?.data[0][0]; | ||
485 | - if (el?.dataKey?.label == 'type') { | ||
486 | - obj['deviceType'] = el?.data[0][1]; | ||
487 | - } | 464 | + obj[el?.dataKey?.label] = el?.data[i][1]; |
465 | + obj[el?.dataKey?.label + '|ts'] = el?.data[0][0]; | ||
466 | + if (el?.dataKey?.label == 'type') { | ||
467 | + obj['deviceType'] = el?.data[0][1]; | ||
468 | + } | ||
488 | }); | 469 | }); |
489 | return obj; | 470 | return obj; |
471 | + }) | ||
472 | + ); | ||
473 | +} | ||
474 | + | ||
475 | +export function parseData(input: any[]): any[] { | ||
476 | + return _(input).groupBy(el => el?.datasource?.aliasName).values().value().map((alliasArray, i) => { | ||
477 | + const obj = { | ||
478 | + aliasName: alliasArray[0]?.datasource?.aliasName, | ||
479 | + entityName: alliasArray[0]?.datasource?.entityName, | ||
480 | + $datasource: alliasArray[0]?.datasource, | ||
481 | + dsIndex: i | ||
482 | + }; | ||
483 | + alliasArray.forEach(el => { | ||
484 | + obj[el?.dataKey?.label] = el?.data[0][1]; | ||
485 | + obj[el?.dataKey?.label + '|ts'] = el?.data[0][0]; | ||
486 | + if (el?.dataKey?.label == 'type') { | ||
487 | + obj['deviceType'] = el?.data[0][1]; | ||
488 | + } | ||
489 | + }); | ||
490 | + return obj; | ||
490 | }); | 491 | }); |
491 | } | 492 | } |
492 | 493 | ||
493 | export function safeExecute(func: Function, params = []) { | 494 | export function safeExecute(func: Function, params = []) { |
494 | let res = null; | 495 | let res = null; |
495 | if (func && typeof (func) == "function") { | 496 | if (func && typeof (func) == "function") { |
496 | - try { | ||
497 | - res = func(...params); | ||
498 | - } | ||
499 | - catch (err) { | ||
500 | - console.error(err); | ||
501 | - res = null; | ||
502 | - } | 497 | + try { |
498 | + res = func(...params); | ||
499 | + } | ||
500 | + catch (err) { | ||
501 | + console.error(err); | ||
502 | + res = null; | ||
503 | + } | ||
503 | } | 504 | } |
504 | return res; | 505 | return res; |
505 | } | 506 | } |
@@ -507,13 +508,13 @@ export function safeExecute(func: Function, params = []) { | @@ -507,13 +508,13 @@ export function safeExecute(func: Function, params = []) { | ||
507 | export function parseFunction(source: string, params: string[] = []): Function { | 508 | export function parseFunction(source: string, params: string[] = []): Function { |
508 | let res = null; | 509 | let res = null; |
509 | if (source?.length) { | 510 | if (source?.length) { |
510 | - try { | ||
511 | - res = new Function(...params, source); | ||
512 | - } | ||
513 | - catch (err) { | ||
514 | - console.error(err); | ||
515 | - res = null; | ||
516 | - } | 511 | + try { |
512 | + res = new Function(...params, source); | ||
513 | + } | ||
514 | + catch (err) { | ||
515 | + console.error(err); | ||
516 | + res = null; | ||
517 | + } | ||
517 | } | 518 | } |
518 | return res; | 519 | return res; |
519 | } | 520 | } |
@@ -122,6 +122,11 @@ export default abstract class LeafletMap { | @@ -122,6 +122,11 @@ export default abstract class LeafletMap { | ||
122 | ////Markers | 122 | ////Markers |
123 | updateMarkers(markersData) { | 123 | updateMarkers(markersData) { |
124 | markersData.forEach(data => { | 124 | markersData.forEach(data => { |
125 | + if(data.rotationAngle){ | ||
126 | + this.options.icon= L.divIcon({ | ||
127 | + html: `<div class="arrow" style="transform: rotate(${data.rotationAngle}deg)"><div>` | ||
128 | + }) | ||
129 | + } | ||
125 | if (this.markers.get(data.aliasName)) { | 130 | if (this.markers.get(data.aliasName)) { |
126 | this.updateMarker(data.aliasName, data, markersData, this.options as MarkerSettings) | 131 | this.updateMarker(data.aliasName, data, markersData, this.options as MarkerSettings) |
127 | } | 132 | } |
@@ -18,6 +18,7 @@ export interface MapOptions { | @@ -18,6 +18,7 @@ export interface MapOptions { | ||
18 | useDefaultCenterPosition?: boolean, | 18 | useDefaultCenterPosition?: boolean, |
19 | gmDefaultMapType?: string, | 19 | gmDefaultMapType?: string, |
20 | useLabelFunction: string; | 20 | useLabelFunction: string; |
21 | + icon?: any; | ||
21 | } | 22 | } |
22 | 23 | ||
23 | export enum MapProviders { | 24 | export enum MapProviders { |
@@ -29,6 +30,7 @@ export enum MapProviders { | @@ -29,6 +30,7 @@ export enum MapProviders { | ||
29 | } | 30 | } |
30 | 31 | ||
31 | export interface MarkerSettings extends MapOptions { | 32 | export interface MarkerSettings extends MapOptions { |
33 | + icon?: any; | ||
32 | showLabel?: boolean, | 34 | showLabel?: boolean, |
33 | draggable?: boolean, | 35 | draggable?: boolean, |
34 | displayTooltip?: boolean, | 36 | displayTooltip?: boolean, |
@@ -8,7 +8,8 @@ export interface MapWidgetInterface { | @@ -8,7 +8,8 @@ export interface MapWidgetInterface { | ||
8 | } | 8 | } |
9 | 9 | ||
10 | export interface MapWidgetStaticInterface { | 10 | export interface MapWidgetStaticInterface { |
11 | - settingsSchema(mapProvider, drawRoutes): Object; | 11 | + settingsSchema(mapProvider?, drawRoutes?): Object; |
12 | + getProvidersSchema():Object | ||
12 | dataKeySettingsSchema(): Object; | 13 | dataKeySettingsSchema(): Object; |
13 | actionSources(): Object; | 14 | actionSources(): Object; |
14 | } | 15 | } |
@@ -15,6 +15,7 @@ import { | @@ -15,6 +15,7 @@ import { | ||
15 | import { MapWidgetStaticInterface, MapWidgetInterface } from './map-widget.interface'; | 15 | import { MapWidgetStaticInterface, MapWidgetInterface } from './map-widget.interface'; |
16 | import { OpenStreetMap, TencentMap, GoogleMap, HEREMap, ImageMap } from './providers'; | 16 | import { OpenStreetMap, TencentMap, GoogleMap, HEREMap, ImageMap } from './providers'; |
17 | import { parseFunction, parseArray, parseData } from '@app/core/utils'; | 17 | import { parseFunction, parseArray, parseData } from '@app/core/utils'; |
18 | +import { initSchema, addToSchema, mergeSchemes, addCondition, addGroupInfo } from '@app/core/schema-utils'; | ||
18 | 19 | ||
19 | export class MapWidgetController implements MapWidgetInterface { | 20 | export class MapWidgetController implements MapWidgetInterface { |
20 | 21 | ||
@@ -73,7 +74,7 @@ export class MapWidgetController implements MapWidgetInterface { | @@ -73,7 +74,7 @@ export class MapWidgetController implements MapWidgetInterface { | ||
73 | this.map.updateMarkers(parseData(this.data)); | 74 | this.map.updateMarkers(parseData(this.data)); |
74 | } | 75 | } |
75 | 76 | ||
76 | - public updateHistoryData(dataSources){ | 77 | + public updateHistoryData(dataSources) { |
77 | dataSources.map() | 78 | dataSources.map() |
78 | } | 79 | } |
79 | 80 | ||
@@ -93,90 +94,28 @@ export class MapWidgetController implements MapWidgetInterface { | @@ -93,90 +94,28 @@ export class MapWidgetController implements MapWidgetInterface { | ||
93 | return {}; | 94 | return {}; |
94 | } | 95 | } |
95 | 96 | ||
97 | + public static getProvidersSchema(){ | ||
98 | + return mergeSchemes([mapProviderSchema, | ||
99 | + ...Object.values(providerSets)?.map( | ||
100 | + setting => addCondition(setting?.schema, `model.provider === '${setting.name}'`))]) | ||
101 | + } | ||
102 | + | ||
96 | public static settingsSchema(mapProvider, drawRoutes): Object { | 103 | public static settingsSchema(mapProvider, drawRoutes): Object { |
97 | //const providerInfo = providerSets[mapProvider]; | 104 | //const providerInfo = providerSets[mapProvider]; |
98 | let schema = initSchema(); | 105 | let schema = initSchema(); |
106 | + addToSchema(schema,this.getProvidersSchema()); | ||
99 | 107 | ||
100 | - function initSchema() { | ||
101 | - return { | ||
102 | - schema: { | ||
103 | - type: "object", | ||
104 | - properties: {}, | ||
105 | - required: [] | ||
106 | - }, | ||
107 | - form: [], | ||
108 | - groupInfoes: [] | ||
109 | - }; | ||
110 | - } | ||
111 | - | ||
112 | - function addGroupInfo(title: string) { | ||
113 | - schema.groupInfoes.push({ | ||
114 | - "formIndex": schema.groupInfoes?.length || 0, | ||
115 | - "GroupTitle": title | ||
116 | - }); | ||
117 | - } | ||
118 | - | ||
119 | - function addToSchema(newSchema) { | ||
120 | - Object.assign(schema.schema.properties, newSchema.schema.properties); | ||
121 | - schema.schema.required = schema.schema.required.concat(newSchema.schema.required); | ||
122 | - schema.form.push(newSchema.form);//schema.form.concat(commonMapSettingsSchema.form); | ||
123 | - } | ||
124 | - | ||
125 | - function mergeSchemes(schemes: any[]) { | ||
126 | - return schemes.reduce((finalSchema, schema) => { | ||
127 | - return { | ||
128 | - schema: { | ||
129 | - properties: { | ||
130 | - ...finalSchema.schema.properties, | ||
131 | - ...schema.schema.properties | ||
132 | - }, | ||
133 | - required: [ | ||
134 | - ...finalSchema.schema.required, | ||
135 | - ...schema.schema.required | ||
136 | - ] | ||
137 | - }, | ||
138 | - form: [ | ||
139 | - ...finalSchema.form, | ||
140 | - ...schema.form | ||
141 | - ] | ||
142 | - } | ||
143 | - }, initSchema()); | ||
144 | - } | ||
145 | - | ||
146 | - function addCondition(schema, condition: String) { | ||
147 | - schema.form = schema.form.map(element => { | ||
148 | - if (typeof element === 'string') { | ||
149 | - return { | ||
150 | - key: element, | ||
151 | - condition: condition | ||
152 | - } | ||
153 | - } | ||
154 | - if (typeof element == 'object') { | ||
155 | - if (element.condition) { | ||
156 | - element.condition += ' && ' + condition | ||
157 | - } | ||
158 | - else element.condition = condition; | ||
159 | - } | ||
160 | - return element; | ||
161 | - }); | ||
162 | - return schema; | ||
163 | - } | ||
164 | - | ||
165 | - addToSchema(mergeSchemes([mapProviderSchema, | ||
166 | - ...Object.values(providerSets)?.map( | ||
167 | - setting => addCondition(setting?.schema, `model.provider === '${setting.name}'`))])); | ||
168 | - | ||
169 | - addGroupInfo("Map Provider Settings"); | ||
170 | - addToSchema(commonMapSettingsSchema); | ||
171 | - addGroupInfo("Common Map Settings"); | 108 | + addGroupInfo(schema, "Map Provider Settings"); |
109 | + addToSchema(schema, commonMapSettingsSchema); | ||
110 | + addGroupInfo(schema, "Common Map Settings"); | ||
172 | 111 | ||
173 | if (drawRoutes) { | 112 | if (drawRoutes) { |
174 | - addToSchema(routeMapSettingsSchema); | ||
175 | - addGroupInfo("Route Map Settings"); | 113 | + addToSchema(schema, routeMapSettingsSchema); |
114 | + addGroupInfo(schema, "Route Map Settings"); | ||
176 | } else if (mapProvider !== 'image-map') { | 115 | } else if (mapProvider !== 'image-map') { |
177 | let clusteringSchema = mergeSchemes([markerClusteringSettingsSchemaLeaflet, markerClusteringSettingsSchema]) | 116 | let clusteringSchema = mergeSchemes([markerClusteringSettingsSchemaLeaflet, markerClusteringSettingsSchema]) |
178 | - addToSchema(clusteringSchema); | ||
179 | - addGroupInfo("Markers Clustering Settings"); | 117 | + addToSchema(schema, clusteringSchema); |
118 | + addGroupInfo(schema, "Markers Clustering Settings"); | ||
180 | } | 119 | } |
181 | console.log(11, schema); | 120 | console.log(11, schema); |
182 | 121 | ||
@@ -243,7 +182,7 @@ const defaultSettings = { | @@ -243,7 +182,7 @@ const defaultSettings = { | ||
243 | latKeyName: 'latitude', | 182 | latKeyName: 'latitude', |
244 | lngKeyName: 'longitude', | 183 | lngKeyName: 'longitude', |
245 | polygonKeyName: 'coordinates', | 184 | polygonKeyName: 'coordinates', |
246 | - showLabel: true, | 185 | + showLabel: false, |
247 | label: "${entityName}", | 186 | label: "${entityName}", |
248 | showTooltip: false, | 187 | showTooltip: false, |
249 | useDefaultCenterPosition: false, | 188 | useDefaultCenterPosition: false, |
@@ -30,6 +30,12 @@ export function interpolateArray(originData, interpolatedIntervals) { | @@ -30,6 +30,12 @@ export function interpolateArray(originData, interpolatedIntervals) { | ||
30 | return (intermediateMoment - firsMoment) / (secondMoment - firsMoment); | 30 | return (intermediateMoment - firsMoment) / (secondMoment - firsMoment); |
31 | }; | 31 | }; |
32 | 32 | ||
33 | + function findAngle(startPoint, endPoint) { | ||
34 | + let angle = -Math.atan2(endPoint.latitude - startPoint.longitude, endPoint.longitude - startPoint.latitude); | ||
35 | + angle = angle * 180 / Math.PI; | ||
36 | + return parseInt(angle.toFixed(2)); | ||
37 | + } | ||
38 | + | ||
33 | const result = {}; | 39 | const result = {}; |
34 | 40 | ||
35 | for (let i = 1, j = 0; i < originData.length, j < interpolatedIntervals.length;) { | 41 | for (let i = 1, j = 0; i < originData.length, j < interpolatedIntervals.length;) { |
@@ -37,10 +43,16 @@ export function interpolateArray(originData, interpolatedIntervals) { | @@ -37,10 +43,16 @@ export function interpolateArray(originData, interpolatedIntervals) { | ||
37 | while (originData[i].time < currentTime) i++; | 43 | while (originData[i].time < currentTime) i++; |
38 | const before = originData[i - 1]; | 44 | const before = originData[i - 1]; |
39 | const after = originData[i]; | 45 | const after = originData[i]; |
40 | - result[currentTime] = (interpolateOnPointSegment( | 46 | + const interpolation = interpolateOnPointSegment( |
41 | new L.Point(before.latitude, before.longitude), | 47 | new L.Point(before.latitude, before.longitude), |
42 | new L.Point(after.latitude, after.longitude), | 48 | new L.Point(after.latitude, after.longitude), |
43 | - getRatio(before.time, after.time, currentTime))); | 49 | + getRatio(before.time, after.time, currentTime)); |
50 | + result[currentTime] = ({ | ||
51 | + ...originData[i], | ||
52 | + rotationAngle: findAngle(before, after), | ||
53 | + latitude: interpolation.x, | ||
54 | + longitude: interpolation.y | ||
55 | + }); | ||
44 | j++; | 56 | j++; |
45 | } | 57 | } |
46 | 58 |
1 | + | ||
2 | +.arrow{ | ||
3 | + background:#222; | ||
4 | + text-align:center; | ||
5 | + font-size:180%; | ||
6 | + margin:2em; | ||
7 | + font-family: Calibri, arial, sans-serif; | ||
8 | + color:white; | ||
9 | + padding-top:1.8em; | ||
10 | + display:inline-block;/* or block */ | ||
11 | + position:relative; | ||
12 | + border-color:white; | ||
13 | + text-decoration:none; | ||
14 | + transition:all .3s ease-out; | ||
15 | +} | ||
16 | +.arrow:before{ | ||
17 | + content:'▲'; | ||
18 | + font-size:.9em; | ||
19 | + position:absolute; | ||
20 | + top:0; | ||
21 | + left:50%; | ||
22 | + margin-left:-.7em; | ||
23 | + border:solid .13em white; | ||
24 | + border-radius:10em; | ||
25 | + width:1.4em; | ||
26 | + height:1.4em; | ||
27 | + line-height:1.3em; | ||
28 | + border-color:inherit; | ||
29 | + transition:transform .5s ease-in; | ||
30 | +} | ||
31 | +.arrow:hover{ | ||
32 | + color:pink; | ||
33 | + border-color:pink; | ||
34 | +} |
@@ -25,7 +25,7 @@ export class Marker { | @@ -25,7 +25,7 @@ export class Marker { | ||
25 | this.leafletMarker.setIcon(iconInfo.icon); | 25 | this.leafletMarker.setIcon(iconInfo.icon); |
26 | if (settings.showLabel) { | 26 | if (settings.showLabel) { |
27 | this.tooltipOffset = [0, -iconInfo.size[1] + 10]; | 27 | this.tooltipOffset = [0, -iconInfo.size[1] + 10]; |
28 | - this.updateMarkerLabel(settings) | 28 | + // this.updateMarkerLabel(settings) |
29 | } | 29 | } |
30 | 30 | ||
31 | this.leafletMarker.addTo(map) | 31 | this.leafletMarker.addTo(map) |
@@ -55,8 +55,6 @@ export class Marker { | @@ -55,8 +55,6 @@ export class Marker { | ||
55 | this.leafletMarker.setLatLng(position); | 55 | this.leafletMarker.setLatLng(position); |
56 | } | 56 | } |
57 | 57 | ||
58 | - | ||
59 | - | ||
60 | updateMarkerLabel(settings) { | 58 | updateMarkerLabel(settings) { |
61 | 59 | ||
62 | function getText(template, data) { | 60 | function getText(template, data) { |
@@ -74,7 +72,7 @@ export class Marker { | @@ -74,7 +72,7 @@ export class Marker { | ||
74 | return res; | 72 | return res; |
75 | } | 73 | } |
76 | 74 | ||
77 | - | 75 | + |
78 | this.leafletMarker.unbindTooltip(); | 76 | this.leafletMarker.unbindTooltip(); |
79 | if (settings.showLabel) { | 77 | if (settings.showLabel) { |
80 | if (settings.useLabelFunction) { | 78 | if (settings.useLabelFunction) { |
@@ -104,9 +102,20 @@ export class Marker { | @@ -104,9 +102,20 @@ export class Marker { | ||
104 | } | 102 | } |
105 | 103 | ||
106 | createMarkerIcon(onMarkerIconReady) { | 104 | createMarkerIcon(onMarkerIconReady) { |
107 | - const currentImage = this.settings.useMarkerImageFunction ? | ||
108 | - safeExecute(this.settings.markerImageFunction, [this.data, this.settings.markerImages, this.dataSources, this.data.dsIndex]) : this.settings.currentImage; | ||
109 | - // var opMap = this; | 105 | + |
106 | + if (this.settings.icon) { | ||
107 | + onMarkerIconReady({ | ||
108 | + size: [30,30], | ||
109 | + icon: this.settings.icon, | ||
110 | + }); | ||
111 | + return; | ||
112 | + } | ||
113 | + | ||
114 | + let currentImage = this.settings.useMarkerImageFunction ? | ||
115 | + safeExecute(this.settings.markerImageFunction, | ||
116 | + [this.data, this.settings.markerImages, this.dataSources, this.data.dsIndex]) : this.settings.currentImage; | ||
117 | + | ||
118 | + | ||
110 | if (currentImage && currentImage.url) { | 119 | if (currentImage && currentImage.url) { |
111 | aspectCache(currentImage.url).subscribe( | 120 | aspectCache(currentImage.url).subscribe( |
112 | (aspect) => { | 121 | (aspect) => { |
@@ -856,4 +856,373 @@ export const mapProviderSchema = | @@ -856,4 +856,373 @@ export const mapProviderSchema = | ||
856 | ] | 856 | ] |
857 | } | 857 | } |
858 | ] | 858 | ] |
859 | -}; | ||
859 | +}; | ||
860 | + | ||
861 | + | ||
862 | +export const tripAnimationSchema = { | ||
863 | + "schema": { | ||
864 | + "title": "Openstreet Map Configuration", | ||
865 | + "type": "object", | ||
866 | + "properties": { | ||
867 | + "normalizationStep": { | ||
868 | + "title": "Normalization data step (ms)", | ||
869 | + "type": "number", | ||
870 | + "default": 1000 | ||
871 | + }, | ||
872 | + "latKeyName": { | ||
873 | + "title": "Latitude key name", | ||
874 | + "type": "string", | ||
875 | + "default": "latitude" | ||
876 | + }, | ||
877 | + "lngKeyName": { | ||
878 | + "title": "Longitude key name", | ||
879 | + "type": "string", | ||
880 | + "default": "longitude" | ||
881 | + }, | ||
882 | + "polKeyName": { | ||
883 | + "title": "Polygon key name", | ||
884 | + "type": "string", | ||
885 | + "default": "coordinates" | ||
886 | + }, | ||
887 | + "showLabel": { | ||
888 | + "title": "Show label", | ||
889 | + "type": "boolean", | ||
890 | + "default": true | ||
891 | + }, | ||
892 | + "label": { | ||
893 | + "title": "Label (pattern examples: '${entityName}', '${entityName}: (Text ${keyName} units.)' )", | ||
894 | + "type": "string", | ||
895 | + "default": "${entityName}" | ||
896 | + }, | ||
897 | + "useLabelFunction": { | ||
898 | + "title": "Use label function", | ||
899 | + "type": "boolean", | ||
900 | + "default": false | ||
901 | + }, | ||
902 | + "labelFunction": { | ||
903 | + "title": "Label function: f(data, dsData, dsIndex)", | ||
904 | + "type": "string" | ||
905 | + }, | ||
906 | + "showTooltip": { | ||
907 | + "title": "Show tooltip", | ||
908 | + "type": "boolean", | ||
909 | + "default": true | ||
910 | + }, | ||
911 | + "tooltipColor": { | ||
912 | + "title": "Tooltip background color", | ||
913 | + "type": "string", | ||
914 | + "default": "#fff" | ||
915 | + }, | ||
916 | + "tooltipFontColor": { | ||
917 | + "title": "Tooltip font color", | ||
918 | + "type": "string", | ||
919 | + "default": "#000" | ||
920 | + }, | ||
921 | + "tooltipOpacity": { | ||
922 | + "title": "Tooltip opacity (0-1)", | ||
923 | + "type": "number", | ||
924 | + "default": 1 | ||
925 | + }, | ||
926 | + "tooltipPattern": { | ||
927 | + "title": "Tooltip (for ex. 'Text ${keyName} units.' or <link-act name='my-action'>Link text</link-act>')", | ||
928 | + "type": "string", | ||
929 | + "default": "<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}" | ||
930 | + }, | ||
931 | + "useTooltipFunction": { | ||
932 | + "title": "Use tooltip function", | ||
933 | + "type": "boolean", | ||
934 | + "default": false | ||
935 | + }, | ||
936 | + "tooltipFunction": { | ||
937 | + "title": "Tooltip function: f(data, dsData, dsIndex)", | ||
938 | + "type": "string" | ||
939 | + }, | ||
940 | + "color": { | ||
941 | + "title": "Path color", | ||
942 | + "type": "string" | ||
943 | + }, | ||
944 | + "strokeWeight": { | ||
945 | + "title": "Stroke weight", | ||
946 | + "type": "number", | ||
947 | + "default": 2 | ||
948 | + }, | ||
949 | + "strokeOpacity": { | ||
950 | + "title": "Stroke opacity", | ||
951 | + "type": "number", | ||
952 | + "default": 1 | ||
953 | + }, | ||
954 | + "useColorFunction": { | ||
955 | + "title": "Use path color function", | ||
956 | + "type": "boolean", | ||
957 | + "default": false | ||
958 | + }, | ||
959 | + "colorFunction": { | ||
960 | + "title": "Path color function: f(data, dsData, dsIndex)", | ||
961 | + "type": "string" | ||
962 | + }, | ||
963 | + "usePolylineDecorator": { | ||
964 | + "title": "Use path decorator", | ||
965 | + "type": "boolean", | ||
966 | + "default": false | ||
967 | + }, | ||
968 | + "decoratorSymbol": { | ||
969 | + "title": "Decorator symbol", | ||
970 | + "type": "string", | ||
971 | + "default": "arrowHead" | ||
972 | + }, | ||
973 | + "decoratorSymbolSize": { | ||
974 | + "title": "Decorator symbol size (px)", | ||
975 | + "type": "number", | ||
976 | + "default": 10 | ||
977 | + }, | ||
978 | + "useDecoratorCustomColor": { | ||
979 | + "title": "Use path decorator custom color", | ||
980 | + "type": "boolean", | ||
981 | + "default": false | ||
982 | + }, | ||
983 | + "decoratorCustomColor": { | ||
984 | + "title": "Decorator custom color", | ||
985 | + "type": "string", | ||
986 | + "default": "#000" | ||
987 | + }, | ||
988 | + "decoratorOffset": { | ||
989 | + "title": "Decorator offset", | ||
990 | + "type": "string", | ||
991 | + "default": "20px" | ||
992 | + }, | ||
993 | + "endDecoratorOffset": { | ||
994 | + "title": "End decorator offset", | ||
995 | + "type": "string", | ||
996 | + "default": "20px" | ||
997 | + }, | ||
998 | + "decoratorRepeat": { | ||
999 | + "title": "Decorator repeat", | ||
1000 | + "type": "string", | ||
1001 | + "default": "20px" | ||
1002 | + }, | ||
1003 | + "showPolygon": { | ||
1004 | + "title": "Show polygon", | ||
1005 | + "type": "boolean", | ||
1006 | + "default": false | ||
1007 | + }, | ||
1008 | + "polygonTooltipPattern": { | ||
1009 | + "title": "Tooltip (for ex. 'Text ${keyName} units.' or <link-act name='my-action'>Link text</link-act>')", | ||
1010 | + "type": "string", | ||
1011 | + "default": "<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}" | ||
1012 | + }, | ||
1013 | + "usePolygonTooltipFunction": { | ||
1014 | + "title": "Use polygon tooltip function", | ||
1015 | + "type": "boolean", | ||
1016 | + "default": false | ||
1017 | + }, | ||
1018 | + "polygonTooltipFunction": { | ||
1019 | + "title": "Polygon tooltip function: f(data, dsData, dsIndex)", | ||
1020 | + "type": "string" | ||
1021 | + }, | ||
1022 | + "polygonColor": { | ||
1023 | + "title": "Polygon color", | ||
1024 | + "type": "string" | ||
1025 | + }, | ||
1026 | + "polygonOpacity": { | ||
1027 | + "title": "Polygon opacity", | ||
1028 | + "type": "number", | ||
1029 | + "default": 0.5 | ||
1030 | + }, | ||
1031 | + "polygonStrokeColor": { | ||
1032 | + "title": "Polygon border color", | ||
1033 | + "type": "string" | ||
1034 | + }, | ||
1035 | + "polygonStrokeOpacity": { | ||
1036 | + "title": "Polygon border opacity", | ||
1037 | + "type": "number", | ||
1038 | + "default": 1 | ||
1039 | + }, | ||
1040 | + "polygonStrokeWeight": { | ||
1041 | + "title": "Polygon border weight", | ||
1042 | + "type": "number", | ||
1043 | + "default": 1 | ||
1044 | + }, | ||
1045 | + "usePolygonColorFunction": { | ||
1046 | + "title": "Use polygon color function", | ||
1047 | + "type": "boolean", | ||
1048 | + "default": false | ||
1049 | + }, | ||
1050 | + "polygonColorFunction": { | ||
1051 | + "title": "Polygon Color function: f(data, dsData, dsIndex)", | ||
1052 | + "type": "string" | ||
1053 | + }, | ||
1054 | + "showPoints": { | ||
1055 | + "title": "Show points", | ||
1056 | + "type": "boolean", | ||
1057 | + "default": false | ||
1058 | + }, | ||
1059 | + "pointColor": { | ||
1060 | + "title": "Point color", | ||
1061 | + "type": "string" | ||
1062 | + }, | ||
1063 | + "pointSize": { | ||
1064 | + "title": "Point size (px)", | ||
1065 | + "type": "number", | ||
1066 | + "default": 10 | ||
1067 | + }, | ||
1068 | + "usePointAsAnchor": { | ||
1069 | + "title": "Use point as anchor", | ||
1070 | + "type": "boolean", | ||
1071 | + "default": false | ||
1072 | + }, | ||
1073 | + "pointAsAnchorFunction": { | ||
1074 | + "title": "Point as anchor function: f(data, dsData, dsIndex)", | ||
1075 | + "type": "string" | ||
1076 | + }, | ||
1077 | + "pointTooltipOnRightPanel": { | ||
1078 | + "title": "Independant point tooltip", | ||
1079 | + "type": "boolean", | ||
1080 | + "default": true | ||
1081 | + }, | ||
1082 | + "autocloseTooltip": { | ||
1083 | + "title": "Auto-close point popup", | ||
1084 | + "type": "boolean", | ||
1085 | + "default": true | ||
1086 | + }, | ||
1087 | + "markerImage": { | ||
1088 | + "title": "Custom marker image", | ||
1089 | + "type": "string" | ||
1090 | + }, | ||
1091 | + "markerImageSize": { | ||
1092 | + "title": "Custom marker image size (px)", | ||
1093 | + "type": "number", | ||
1094 | + "default": 34 | ||
1095 | + }, | ||
1096 | + "rotationAngle": { | ||
1097 | + "title": "Set additional rotation angle for marker (deg)", | ||
1098 | + "type": "number", | ||
1099 | + "default": 180 | ||
1100 | + }, | ||
1101 | + "useMarkerImageFunction": { | ||
1102 | + "title": "Use marker image function", | ||
1103 | + "type": "boolean", | ||
1104 | + "default": false | ||
1105 | + }, | ||
1106 | + "markerImageFunction": { | ||
1107 | + "title": "Marker image function: f(data, images, dsData, dsIndex)", | ||
1108 | + "type": "string" | ||
1109 | + }, | ||
1110 | + "markerImages": { | ||
1111 | + "title": "Marker images", | ||
1112 | + "type": "array", | ||
1113 | + "items": { | ||
1114 | + "title": "Marker image", | ||
1115 | + "type": "string" | ||
1116 | + } | ||
1117 | + } | ||
1118 | + }, | ||
1119 | + "required": [] | ||
1120 | + }, | ||
1121 | + "form": [{ | ||
1122 | + "key": "mapProvider", | ||
1123 | + "type": "rc-select", | ||
1124 | + "multiple": false, | ||
1125 | + "items": [{ | ||
1126 | + "value": "OpenStreetMap.Mapnik", | ||
1127 | + "label": "OpenStreetMap.Mapnik (Default)" | ||
1128 | + }, { | ||
1129 | + "value": "OpenStreetMap.BlackAndWhite", | ||
1130 | + "label": "OpenStreetMap.BlackAndWhite" | ||
1131 | + }, { | ||
1132 | + "value": "OpenStreetMap.HOT", | ||
1133 | + "label": "OpenStreetMap.HOT" | ||
1134 | + }, { | ||
1135 | + "value": "Esri.WorldStreetMap", | ||
1136 | + "label": "Esri.WorldStreetMap" | ||
1137 | + }, { | ||
1138 | + "value": "Esri.WorldTopoMap", | ||
1139 | + "label": "Esri.WorldTopoMap" | ||
1140 | + }, { | ||
1141 | + "value": "CartoDB.Positron", | ||
1142 | + "label": "CartoDB.Positron" | ||
1143 | + }, { | ||
1144 | + "value": "CartoDB.DarkMatter", | ||
1145 | + "label": "CartoDB.DarkMatter" | ||
1146 | + }] | ||
1147 | + }, "normalizationStep", "latKeyName", "lngKeyName", "polKeyName", "showLabel", "label", "useLabelFunction", { | ||
1148 | + "key": "labelFunction", | ||
1149 | + "type": "javascript" | ||
1150 | + }, "showTooltip", { | ||
1151 | + "key": "tooltipColor", | ||
1152 | + "type": "color" | ||
1153 | + }, { | ||
1154 | + "key": "tooltipFontColor", | ||
1155 | + "type": "color" | ||
1156 | + }, "tooltipOpacity", { | ||
1157 | + "key": "tooltipPattern", | ||
1158 | + "type": "textarea" | ||
1159 | + }, "useTooltipFunction", { | ||
1160 | + "key": "tooltipFunction", | ||
1161 | + "type": "javascript" | ||
1162 | + }, { | ||
1163 | + "key": "color", | ||
1164 | + "type": "color" | ||
1165 | + }, "useColorFunction", { | ||
1166 | + "key": "colorFunction", | ||
1167 | + "type": "javascript" | ||
1168 | + }, "usePolylineDecorator", { | ||
1169 | + "key": "decoratorSymbol", | ||
1170 | + "type": "rc-select", | ||
1171 | + "multiple": false, | ||
1172 | + "items": [{ | ||
1173 | + "value": "arrowHead", | ||
1174 | + "label": "Arrow" | ||
1175 | + }, { | ||
1176 | + "value": "dash", | ||
1177 | + "label": "Dash" | ||
1178 | + }] | ||
1179 | + }, "decoratorSymbolSize", "useDecoratorCustomColor", { | ||
1180 | + "key": "decoratorCustomColor", | ||
1181 | + "type": "color" | ||
1182 | + }, { | ||
1183 | + "key": "decoratorOffset", | ||
1184 | + "type": "textarea" | ||
1185 | + }, { | ||
1186 | + "key": "endDecoratorOffset", | ||
1187 | + "type": "textarea" | ||
1188 | + }, { | ||
1189 | + "key": "decoratorRepeat", | ||
1190 | + "type": "textarea" | ||
1191 | + }, "strokeWeight", "strokeOpacity", "showPolygon", { | ||
1192 | + "key": "polygonTooltipPattern", | ||
1193 | + "type": "textarea" | ||
1194 | + }, "usePolygonTooltipFunction", { | ||
1195 | + "key": "polygonTooltipFunction", | ||
1196 | + "type": "javascript" | ||
1197 | + }, { | ||
1198 | + "key": "polygonColor", | ||
1199 | + "type": "color" | ||
1200 | + }, "polygonOpacity", { | ||
1201 | + "key": "polygonStrokeColor", | ||
1202 | + "type": "color" | ||
1203 | + }, "polygonStrokeOpacity", "polygonStrokeWeight", "usePolygonColorFunction", { | ||
1204 | + "key": "polygonColorFunction", | ||
1205 | + "type": "javascript" | ||
1206 | + }, "showPoints", { | ||
1207 | + "key": "pointColor", | ||
1208 | + "type": "color" | ||
1209 | + }, "pointSize", "usePointAsAnchor", { | ||
1210 | + "key": "pointAsAnchorFunction", | ||
1211 | + "type": "javascript" | ||
1212 | + }, "pointTooltipOnRightPanel", "autocloseTooltip", { | ||
1213 | + "key": "markerImage", | ||
1214 | + "type": "image" | ||
1215 | + }, "markerImageSize", "rotationAngle", "useMarkerImageFunction", | ||
1216 | + { | ||
1217 | + "key": "markerImageFunction", | ||
1218 | + "type": "javascript" | ||
1219 | + }, { | ||
1220 | + "key": "markerImages", | ||
1221 | + "items": [ | ||
1222 | + { | ||
1223 | + "key": "markerImages[]", | ||
1224 | + "type": "image" | ||
1225 | + } | ||
1226 | + ] | ||
1227 | + }] | ||
1228 | +} |
1 | <div class="map" #map ></div> | 1 | <div class="map" #map ></div> |
2 | -<div>{{historicalData?.lenth}}</div> | ||
3 | -<tb-history-selector *ngIf="historicalData" [settings]="ctx.settings" [intervals]="intervals" | 2 | +<tb-history-selector *ngIf="historicalData" [settings]="settings" [intervals]="intervals" |
4 | (onTimeUpdated)="timeUpdated($event)"></tb-history-selector> | 3 | (onTimeUpdated)="timeUpdated($event)"></tb-history-selector> |
1 | import { Component, OnInit, Input, ViewChild, AfterViewInit, ChangeDetectorRef } from '@angular/core'; | 1 | import { Component, OnInit, Input, ViewChild, AfterViewInit, ChangeDetectorRef } from '@angular/core'; |
2 | -import { MapWidgetController } from '../lib/maps/map-widget2'; | 2 | +import { MapWidgetController, TbMapWidgetV2 } from '../lib/maps/map-widget2'; |
3 | import { MapProviders } from '../lib/maps/map-models'; | 3 | import { MapProviders } from '../lib/maps/map-models'; |
4 | import { parseArray } from '@app/core/utils'; | 4 | import { parseArray } from '@app/core/utils'; |
5 | import { interpolateArray } from '../lib/maps/maps-utils'; | 5 | import { interpolateArray } from '../lib/maps/maps-utils'; |
6 | +import tinycolor from "tinycolor2"; | ||
7 | +import { initSchema, addToSchema, addGroupInfo } from '@app/core/schema-utils'; | ||
8 | +import { tripAnimationSchema } from '../lib/maps/schemes'; | ||
9 | +import L from 'leaflet'; | ||
6 | 10 | ||
7 | @Component({ | 11 | @Component({ |
8 | selector: 'trip-animation', | 12 | selector: 'trip-animation', |
@@ -18,35 +22,45 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { | @@ -18,35 +22,45 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { | ||
18 | mapWidget: MapWidgetController; | 22 | mapWidget: MapWidgetController; |
19 | historicalData; | 23 | historicalData; |
20 | intervals; | 24 | intervals; |
21 | - normalizationStep = 500; | 25 | + normalizationStep = 1000; |
22 | interpolatedData = []; | 26 | interpolatedData = []; |
23 | - | 27 | + widgetConfig; |
28 | + settings; | ||
24 | 29 | ||
25 | constructor(private cd: ChangeDetectorRef) { } | 30 | constructor(private cd: ChangeDetectorRef) { } |
26 | 31 | ||
27 | ngOnInit(): void { | 32 | ngOnInit(): void { |
33 | + this.widgetConfig = this.ctx.widgetConfig; | ||
34 | + const settings = { | ||
35 | + normalizationStep: 1000, | ||
36 | + buttonColor: tinycolor(this.widgetConfig.color).setAlpha(0.54).toRgbString(), | ||
37 | + disabledButtonColor: tinycolor(this.widgetConfig.color).setAlpha(0.3).toRgbString(), | ||
38 | + rotationAngle: 0 | ||
39 | + } | ||
40 | + this.settings = { ...settings, ...this.ctx.settings }; | ||
41 | + //this.ctx.settings = settings; | ||
42 | + console.log("TripAnimationComponent -> ngOnInit -> this.ctx.settings", this.ctx.settings) | ||
28 | let subscription = this.ctx.subscriptions[Object.keys(this.ctx.subscriptions)[0]]; | 43 | let subscription = this.ctx.subscriptions[Object.keys(this.ctx.subscriptions)[0]]; |
29 | if (subscription) subscription.callbacks.onDataUpdated = (updated) => { | 44 | if (subscription) subscription.callbacks.onDataUpdated = (updated) => { |
30 | this.historicalData = parseArray(this.ctx.data); | 45 | this.historicalData = parseArray(this.ctx.data); |
31 | - this.historicalData.forEach(el => { | ||
32 | - console.log("TripAnimationComponent -> if -> el", el) | 46 | + this.historicalData.forEach(ds => ds.forEach(el => { |
33 | el.longitude += (Math.random() - 0.5) | 47 | el.longitude += (Math.random() - 0.5) |
34 | el.latitude += (Math.random() - 0.5) | 48 | el.latitude += (Math.random() - 0.5) |
35 | - }); | 49 | + })); |
36 | this.calculateIntervals(); | 50 | this.calculateIntervals(); |
51 | + this.timeUpdated(this.intervals[0]); | ||
37 | this.cd.detectChanges(); | 52 | this.cd.detectChanges(); |
53 | + this.mapWidget.map.map.invalidateSize(); | ||
38 | } | 54 | } |
39 | } | 55 | } |
40 | 56 | ||
41 | ngAfterViewInit() { | 57 | ngAfterViewInit() { |
42 | this.mapWidget = new MapWidgetController(MapProviders.openstreet, false, this.ctx, this.mapContainer.nativeElement); | 58 | this.mapWidget = new MapWidgetController(MapProviders.openstreet, false, this.ctx, this.mapContainer.nativeElement); |
43 | - this.mapWidget.data | ||
44 | } | 59 | } |
45 | 60 | ||
46 | timeUpdated(time) { | 61 | timeUpdated(time) { |
47 | - //this.mapWidget.ma | ||
48 | - const currentPosition = this.interpolatedData.map(dataSource=>dataSource[time]); | ||
49 | - console.log("TripAnimationComponent -> timeUpdated -> currentPosition", currentPosition) | 62 | + const currentPosition = this.interpolatedData.map(dataSource => dataSource[time]); |
63 | + this.mapWidget.map.updateMarkers(currentPosition); | ||
50 | } | 64 | } |
51 | 65 | ||
52 | calculateIntervals() { | 66 | calculateIntervals() { |
@@ -57,9 +71,17 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { | @@ -57,9 +71,17 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { | ||
57 | } | 71 | } |
58 | this.intervals.push(dataSource[dataSource.length - 1]?.time); | 72 | this.intervals.push(dataSource[dataSource.length - 1]?.time); |
59 | this.interpolatedData[index] = interpolateArray(dataSource, this.intervals); | 73 | this.interpolatedData[index] = interpolateArray(dataSource, this.intervals); |
60 | - console.log("TripAnimationComponent -> calculateIntervals -> this.intervals", this.intervals) | ||
61 | - | ||
62 | }); | 74 | }); |
63 | } | 75 | } |
64 | 76 | ||
77 | + static getSettingsSchema() { | ||
78 | + let schema = initSchema(); | ||
79 | + addToSchema(schema, TbMapWidgetV2.getProvidersSchema()); | ||
80 | + addGroupInfo(schema, "Map Provider Settings"); | ||
81 | + addToSchema(schema, tripAnimationSchema); | ||
82 | + addGroupInfo(schema, "Trip Animation Settings"); | ||
83 | + return schema; | ||
84 | + } | ||
65 | } | 85 | } |
86 | + | ||
87 | +export let TbTripAnimationWidget = TripAnimationComponent; |
1 | import { Component, OnInit, OnChanges, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core'; | 1 | import { Component, OnInit, OnChanges, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core'; |
2 | -import { interval } from 'rxjs'; | 2 | +import { interval, Subscription } from 'rxjs'; |
3 | import { filter, tap } from 'rxjs/operators'; | 3 | import { filter, tap } from 'rxjs/operators'; |
4 | 4 | ||
5 | @Component({ | 5 | @Component({ |
@@ -34,23 +34,25 @@ export class HistorySelectorComponent implements OnInit, OnChanges { | @@ -34,23 +34,25 @@ export class HistorySelectorComponent implements OnInit, OnChanges { | ||
34 | 34 | ||
35 | play() { | 35 | play() { |
36 | this.playing = true; | 36 | this.playing = true; |
37 | - this.interval = interval(1000 / this.speed) | ||
38 | - .pipe( | ||
39 | - filter(() => this.playing), | ||
40 | - tap(() => this.index++)).subscribe(() => { | ||
41 | - if (this.index < this.maxTimeIndex) { | ||
42 | - this.cd.detectChanges(); | ||
43 | - this.onTimeUpdated.emit(this.intervals[this.index]); | ||
44 | - } | ||
45 | - else { | ||
46 | - this.interval.complete(); | ||
47 | - } | ||
48 | - }, err => { | ||
49 | - console.log(err); | ||
50 | - }, () => { | ||
51 | - this.index = this.minTimeIndex; | ||
52 | - this.playing = false; | ||
53 | - }) | 37 | + if (!this.interval) |
38 | + this.interval = interval(1000 / this.speed) | ||
39 | + .pipe( | ||
40 | + filter(() => this.playing), | ||
41 | + tap(() => this.index++)).subscribe(() => { | ||
42 | + if (this.index < this.maxTimeIndex) { | ||
43 | + this.cd.detectChanges(); | ||
44 | + this.onTimeUpdated.emit(this.intervals[this.index]); | ||
45 | + } | ||
46 | + else { | ||
47 | + this.interval.complete(); | ||
48 | + } | ||
49 | + }, err => { | ||
50 | + console.log(err); | ||
51 | + }, () => { | ||
52 | + this.index = this.minTimeIndex; | ||
53 | + this.playing = false; | ||
54 | + this.interval = null; | ||
55 | + }); | ||
54 | } | 56 | } |
55 | 57 | ||
56 | pause() { | 58 | pause() { |
@@ -93,6 +93,7 @@ import { TbAnalogueRadialGauge } from '@home/components/widget/lib/analogue-radi | @@ -93,6 +93,7 @@ import { TbAnalogueRadialGauge } from '@home/components/widget/lib/analogue-radi | ||
93 | import { TbAnalogueLinearGauge } from '@home/components/widget/lib/analogue-linear-gauge'; | 93 | import { TbAnalogueLinearGauge } from '@home/components/widget/lib/analogue-linear-gauge'; |
94 | import { TbCanvasDigitalGauge } from '@home/components/widget/lib/digital-gauge'; | 94 | import { TbCanvasDigitalGauge } from '@home/components/widget/lib/digital-gauge'; |
95 | import { TbMapWidgetV2 } from '@home/components/widget/lib/maps/map-widget2'; | 95 | import { TbMapWidgetV2 } from '@home/components/widget/lib/maps/map-widget2'; |
96 | +import { TbTripAnimationWidget } from '@app/modules/home/components/widget/trip-animation/trip-animation.component'; | ||
96 | 97 | ||
97 | import * as tinycolor_ from 'tinycolor2'; | 98 | import * as tinycolor_ from 'tinycolor2'; |
98 | 99 | ||
@@ -106,3 +107,5 @@ const tinycolor = tinycolor_; | @@ -106,3 +107,5 @@ const tinycolor = tinycolor_; | ||
106 | (window as any).TbAnalogueLinearGauge = TbAnalogueLinearGauge; | 107 | (window as any).TbAnalogueLinearGauge = TbAnalogueLinearGauge; |
107 | (window as any).TbCanvasDigitalGauge = TbCanvasDigitalGauge; | 108 | (window as any).TbCanvasDigitalGauge = TbCanvasDigitalGauge; |
108 | (window as any).TbMapWidgetV2 = TbMapWidgetV2; | 109 | (window as any).TbMapWidgetV2 = TbMapWidgetV2; |
110 | +(window as any).TbTripAnimationWidget = TbTripAnimationWidget; | ||
111 | +console.log("TbTripAnimationWidget", TbTripAnimationWidget) |