1 import { Slider
} from './slider.js';
2 import { utcToLocal
, createElement
, setURL
, IS_MOBILE
} from '../util.js';
3 import { controllerEvents
, controllers
} from './Controller.js';
4 import { simVars
} from '../simVars.js';
7 * 1. Initialization block
8 * 1.a BoundingDateInitialization block
15 export class SimulationSlider
extends Slider
{
16 /** ===== Initialization block ===== */
18 let width
= IS_MOBILE
? 300 : 340;
19 super(width
, simVars
.sortedTimestamps
.length
- 1);
20 this.progressWidth
= 0;
21 this.progressCheck
= 0;
25 super.connectedCallback();
26 this.initializeSlider();
28 this.subscibeToCurrentDomain();
29 controllers
.currentTimestamp
.subscribe(() => this.updateSliderToCurrentTimestamp());
30 this.subsribeToLoadingProgress();
32 this.initializeStartSetter();
33 this.initializeEndSetter();
37 const slider
= this.querySelector('#slider');
38 const sliderBar
= this.querySelector('#slider-bar');
39 const sliderHead
= this.querySelector('#slider-head');
41 slider
.classList
.add('simulation-slider');
42 sliderBar
.classList
.add('simulation-slider');
43 this.createProgressBar();
45 sliderHead
.onpointerdown
= (e
) => {
46 const finishedCallback
= () => setURL();
47 this.dragSliderHead(e
, this.frame
, this.setTimestamp
, finishedCallback
);
49 const clickBarCallback
= (newTimestamp
) => {
50 this.setTimestamp(newTimestamp
);
53 sliderBar
.onclick
= (e
) => {
54 this.clickBar(e
, clickBarCallback
);
58 subscibeToCurrentDomain() {
59 // assumes that all necessary controllers are set and all I need to do is update my UI.
60 controllers
.currentDomain
.subscribe(() => {
61 this.nFrames
= simVars
.sortedTimestamps
.length
- 1;
62 this.updateStartLocation();
63 this.updateEndLocation();
64 this.updateSliderToCurrentTimestamp();
65 this.updateProgressWidth();
66 }, controllerEvents
.ALL
);
69 subsribeToLoadingProgress() {
70 controllers
.loadingProgress
.subscribe(() => {
71 let progress
= controllers
.loadingProgress
.value
;
73 if (progress
>= this.progressCheck
) {
74 this.progressCheck
= Math
.floor((this.progressCheck
+ .01)*100)/100;
75 this.setLoadProgress(progress
);
78 this.progressCheck
= 0;
79 this.setLoadProgress(progress
);
85 const slider
= this.querySelector('#slider');
86 const sliderStart
= createElement('slider-start', 'slider-marker');
87 const sliderEnd
= createElement('slider-end', 'slider-marker');
88 const sliderProgress
= createElement('slider-progress', 'slider-bar hidden');
89 const sliderMarkerInfo
= createElement('slider-marker-info');
91 slider
.append(sliderProgress
, sliderStart
, sliderEnd
, sliderMarkerInfo
);
94 /** ===== BoundingDateInitialization block ===== */
95 initializeStartSetter() {
96 const sliderStart
= this.querySelector('#slider-start');
97 const updateCallback
= (timeIndex
) => {
98 let endDate
= controllers
.endDate
.getValue();
99 const dateComparator
= (newTimestamp
) => newTimestamp
>= endDate
;
100 let boundingIndex
= simVars
.sortedTimestamps
.indexOf(endDate
) - 1;
101 this.boundingDateDragUpdate(timeIndex
, controllers
.startDate
, dateComparator
, boundingIndex
);
103 const finishedCallback
= () => {
104 this.boundingDateDragComplete(controllers
.startDate
);
107 this.setBoundingDateMouseOver(controllers
.startDate
, sliderStart
);
108 this.setBoundingDateMouseOut(sliderStart
);
109 this.setBoundingDatePointerDown(controllers
.startDate
, sliderStart
, updateCallback
, finishedCallback
);
111 controllers
.startDate
.subscribe(() => {
112 this.updateStartLocation();
113 this.updateProgressWidth();
114 }, controllerEvents
.ALL
);
117 initializeEndSetter() {
118 const sliderEnd
= this.querySelector('#slider-end');
119 const updateCallback
= (timeIndex
) => {
120 let startDate
= controllers
.startDate
.getValue();
121 const dateComparator
= (newTimestamp
) => newTimestamp
< startDate
;
122 let boundingIndex
= simVars
.sortedTimestamps
.indexOf(startDate
) + 1;
123 this.boundingDateDragUpdate(timeIndex
, controllers
.endDate
, dateComparator
, boundingIndex
);
125 const finishedCallback
= () => {
126 this.boundingDateDragComplete(controllers
.endDate
);
129 this.setBoundingDateMouseOver(controllers
.endDate
, sliderEnd
);
130 this.setBoundingDateMouseOut(sliderEnd
);
131 this.setBoundingDatePointerDown(controllers
.endDate
, sliderEnd
, updateCallback
, finishedCallback
);
133 controllers
.endDate
.subscribe(() => {
134 this.updateEndLocation();
135 this.updateProgressWidth();
136 }, controllerEvents
.ALL
);
139 setBoundingDateMouseOver(boundingDateController
, sliderMarker
) {
140 const sliderMarkerInfo
= this.querySelector('#slider-marker-info');
141 sliderMarker
.onmouseover
= () => {
142 let boundingDate
= boundingDateController
.getValue();
144 this.setSliderMarkerInfo(boundingDate
);
145 sliderMarkerInfo
.classList
.add('hovered');
149 setBoundingDateMouseOut(sliderMarker
) {
150 const sliderMarkerInfo
= this.querySelector('#slider-marker-info');
151 sliderMarker
.onmouseout
= () => {
152 sliderMarkerInfo
.classList
.remove('hovered');
156 setBoundingDatePointerDown(boundingDateController
, sliderMarker
, updateCallback
, finishedCallback
) {
157 const sliderMarkerInfo
= this.querySelector('#slider-marker-info');
159 sliderMarker
.onpointerdown
= (e
) => {
160 sliderMarkerInfo
.classList
.add('clicked');
161 let boundingDate
= boundingDateController
.getValue();
162 let originalFrame
= simVars
.sortedTimestamps
.indexOf(boundingDate
);
164 this.setSliderMarkerInfo(boundingDate
);
165 this.setLoadProgress(0);
166 this.dragSliderHead(e
, originalFrame
, updateCallback
, finishedCallback
);
170 boundingDateDragUpdate(timeIndex
, updatingController
, dateComparator
, boundingIndex
) {
171 let newTimestamp
= simVars
.sortedTimestamps
[timeIndex
];
172 if (dateComparator(newTimestamp
)) {
173 newTimestamp
= simVars
.sortedTimestamps
[boundingIndex
];
176 updatingController
.setValue(newTimestamp
, controllerEvents
.SLIDING_VALUE
);
177 this.setSliderMarkerInfo(newTimestamp
);
180 boundingDateDragComplete(dateController
) {
181 const sliderMarkerInfo
= this.querySelector('#slider-marker-info');
183 sliderMarkerInfo
.classList
.remove('clicked');
184 dateController
.broadcastEvent(controllerEvents
.VALUE_SET
);
188 /** ===== Getter block ===== */
190 let startDate
= controllers
.startDate
.getValue();
191 let left
= this.getLeftOfDate(startDate
);
196 let endDate
= controllers
.endDate
.value
;
197 let left
= this.getLeftOfDate(endDate
);
201 getLeftOfDate(date
) {
202 let index
= simVars
.sortedTimestamps
.indexOf(date
);
203 let left
= Math
.floor((index
/ (simVars
.sortedTimestamps
.length
- 1)) * this.sliderWidth
* .95);
208 /** ===== Setter block ===== */
209 setTimestamp(timeIndex
) {
210 let newTimestamp
= simVars
.sortedTimestamps
[timeIndex
];
211 let endDate
= controllers
.endDate
.getValue();
212 let startDate
= controllers
.startDate
.getValue();
214 if (newTimestamp
> endDate
) {
215 newTimestamp
= endDate
;
216 } else if (newTimestamp
< startDate
) {
217 newTimestamp
= startDate
;
220 controllers
.currentTimestamp
.setValue(newTimestamp
);
223 setLoadProgress(progress
) {
224 let progressWidth
= progress
*this.progressWidth
+ 2;
226 const progressBar
= this.querySelector('#slider-progress');
227 progressBar
.classList
.remove('hidden');
228 progressBar
.style
.width
= progressWidth
+ 'px';
230 progressBar
.classList
.add('hidden');
234 let startDate
= controllers
.startDate
.getValue();
235 let startIndex
= simVars
.sortedTimestamps
.indexOf(startDate
);
236 let left
= Math
.floor((startIndex
/ (simVars
.sortedTimestamps
.length
- 1)) * this.sliderWidth
* .95);
238 progressBar
.style
.left
= left
+ 'px';
241 setSliderMarkerInfo(timeStamp
) {
242 const sliderMarkerInfo
= this.querySelector('#slider-marker-info');
243 let localTime
= utcToLocal(timeStamp
);
244 sliderMarkerInfo
.innerHTML
= localTime
;
247 /** ===== Update block ===== */
248 updateProgressWidth() {
249 let startLeft
= this.getStartLeft();
250 let endLeft
= this.getEndLeft();
251 let totalWidth
= endLeft
- (startLeft
+ 4);
252 this.progressWidth
= totalWidth
;
255 updateStartLocation() {
256 const sliderStart
= this.querySelector('#slider-start');
257 let left
= this.getStartLeft();
259 sliderStart
.style
.left
= left
+ 'px';
262 updateSliderToCurrentTimestamp() {
263 let currentTimestamp
= controllers
.currentTimestamp
.getValue();
264 let newFrame
= simVars
.sortedTimestamps
.indexOf(currentTimestamp
);
265 this.updateHeadPosition(newFrame
);
268 updateEndLocation() {
269 const sliderEnd
= this.querySelector('#slider-end');
270 let left
= this.getEndLeft();
272 sliderEnd
.style
.left
= left
+ 'px';
275 /** ===== Util block ===== */
277 let nextFrame
= (this.frame
+ 1) % (this.nFrames
+ 1);
278 let startDate
= controllers
.startDate
.getValue();
279 let endDate
= controllers
.endDate
.getValue();
281 let nextTimestamp
= simVars
.sortedTimestamps
[nextFrame
];
282 if (nextTimestamp
> endDate
|| nextFrame
== 0) {
283 nextTimestamp
= startDate
;
286 return nextTimestamp
;
290 let prevFrame
= (this.frame
- 1) % (this.nFrames
+ 1);
291 let startDate
= controllers
.startDate
.getValue();
292 let endDate
= controllers
.endDate
.getValue();
295 prevFrame
= this.nFrames
;
298 let prevTimestamp
= simVars
.sortedTimestamps
[prevFrame
];
299 if (prevTimestamp
< startDate
|| prevTimestamp
> endDate
) {
300 prevTimestamp
= endDate
;
303 return prevTimestamp
;
307 window
.customElements
.define('simulation-slider', SimulationSlider
);