Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 1774c06d

Přidáno uživatelem Tomáš Ballák před téměř 4 roky(ů)

done

Zobrazit rozdíly:

website/public/js/zcu-heatmap.js
11 11

  
12 12
var dataSourceRoute
13 13
let positionsSourceRoute
14
var currentTime
14

  
15
let currentTime
16

  
17
let currentDate
15 18

  
16 19
var timer
17 20
var isAnimationRunning = false
......
23 26
const datasetDictNameDisplayName = {}
24 27
var datasetSelected = []
25 28

  
29
// data only for one day
30
let lockedDay = false
31

  
32
let loading = 0
33

  
34
// marks for all datasets
35
const dataSourceMarks = {}
36

  
26 37
const globalMarkersHolder = {}
27 38
// all marker from which popup was removed
28 39
// contains: {key:[L.circle,L.pupup]}
29 40
// key: x and y, x + '' + y string
30 41
let globalMarkersChanged = {}
31 42

  
43
const loadingY = () => {
44
  loading++
45
}
46
const loadingN = () => {
47
  loading--
48
}
49

  
50
const changeCurrentTime = (time = null) => {
51
  if (time !== null) {
52
    currentTime = time
53
  } else {
54
    $('#dropdown-time input[type="radio"]:checked').each(function () {
55
      currentTime = parseInt($(this).val())
56
    })
57
  }
58
}
59

  
60
const changeCurrentDate = (date = null) => {
61
  if (date) {
62
    currentDate = new Date(date)
63
  } else {
64
    currentDate = new Date($('#date').val())
65
  }
66
  $('#player-date span').html(`${currentDate.getDate()}. ${currentDate.getMonth() + 1}. ${currentDate.getFullYear()}`)
67
  $('#date').val(currentDateToString())
68
  data = []
69
}
70
const currentDayToString = () => {
71
  const day = currentDate.getDate()
72
  return day > 9 ? `${day}` : `0${day}`
73
}
74
const currentMonthToString = () => {
75
  const month = currentDate.getMonth() + 1
76
  return month > 9 ? `${month}` : `0${month}`
77
}
78
const currentDateToString = () => `${currentDate.getFullYear()}-${currentMonthToString()}-${currentDayToString()}`
79
const addDayToCurrentDate = (day) => {
80
  currentDate.setDate(currentDate.getDate() + day)
81
  changeCurrentDate(currentDate)
82
}
83
const toggleDayLock = () => {
84
  lockedDay = !lockedDay
85
  $('#player-date').toggleClass('lock')
86
}
32 87

  
33 88
const fetchByNameDate = async (baseRoute, name, date, currentTime) => {
34 89
  const headers = new Headers()
......
40 95
  return beforeJson.json()
41 96
}
42 97

  
43

  
44 98
const fetchDataSourceMarks = async (positionRoute, datasetName) => {
45 99
  const headers = new Headers()
46 100
  const myRequest = new Request(positionRoute + '/' + datasetName, {
......
51 105
  return beforeJson.json()
52 106
}
53 107

  
54

  
55 108
const genPopUpControlButtons = (currentPage, numPages, onNextClick, onPreviousClick) => ({
56 109
  previousButton: '<button id="previous-info-btn" class="circle-button" onclick="previousInfo()"></button>',
57 110
  nextButton: '<button id="next-info-btn" class="circle-button next" onclick="nextInfo()"></button>',
58 111
  posInfo: `<div id="count-info">${currentPage} z ${numPages}</div>`
59 112
})
60 113

  
61

  
62 114
const genPopUpControls = (controls) => {
63 115
  return `<div class="popup-controls">${controls ? controls.reduce((sum, item) => sum + item, '') : ''}</div>`
64 116
}
65 117

  
66

  
67 118
const genMultipleDatasetsPopUp = (sum, currentPos, maxPos, datasetName) => {
68 119
  const popupHeader = `<strong id="dataset-info">${datasetName}</strong>`
69 120
  const popupData = `<div id="number-info"><span id="digit-info">${sum}</span></div>`
......
76 127
  `
77 128
}
78 129

  
79

  
80 130
const prepareLayerPopUp = (lat, lng, num, className) => L.popup({
81 131
  autoPan: false,
82 132
  className: className
83 133
}).setLatLng([lat / num, lng / num])
84 134

  
85

  
86 135
const genPopUp = (datasetName, place, count, sum, currentPos, maxPos) => {
87 136
  const popupHeader = `
88 137
    <strong>${datasetName}</strong>
......
101 150
  `
102 151
}
103 152

  
104

  
105 153
const onCheckboxClicked = async (checkbox) => {
106 154
  if ($(checkbox).prop('checked')) {
107 155
    loadCurrentTimeHeatmap(dataSourceRoute, positionsSourceRoute)
108 156
    changeUrl()
109
  }
110
  else {
157
  } else {
111 158
    loadCheckboxDatasetNameData()
112 159

  
113 160
    data.forEach((item, index) => {
......
123 170
  }
124 171
}
125 172

  
126

  
127 173
const debounce = (func, delay) => {
128 174
  let inDebounce
129 175
  return function () {
......
134 180
  }
135 181
}
136 182

  
137

  
138 183
const onValueChangeRegister = () => {
139 184
  $('#date').change(function () {
140
    data = []
185
    changeCurrentDate($(this).val())
141 186
    loadCurrentTimeHeatmap(dataSourceRoute, positionsSourceRoute)
142
    const date = new Date($(this).val())
143
    $('#player-date').html(`${date.getDate()}. ${date.getMonth() + 1}. ${date.getFullYear()}`)
144 187
    changeUrl()
145 188
  })
146 189

  
147 190
  $('#dropdown-time input[type="radio"]').each(function () {
148 191
    $(this).change(function () {
149
      currentTime = parseInt($(this).val())
150
      updateHeaderControls()
151
      setTimeline()
192
      changeHour(parseInt($(this).val()))
152 193
      drawHeatmap(data[currentTime])
153
      changeUrl()
154 194
    })
155 195
  })
156 196

  
......
161 201
  })
162 202
}
163 203

  
164

  
165 204
/**
166 205
 * Initialize leaflet map on start position which can be default or set based on user action
167 206
 */
......
181 220
  mymap.on('click', showInfo)
182 221
}
183 222

  
184

  
185 223
const getInfoLength = () => {
186 224
  const infoKeys = Object.keys(info)
187 225
  if (infoKeys.length === 1) {
......
192 230
  return infoKeys.length
193 231
}
194 232

  
195

  
196 233
const getElFromObjectInfo = (position) => {
197 234
  const keys = Object.keys(info)
198 235
  return info[keys[position]]
199 236
}
200 237

  
201

  
202 238
const hasInfoMultipleDatasets = () => {
203 239
  return Object.keys(info).length > 1
204 240
}
205 241

  
206

  
207 242
function showInfo (e) {
208 243
  info = []
209 244
  currentInfo = 0
......
272 307
      $('#next-info-btn').prop('disabled', true)
273 308
      $('.popup-controls').hide()
274 309
    }
275
  }
276
  else {
310
  } else {
277 311
    const { datasetName, number } = getElFromObjectInfo(currentInfo)
278 312

  
279 313
    prepareLayerPopUp(lat, lng, i, `popup-${datasetName}`)
......
282 316
  }
283 317
}
284 318

  
285

  
286 319
// eslint-disable-next-line no-unused-vars
287 320
function previousInfo () {
288 321
  const infoLength = getInfoLength()
......
292 325
  displayInfoText(previousCurrentInfo)
293 326
}
294 327

  
295

  
296 328
// eslint-disable-next-line no-unused-vars
297 329
function nextInfo () {
298 330
  const infoLength = getInfoLength()
......
302 334
  displayInfoText(previousCurrentInfo)
303 335
}
304 336

  
305

  
306 337
function displayInfoText (previousInfoNum) {
307 338
  const previousInfo = hasInfoMultipleDatasets() ? getElFromObjectInfo(previousInfoNum) : getElFromObjectInfo(0).items[previousInfoNum]
308 339
  const info_ = hasInfoMultipleDatasets() ? getElFromObjectInfo(currentInfo) : getElFromObjectInfo(0).items[currentInfo]
......
312 343
  if (datasetInfo) {
313 344
    $(datasetInfo).html(datasetDictNameDisplayName[info_.datasetName])
314 345
  }
315
  
346

  
316 347
  $('#place-info').html(info_.place ? info_.place : info_.datasetName)
317 348
  $('#digit-info').html(info_.number)
318 349
  $('#count-info').html(currentInfo + 1 + ' z ' + infoLength)
......
321 352
  $('.leaflet-popup').addClass(`popup-${info_.datasetName}`)
322 353
}
323 354

  
324

  
325 355
// eslint-disable-next-line no-unused-vars
326 356
function setMapView (latitude, longitude, zoom) {
327 357
  localStorage.setItem('lat', latitude)
......
330 360
  mymap.setView([latitude, longitude], zoom)
331 361
}
332 362

  
333

  
334 363
/**
335 364
 * Change animation start from playing to stopped or the other way round
336 365
 */
......
340 369

  
341 370
  if (isAnimationRunning) {
342 371
    $('#play-pause').attr('class', 'pause')
343
    timer = setInterval(function() { next() }, 800)
344
  }
345
  else {
372
    timer = setInterval(function () { next() }, 800)
373
  } else {
346 374
    clearTimeout(timer)
347 375
    $('#play-pause').attr('class', 'play')
348 376
  }
349 377
}
350 378

  
351

  
352 379
// eslint-disable-next-line no-unused-vars
353
function previous () {
380
async function previous () {
381
  if (loading) {
382
    return
383
  }
354 384
  currentTime = (currentTime + 23) % 24
355
  drawHeatmap(data[currentTime])
356
  setTimeline()
385
  changeHour(currentTime)
357 386
  mymap.closePopup()
358
  updateHeaderControls()
359
  changeUrl()
387
  if (!lockedDay && (currentTime === 23)) {
388
    addDayToCurrentDate(-1)
389
    await loadCurrentTimeHeatmap(dataSourceRoute, positionsSourceRoute)
390
  } else {
391
    drawHeatmap(data[currentTime])
392
  }
360 393
}
361 394

  
362

  
363
function next () {
395
async function next () {
396
  if (loading) {
397
    return
398
  }
364 399
  currentTime = (currentTime + 1) % 24
365
  drawHeatmap(data[currentTime])
366
  setTimeline()
400
  changeHour(currentTime)
367 401
  mymap.closePopup()
368
  updateHeaderControls()
369
  changeUrl()
402
  if (!lockedDay && (currentTime === 0)) {
403
    addDayToCurrentDate(1)
404
    await loadCurrentTimeHeatmap(dataSourceRoute, positionsSourceRoute)
405
  } else {
406
    drawHeatmap(data[currentTime])
407
  }
370 408
}
371 409

  
372

  
373 410
/**
374 411
 * Change browser url based on animation step.
375 412
 */
......
377 414
  window.history.pushState(
378 415
    '',
379 416
    document.title,
380
    window.location.origin + window.location.pathname + `?date=${$('#date').val()}&time=${currentTime}${datasetSelected.reduce((acc, current) => acc + '&type=' + current, '')}`
417
    window.location.origin + window.location.pathname + `?date=${currentDateToString()}&time=${currentTime}${datasetSelected.reduce((acc, current) => acc + '&type=' + current, '')}`
381 418
  )
382 419
}
383 420

  
384

  
385 421
function updateHeaderControls () {
386 422
  $(`#time_${currentTime}`).prop('checked', true)
387 423
  $('#dropdownMenuButtonTime').html((currentTime < 10 ? '0' : '') + `${currentTime}:00`)
388 424
}
389 425

  
390

  
391 426
function setTimeline () {
392 427
  $('#timeline').text(currentTime + ':00')
393 428
  $('#timeline').attr('class', 'time hour-' + currentTime)
394 429
}
395

  
396

  
397
function changeHour(hour) {
398
  currentTime = hour
430
const onChangeHour = (hour) => {
431
  changeHour(hour)
432
  drawHeatmap(data[currentTime])
433
}
434
const changeHour = (hour) => {
435
  changeCurrentTime(hour)
399 436
  updateHeaderControls()
400 437
  setTimeline()
401
  drawHeatmap(data[currentTime])
402 438
  changeUrl()
403 439
}
404 440

  
405

  
406 441
/**
407 442
 * Load and display heatmap layer for current data
408 443
 * @param {string} opendataRoute route to dataset source
......
414 449

  
415 450
  dataSourceRoute = opendataRoute
416 451
  positionsSourceRoute = positionsRoute
417
  const dataSourceMarks = {}
418 452
  const allPromises = []
419
  const date = $('#date').val()
420
  currentTime = parseInt($('#dropdown-time input[type="radio"]:checked').val())
421

  
422
  setTimeline()
423 453
  data[currentTime] = {}
454

  
424 455
  const dataSelectedHandler = async (datasetName) => {
425
    const marks = await fetchDataSourceMarks(positionsRoute, datasetName)
426
    const datasetData = await fetchByNameDate(dataSourceRoute, datasetName, date, currentTime)
427
    dataSourceMarks[datasetName] = marks
456
    if (!(datasetName in dataSourceMarks)) {
457
      dataSourceMarks[datasetName] = await fetchDataSourceMarks(positionsRoute, datasetName)
458
    }
459
    const datasetData = await fetchByNameDate(dataSourceRoute, datasetName, currentDateToString(), currentTime)
428 460
    data[currentTime][datasetName] = datasetData
429 461
  }
430

  
431
  await datasetSelected.forEach((datasetName) => {
462
  datasetSelected.forEach((datasetName) => {
432 463
    allPromises.push(dataSelectedHandler(datasetName))
433 464
  })
434 465

  
466
  loadingY()
435 467
  Promise.all(allPromises).then(
436 468
    () => {
469
      loadingN()
437 470
      drawDataSourceMarks(dataSourceMarks)
438 471
      drawHeatmap(data[currentTime])
439
      preload(currentTime, 1, date)
440
      preload(currentTime, -1, date)
472
      preload(currentTime, 1, currentDateToString())
473
      preload(currentTime, -1, currentDateToString())
441 474
    }
442 475
  )
443 476
}
444 477

  
445

  
446 478
function drawDataSourceMarks (data) {
447 479
  if (marksLayer != null) {
448 480
    mymap.removeLayer(marksLayer)
......
469 501
  marksLayer.setZIndex(-1).addTo(mymap)
470 502
}
471 503

  
472

  
473 504
async function preload (time, change, date) {
505
  loadingY()
474 506
  for (let nTime = time + change; nTime >= 0 && nTime <= 23; nTime = nTime + change) {
475 507
    if (!data[nTime]) {
476 508
      data[nTime] = {}
......
482 514
      }
483 515
    })
484 516
  }
517
  loadingN()
485 518
}
486 519

  
487

  
488 520
function drawHeatmap (dataRaw) {
489 521
  // Todo still switched
490 522
  const dataDict = dataRaw
491 523
  const mergedPoints = []
492 524
  let max = 0
493
  
525

  
494 526
  if (Object.keys(globalMarkersChanged).length) {
495 527
    Object.keys(globalMarkersChanged).forEach(function (key) {
496 528
      globalMarkersChanged[key][0].bindPopup(globalMarkersChanged[key][1])
......
518 550
        return [x, y, number]
519 551
      })
520 552
      mergedPoints.push(...points)
521
    }
522
    else {
553
    } else {
523 554
      if (heatmapLayer != null) {
524 555
        mymap.removeLayer(heatmapLayer)
525 556
      }
......
535 566
  }
536 567
}
537 568

  
538

  
539 569
/**
540 570
 * Checks dataset availibility
541 571
 * @param {string} route authority for datasets availibility checks
......
545 575
  $.ajax({
546 576
    type: 'POST',
547 577
    // Todo it might be good idea to change db collections format
548
    url: route + '/' + $('#date').val(),
578
    url: route + '/' + currentDateToString(),
549 579
    success: function (result) {
550 580
      updateAvailableDataSets(result)
551 581
    }
552 582
  })
553 583
}
554 584

  
555

  
556 585
function updateAvailableDataSets (available) {
557 586
  let leastOneOptionEnabled = false
558
  // datasetSelected = []
559 587

  
560 588
  $('#dropdown-dataset .dropdown-item').each(function () {
561 589
    const input = $(this).find('input')
......
564 592
    if (!(inputVal in available)) {
565 593
      $(this).addClass('disabled')
566 594
      $(input).prop('checked', false)
567
    }
568
    else {
595
    } else {
569 596
      leastOneOptionEnabled = true
570 597
      $(this).removeClass('disabled')
571 598
    }
......
574 601
  $('#btn-update-heatmap').prop('disabled', !leastOneOptionEnabled)
575 602
}
576 603

  
577

  
578 604
function formatDate (date) {
579 605
  var day = String(date.getDate())
580 606
  var month = String(date.getMonth() + 1)
......
590 616
  return date.getFullYear() + '-' + month + '-' + day
591 617
}
592 618

  
593

  
594 619
// eslint-disable-next-line no-unused-vars
595 620
function initDatepicker (availableDatesSource) {
596 621
  var availableDates = ''
......
608 633
      beforeShowDay: function (date) {
609 634
        if (availableDates.indexOf(formatDate(date)) < 0) {
610 635
          return { enabled: false, tooltip: 'Žádná data' }
611
        }
612
        else {
636
        } else {
613 637
          return { enabled: true }
614 638
        }
615 639
      },
......
618 642
  })
619 643
}
620 644

  
621

  
622 645
function initLocationsMenu () {
623 646
  var locationsWrapper = '.locations'
624 647
  var locationsDisplayClass = 'show'
625 648

  
626 649
  if ($(window).width() <= 480) {
627 650
    $(locationsWrapper).removeClass(locationsDisplayClass)
628
  }
629
  else {
651
  } else {
630 652
    $(locationsWrapper).addClass(locationsDisplayClass)
631 653
  }
632 654
}
633 655

  
634

  
635
function openDatepicker () {
636
  if ($(window).width() <= 990) {
637
    $('.navbar-collapse').collapse()
638
  }
639

  
640
  $('#date').datepicker('show')
641
}
642

  
643

  
644 656
function onDocumentReady () {
645 657
  $('#dropdown-dataset').on('click', function (e) {
646 658
    e.stopPropagation()
647 659
  })
648 660

  
649 661
  $('#btn-update-heatmap').prop('name', '')
662
  changeCurrentTime()
663
  setTimeline()
664
  changeCurrentDate()
650 665
  onValueChangeRegister()
651 666
}
652 667

  
653

  
654 668
const loadCheckboxDatasetNameData = () => {
655 669
  datasetSelected = []
656 670
  $('#dropdown-dataset .dropdown-item').each(function () {

Také k dispozici: Unified diff