Commit 5535c33d0eabd9e0b3c10e8094c584126e5f8b1d
1 parent
b9db41bd
WIP on history control and route interpolation
Showing
10 changed files
with
378 additions
and
131 deletions
... | ... | @@ -1900,7 +1900,8 @@ |
1900 | 1900 | "@types/lodash": { |
1901 | 1901 | "version": "4.14.149", |
1902 | 1902 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz", |
1903 | - "integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==" | |
1903 | + "integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==", | |
1904 | + "dev": true | |
1904 | 1905 | }, |
1905 | 1906 | "@types/minimatch": { |
1906 | 1907 | "version": "3.0.3", |
... | ... | @@ -8263,6 +8264,14 @@ |
8263 | 8264 | "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.6.0.tgz", |
8264 | 8265 | "integrity": "sha512-CPkhyqWUKZKFJ6K8umN5/D2wrJ2+/8UIpXppY7QDnUZW5bZL5+SEI2J7GBpwh4LIupOKqbNSQXgqmrEJopHVNQ==" |
8265 | 8266 | }, |
8267 | + "leaflet-geometryutil": { | |
8268 | + "version": "0.9.3", | |
8269 | + "resolved": "https://registry.npmjs.org/leaflet-geometryutil/-/leaflet-geometryutil-0.9.3.tgz", | |
8270 | + "integrity": "sha512-Wi6YvfNx/Xu9q35AEfXpsUXmIFLen/MO+C2qimxHRnjyeyOxBhdcZa6kSiReaOX0cGK7yQInqrzz0dkIqZ8Dpg==", | |
8271 | + "requires": { | |
8272 | + "leaflet": "1.6.0" | |
8273 | + } | |
8274 | + }, | |
8266 | 8275 | "leaflet-providers": { |
8267 | 8276 | "version": "1.9.1", |
8268 | 8277 | "resolved": "https://registry.npmjs.org/leaflet-providers/-/leaflet-providers-1.9.1.tgz", | ... | ... |
... | ... | @@ -451,13 +451,13 @@ export function aspectCache(imageUrl: string): Observable<number> { |
451 | 451 | |
452 | 452 | export function parseArray(input: any[]): any[] { |
453 | 453 | let alliases: any = _(input).groupBy(el => el?.datasource?.aliasName).values().value(); |
454 | - console.log("alliases", alliases) | |
455 | 454 | return alliases.map((alliasArray, dsIndex) => |
456 | 455 | alliasArray[0].data.map((el, i) => { |
457 | 456 | const obj = { |
458 | 457 | aliasName: alliasArray[0]?.datasource?.aliasName, |
459 | 458 | $datasource: alliasArray[0]?.datasource, |
460 | - dsIndex: dsIndex | |
459 | + dsIndex: dsIndex, | |
460 | + time: el[0] | |
461 | 461 | }; |
462 | 462 | alliasArray.forEach(el => { |
463 | 463 | obj[el?.dataKey?.label] = el?.data[i][1]; | ... | ... |
1 | 1 | import L from 'leaflet'; |
2 | +import { interpolateOnPointSegment } from 'leaflet-geometryutil'; | |
2 | 3 | import _ from 'lodash'; |
3 | 4 | |
4 | 5 | export function createTooltip(target, settings, targetArgs?) { |
5 | - var popup = L.popup(); | |
6 | + const popup = L.popup(); | |
6 | 7 | popup.setContent(''); |
7 | 8 | target.bindPopup(popup, { autoClose: settings.autocloseTooltip, closeOnClick: false }); |
8 | 9 | if (settings.displayTooltipAction == 'hover') { |
... | ... | @@ -21,3 +22,27 @@ export function createTooltip(target, settings, targetArgs?) { |
21 | 22 | dsIndex: settings.dsIndex |
22 | 23 | }; |
23 | 24 | } |
25 | + | |
26 | + | |
27 | +export function interpolateArray(originData, interpolatedIntervals) { | |
28 | + | |
29 | + const getRatio = (firsMoment, secondMoment, intermediateMoment) => { | |
30 | + return (intermediateMoment - firsMoment) / (secondMoment - firsMoment); | |
31 | + }; | |
32 | + | |
33 | + const result = {}; | |
34 | + | |
35 | + for (let i = 1, j = 0; i < originData.length, j < interpolatedIntervals.length;) { | |
36 | + const currentTime = interpolatedIntervals[j]; | |
37 | + while (originData[i].time < currentTime) i++; | |
38 | + const before = originData[i - 1]; | |
39 | + const after = originData[i]; | |
40 | + result[currentTime] = (interpolateOnPointSegment( | |
41 | + new L.Point(before.latitude, before.longitude), | |
42 | + new L.Point(after.latitude, after.longitude), | |
43 | + getRatio(before.time, after.time, currentTime))); | |
44 | + j++; | |
45 | + } | |
46 | + | |
47 | + return result; | |
48 | +}; | ... | ... |
1 | 1 | <div class="map" #map ></div> |
2 | -<tb-history-selector [settings]="ctx.settings"></tb-history-selector> | |
\ No newline at end of file | ||
2 | +<div>{{historicalData?.lenth}}</div> | |
3 | +<tb-history-selector *ngIf="historicalData" [settings]="ctx.settings" [intervals]="intervals" | |
4 | + (onTimeUpdated)="timeUpdated($event)"></tb-history-selector> | ... | ... |
1 | -import { Component, OnInit, Input, ViewChild, AfterViewInit } from '@angular/core'; | |
1 | +import { Component, OnInit, Input, ViewChild, AfterViewInit, ChangeDetectorRef } from '@angular/core'; | |
2 | 2 | import { MapWidgetController } from '../lib/maps/map-widget2'; |
3 | 3 | import { MapProviders } from '../lib/maps/map-models'; |
4 | 4 | import { parseArray } from '@app/core/utils'; |
5 | +import { interpolateArray } from '../lib/maps/maps-utils'; | |
5 | 6 | |
6 | 7 | @Component({ |
7 | 8 | selector: 'trip-animation', |
... | ... | @@ -15,18 +16,50 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { |
15 | 16 | @ViewChild('map') mapContainer; |
16 | 17 | |
17 | 18 | mapWidget: MapWidgetController; |
18 | - historicalData | |
19 | + historicalData; | |
20 | + intervals; | |
21 | + normalizationStep = 500; | |
22 | + interpolatedData = []; | |
19 | 23 | |
20 | - constructor() { } | |
24 | + | |
25 | + constructor(private cd: ChangeDetectorRef) { } | |
21 | 26 | |
22 | 27 | ngOnInit(): void { |
23 | - console.log(this.ctx); | |
24 | - this.historicalData = parseArray(this.ctx.data); | |
25 | - console.log("TripAnimationComponent -> ngOnInit -> this.historicalData",this.ctx.data, this.historicalData) | |
28 | + let subscription = this.ctx.subscriptions[Object.keys(this.ctx.subscriptions)[0]]; | |
29 | + if (subscription) subscription.callbacks.onDataUpdated = (updated) => { | |
30 | + this.historicalData = parseArray(this.ctx.data); | |
31 | + this.historicalData.forEach(el => { | |
32 | + console.log("TripAnimationComponent -> if -> el", el) | |
33 | + el.longitude += (Math.random() - 0.5) | |
34 | + el.latitude += (Math.random() - 0.5) | |
35 | + }); | |
36 | + this.calculateIntervals(); | |
37 | + this.cd.detectChanges(); | |
38 | + } | |
26 | 39 | } |
27 | 40 | |
28 | 41 | ngAfterViewInit() { |
29 | 42 | this.mapWidget = new MapWidgetController(MapProviders.openstreet, false, this.ctx, this.mapContainer.nativeElement); |
30 | 43 | this.mapWidget.data |
31 | 44 | } |
45 | + | |
46 | + timeUpdated(time) { | |
47 | + //this.mapWidget.ma | |
48 | + const currentPosition = this.interpolatedData.map(dataSource=>dataSource[time]); | |
49 | + console.log("TripAnimationComponent -> timeUpdated -> currentPosition", currentPosition) | |
50 | + } | |
51 | + | |
52 | + calculateIntervals() { | |
53 | + this.historicalData.forEach((dataSource, index) => { | |
54 | + this.intervals = []; | |
55 | + for (let time = dataSource[0]?.time; time < dataSource[dataSource.length - 1]?.time; time += this.normalizationStep) { | |
56 | + this.intervals.push(time); | |
57 | + } | |
58 | + this.intervals.push(dataSource[dataSource.length - 1]?.time); | |
59 | + this.interpolatedData[index] = interpolateArray(dataSource, this.intervals); | |
60 | + console.log("TripAnimationComponent -> calculateIntervals -> this.intervals", this.intervals) | |
61 | + | |
62 | + }); | |
63 | + } | |
64 | + | |
32 | 65 | } | ... | ... |
... | ... | @@ -6,34 +6,41 @@ |
6 | 6 | <button mat-icon-button class="mat-icon-button" aria-label="Previous" ng-click="movePrev()"> |
7 | 7 | <mat-icon class="material-icons" ng-style="{'color': staticSettings.buttonColor}">skip_previous</mat-icon> |
8 | 8 | </button> |
9 | - <!-- <mat-slider ng-model="index" [min]="minTimeIndex" [max]="maxTimeIndex" (change)="recalculateTrips()"> | |
10 | - </mat-slider>--> | |
9 | + <mat-slider [(ngModel)]="index" [min]="minTimeIndex" [max]="maxTimeIndex" (change)="recalculateTrips()"> | |
10 | + </mat-slider> | |
11 | 11 | <button mat-icon-button class="mat-icon-button" aria-label="Next" ng-click="moveNext()"> |
12 | 12 | <mat-icon class="material-icons" ng-style="{'color': staticSettings.buttonColor}">skip_next</mat-icon> |
13 | 13 | </button> |
14 | 14 | <button mat-icon-button class="mat-icon-button" aria-label="End" ng-click="moveEnd()"> |
15 | 15 | <mat-icon class="material-icons" ng-style="{'color': staticSettings.buttonColor}">fast_forward</mat-icon> |
16 | 16 | </button> |
17 | - <button mat-icon-button class="mat-icon-button" aria-label="Play" ng-click="playMove(true)" | |
18 | - ng-disabled="isPlaying"> | |
19 | - <mat-icon class="material-icons" | |
20 | - ng-style="{'color': isPlaying ? staticSettings.disabledButtonColor : staticSettings.buttonColor}"> | |
17 | + <!--<div class="play-pause"> | |
18 | + <input type="checkbox" [(ngModel)]="play" value="" id="playPauseCheckbox" name="playPauseCheckbox" /> | |
19 | + <label for="playPauseCheckbox"></label> | |
20 | + </div>--> | |
21 | + <button mat-icon-button class="mat-icon-button" aria-label="Play" > | |
22 | + <mat-icon (click)="play()" *ngIf="!playing" class="material-icons" ng-style="{'color': settings.buttonColor}"> | |
21 | 23 | play_circle_outline |
22 | 24 | </mat-icon> |
25 | + <mat-icon (click)="pause()" *ngIf="playing" class="material-icons" ng-style="{'color': settings.buttonColor}"> | |
26 | + pause_circle_outline | |
27 | + </mat-icon> | |
23 | 28 | </button> |
24 | - <!-- <mat-select ng-model="speed" aria-label="Speed selector"> | |
29 | + <!-- <mat-select [(ngModel)]="speed" aria-label="Speed selector"> | |
25 | 30 | <mat-option ng-value="speed" flex="1" ng-repeat="speed in speeds track by $index">{{ speed}} |
26 | 31 | </mat-option> |
27 | 32 | </mat-select>--> |
28 | - <button mat-icon-button class="mat-icon-button" aria-label="Stop playing" ng-click="stopPlay()" | |
33 | + <!-- <button mat-icon-button class="mat-icon-button" aria-label="Stop playing" ng-click="stopPlay()" | |
29 | 34 | ng-disabled="!isPlaying"> |
30 | 35 | <mat-icon class="material-icons" |
31 | 36 | ng-style="{'color': isPlaying ? staticSettings.buttonColor : staticSettings.disabledButtonColor}"> |
32 | 37 | pause_circle_outline |
33 | 38 | </mat-icon> |
34 | - </button> | |
39 | + </button>--> | |
35 | 40 | </div> |
36 | 41 | <div class="panel-timer"> |
37 | 42 | <span *ngIf="animationTime">{{ animationTime | date:'medium'}}</span> |
38 | 43 | <span *ngIf="!animationTime">{{ "widget.no-data-found" | translate}}</span> |
39 | - </div> | |
\ No newline at end of file | ||
44 | + </div> | |
45 | + | |
46 | + <div>{{index}}</div> | |
\ No newline at end of file | ... | ... |
... | ... | @@ -13,125 +13,152 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | - .trip-animation-widget { | |
16 | +.trip-animation-widget { | |
17 | + position: relative; | |
18 | + width: 100%; | |
19 | + height: 100%; | |
20 | + font-size: 16px; | |
21 | + line-height: 24px; | |
17 | 22 | |
23 | + .trip-animation-label-container { | |
24 | + height: 24px; | |
25 | + } | |
26 | + | |
27 | + .trip-animation-container { | |
18 | 28 | position: relative; |
29 | + z-index: 1; | |
30 | + flex: 1; | |
19 | 31 | width: 100%; |
20 | - height: 100%; | |
21 | - font-size: 16px; | |
22 | - line-height: 24px; | |
23 | - | |
24 | - .trip-animation-label-container { | |
25 | - height: 24px; | |
26 | - } | |
27 | - | |
28 | - .trip-animation-container { | |
29 | - position: relative; | |
32 | + | |
33 | + #trip-animation-map { | |
30 | 34 | z-index: 1; |
31 | - flex: 1; | |
32 | 35 | width: 100%; |
33 | - | |
34 | - #trip-animation-map { | |
35 | - z-index: 1; | |
36 | - width: 100%; | |
37 | - height: 100%; | |
38 | - | |
39 | - .pointsLayerMarkerIcon { | |
40 | - border-radius: 50%; | |
41 | - } | |
36 | + height: 100%; | |
37 | + | |
38 | + .pointsLayerMarkerIcon { | |
39 | + border-radius: 50%; | |
42 | 40 | } |
43 | - | |
44 | - .trip-animation-info-panel { | |
45 | - position: absolute; | |
41 | + } | |
42 | + | |
43 | + .trip-animation-info-panel { | |
44 | + position: absolute; | |
45 | + top: 0; | |
46 | + right: 0; | |
47 | + z-index: 2; | |
48 | + pointer-events: none; | |
49 | + | |
50 | + .md-button { | |
46 | 51 | top: 0; |
47 | - right: 0; | |
48 | - z-index: 2; | |
49 | - pointer-events: none; | |
50 | - | |
51 | - .md-button { | |
52 | - top: 0; | |
53 | - left: 0; | |
54 | - width: 32px; | |
55 | - min-width: 32px; | |
56 | - height: 32px; | |
57 | - min-height: 32px; | |
58 | - padding: 0 0 2px; | |
59 | - margin: 2px; | |
60 | - line-height: 24px; | |
61 | - | |
62 | - ng-md-icon { | |
63 | - width: 24px; | |
64 | - height: 24px; | |
65 | - | |
66 | - svg { | |
67 | - width: inherit; | |
68 | - height: inherit; | |
69 | - } | |
52 | + left: 0; | |
53 | + width: 32px; | |
54 | + min-width: 32px; | |
55 | + height: 32px; | |
56 | + min-height: 32px; | |
57 | + padding: 0 0 2px; | |
58 | + margin: 2px; | |
59 | + line-height: 24px; | |
60 | + | |
61 | + ng-md-icon { | |
62 | + width: 24px; | |
63 | + height: 24px; | |
64 | + | |
65 | + svg { | |
66 | + width: inherit; | |
67 | + height: inherit; | |
70 | 68 | } |
71 | 69 | } |
72 | 70 | } |
73 | - | |
74 | - .trip-animation-tooltip { | |
75 | - position: absolute; | |
76 | - top: 38px; | |
77 | - right: 0; | |
78 | - z-index: 2; | |
79 | - padding: 10px; | |
80 | - background-color: #fff; | |
81 | - transition: .3s ease-in-out; | |
82 | - | |
83 | - &-hidden { | |
84 | - transform: translateX(110%); | |
85 | - } | |
71 | + } | |
72 | + | |
73 | + .trip-animation-tooltip { | |
74 | + position: absolute; | |
75 | + top: 38px; | |
76 | + right: 0; | |
77 | + z-index: 2; | |
78 | + padding: 10px; | |
79 | + background-color: #fff; | |
80 | + transition: 0.3s ease-in-out; | |
81 | + | |
82 | + &-hidden { | |
83 | + transform: translateX(110%); | |
86 | 84 | } |
87 | 85 | } |
88 | - | |
89 | - .trip-animation-control-panel { | |
90 | - position: relative; | |
91 | - box-sizing: border-box; | |
92 | - width: 100%; | |
93 | - padding-bottom: 16px; | |
94 | - padding-left: 10px; | |
95 | - | |
96 | - md-slider-container { | |
97 | - md-slider { | |
98 | - min-width: 80px; | |
99 | - } | |
100 | - | |
101 | - button.md-button.md-icon-button { | |
102 | - width: 44px; | |
103 | - min-width: 44px; | |
104 | - height: 44px; | |
105 | - min-height: 44px; | |
106 | - margin: 0; | |
107 | - line-height: 28px; | |
108 | - | |
109 | - md-icon { | |
110 | - width: 28px; | |
111 | - height: 28px; | |
112 | - font-size: 28px; | |
113 | - | |
114 | - svg { | |
115 | - width: inherit; | |
116 | - height: inherit; | |
117 | - } | |
86 | + } | |
87 | + | |
88 | + .trip-animation-control-panel { | |
89 | + position: relative; | |
90 | + box-sizing: border-box; | |
91 | + width: 100%; | |
92 | + padding-bottom: 16px; | |
93 | + padding-left: 10px; | |
94 | + | |
95 | + md-slider-container { | |
96 | + md-slider { | |
97 | + min-width: 80px; | |
98 | + } | |
99 | + | |
100 | + button.md-button.md-icon-button { | |
101 | + width: 44px; | |
102 | + min-width: 44px; | |
103 | + height: 44px; | |
104 | + min-height: 44px; | |
105 | + margin: 0; | |
106 | + line-height: 28px; | |
107 | + | |
108 | + md-icon { | |
109 | + width: 28px; | |
110 | + height: 28px; | |
111 | + font-size: 28px; | |
112 | + | |
113 | + svg { | |
114 | + width: inherit; | |
115 | + height: inherit; | |
118 | 116 | } |
119 | 117 | } |
120 | - | |
121 | - md-select { | |
122 | - margin: 0; | |
123 | - } | |
124 | 118 | } |
125 | - | |
126 | - .panel-timer { | |
127 | - max-width: none; | |
128 | - padding-right: 250px; | |
129 | - padding-left: 90px; | |
130 | - margin-top: -20px; | |
131 | - font-size: 12px; | |
132 | - font-weight: 500; | |
133 | - text-align: center; | |
119 | + | |
120 | + md-select { | |
121 | + margin: 0; | |
134 | 122 | } |
135 | 123 | } |
124 | + | |
125 | + .panel-timer { | |
126 | + max-width: none; | |
127 | + padding-right: 250px; | |
128 | + padding-left: 90px; | |
129 | + margin-top: -20px; | |
130 | + font-size: 12px; | |
131 | + font-weight: 500; | |
132 | + text-align: center; | |
133 | + } | |
134 | + } | |
135 | +} | |
136 | + | |
137 | +.playpause { | |
138 | + label { | |
139 | + display: block; | |
140 | + box-sizing: border-box; | |
141 | + | |
142 | + width: 0; | |
143 | + height: 74px; | |
144 | + | |
145 | + cursor: pointer; | |
146 | + | |
147 | + border-color: transparent transparent transparent #202020; | |
148 | + transition: 100ms all ease; | |
149 | + will-change: border-width; | |
150 | + | |
151 | + // paused state | |
152 | + border-style: double; | |
153 | + border-width: 0px 0 0px 60px; | |
154 | + } | |
155 | + input[type="checkbox"] { | |
156 | + visibility: hidden; | |
157 | + | |
158 | + &:checked + label { | |
159 | + // play state | |
160 | + border-style: solid; | |
161 | + border-width: 37px 0 37px 60px; | |
162 | + } | |
136 | 163 | } |
137 | - | |
\ No newline at end of file | ||
164 | +} | ... | ... |
1 | -import { Component, OnInit, Input } from '@angular/core'; | |
1 | +import { Component, OnInit, OnChanges, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core'; | |
2 | +import { interval } from 'rxjs'; | |
3 | +import { filter, tap } from 'rxjs/operators'; | |
2 | 4 | |
3 | 5 | @Component({ |
4 | 6 | selector: 'tb-history-selector', |
5 | 7 | templateUrl: './history-selector.component.html', |
6 | 8 | styleUrls: ['./history-selector.component.scss'] |
7 | 9 | }) |
8 | -export class HistorySelectorComponent implements OnInit { | |
10 | +export class HistorySelectorComponent implements OnInit, OnChanges { | |
9 | 11 | |
10 | 12 | @Input() settings |
13 | + @Input() intervals = []; | |
11 | 14 | |
12 | - animationTime | |
15 | + @Output() onTimeUpdated = new EventEmitter(); | |
13 | 16 | |
17 | + animationTime; | |
18 | + minTimeIndex = 0; | |
19 | + maxTimeIndex = 0; | |
20 | + speed = 1; | |
21 | + index = 0; | |
22 | + playing = false; | |
23 | + interval; | |
14 | 24 | |
15 | - constructor() { } | |
25 | + | |
26 | + constructor(private cd: ChangeDetectorRef) { } | |
16 | 27 | |
17 | 28 | ngOnInit(): void { |
18 | - console.log(this.settings); | |
19 | - | |
29 | + } | |
30 | + | |
31 | + ngOnChanges() { | |
32 | + this.maxTimeIndex = this.intervals?.length - 1; | |
33 | + } | |
34 | + | |
35 | + play() { | |
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 | + }) | |
54 | + } | |
55 | + | |
56 | + pause() { | |
57 | + this.playing = false; | |
58 | + } | |
59 | + /* | |
60 | + setSpeed() { | |
61 | + if (this.interval) this.interval.unsubscribe(); | |
62 | + this.interval = interval(1000 / this.speed) | |
63 | + .pipe( | |
64 | + takeWhile(() => this.index < this.maxTimeIndex), | |
65 | + filter(() => this.play), | |
66 | + tap(() => this.index++)) | |
67 | + .subscribe(() => { | |
68 | + console.log(this.intervals); | |
69 | + | |
70 | + this.onTimeUpdated.emit(this.intervals[this.index]); | |
71 | + | |
72 | + }, err => { | |
73 | + console.log(err); | |
74 | + }, () => { | |
75 | + this.index = this.minTimeIndex; | |
76 | + this.play = false; | |
77 | + }) | |
78 | + }*/ | |
79 | + | |
80 | + | |
81 | + | |
82 | + | |
83 | + /* | |
84 | + | |
85 | + playMove(play) { | |
86 | + if (play && this.isPlaying) return; | |
87 | + if (play || this.isPlaying) this.isPlaying = true; | |
88 | + if (this.isPlaying) { | |
89 | + moveInc(1); | |
90 | + this.timeout = $timeout(function () { | |
91 | + this.playMove(); | |
92 | + }, 1000 / this.speed) | |
93 | + } | |
94 | + }; | |
95 | + | |
96 | + moveNext() { | |
97 | + this.stopPlay(); | |
98 | + if (this.staticSettings.usePointAsAnchor) { | |
99 | + let newIndex = this.maxTimeIndex; | |
100 | + for (let index = this.index + 1; index < this.maxTimeIndex; index++) { | |
101 | + if (this.trips.some(function (trip) { | |
102 | + return calculateCurrentDate(trip.timeRange, index).hasAnchor; | |
103 | + })) { | |
104 | + newIndex = index; | |
105 | + break; | |
106 | + } | |
107 | + } | |
108 | + this.moveToIndex(newIndex); | |
109 | + } else moveInc(1); | |
110 | + }; | |
111 | + | |
112 | + movePrev() { | |
113 | + this.stopPlay(); | |
114 | + if (this.staticSettings.usePointAsAnchor) { | |
115 | + let newIndex = this.minTimeIndex; | |
116 | + for (let index = this.index - 1; index > this.minTimeIndex; index--) { | |
117 | + if (this.trips.some(function (trip) { | |
118 | + return calculateCurrentDate(trip.timeRange, index).hasAnchor; | |
119 | + })) { | |
120 | + newIndex = index; | |
121 | + break; | |
122 | + } | |
123 | + } | |
124 | + this.moveToIndex(newIndex); | |
125 | + } else moveInc(-1); | |
126 | + }; | |
127 | + | |
128 | + moveStart = function () { | |
129 | + this.stopPlay(); | |
130 | + this.moveToIndex(this.minTimeIndex); | |
131 | + }; | |
132 | + | |
133 | + moveEnd = function () { | |
134 | + this.stopPlay(); | |
135 | + this.moveToIndex(this.maxTimeIndex); | |
136 | + }; | |
137 | + | |
138 | + stopPlay = function () { | |
139 | + if (this.isPlaying) { | |
140 | + this.isPlaying = false; | |
141 | + $timeout.cancel(this.timeout); | |
142 | + } | |
143 | + }; | |
144 | + | |
145 | + moveInc(inc) { | |
146 | + let newIndex = this.index + inc; | |
147 | + this.moveToIndex(newIndex); | |
148 | + } | |
149 | + | |
150 | + moveToIndex(newIndex) { | |
151 | + if (newIndex > this.maxTimeIndex || newIndex < this.minTimeIndex) return; | |
152 | + this.index = newIndex; | |
153 | + this.animationTime = this.minTime + this.index * this.staticSettings.normalizationStep; | |
154 | + recalculateTrips(); | |
155 | + } | |
156 | + */ | |
157 | + recalculateTrips() { | |
158 | + | |
20 | 159 | } |
21 | 160 | |
22 | 161 | } | ... | ... |