Projekt

Obecné

Profil

Stáhnout (9.44 KB) Statistiky
| Větev: | Revize:
1 8feb1753 ballakt
/* global L */
2
/* global $ */
3
var mymap
4
var heatmapLayer = null
5
var marksLayer = null
6 03c02899 vastja
7 8feb1753 ballakt
var startX = 49.7248
8
var startY = 13.3521
9
var startZoom = 17
10 3fc08f2d vastja
11 8feb1753 ballakt
var dataSourceRoute
12
var currentTime
13
var name
14
var date
15 a48642fb vastja
16 8feb1753 ballakt
var timer
17
var isAnimationRunning = false
18
var data = []
19 a48642fb vastja
20 084a5972 ballakt
// holds all instances of markers for bind/unbind popup purpose
21
// contains: {key:[L.circle,L.pupup]}
22
// key: x and y, x + '' + y string
23 8feb1753 ballakt
const globalMarkersHolder = {}
24 084a5972 ballakt
25 8feb1753 ballakt
// all marker from which popup was removed
26 084a5972 ballakt
// contains: {key:[L.circle,L.pupup]}
27
// key: x and y, x + '' + y string
28 8feb1753 ballakt
let globalMarkersChanged = {}
29 084a5972 ballakt
30
const genPopUpControls = (controls) => {
31
  return `<div class="popup-controls">${controls.reduce((sum, item) => sum + item, '')}</div>`
32
}
33
const genPopUp = (place, number, sum, currentPos, maxPos) => {
34 8feb1753 ballakt
  const header = `<strong>Zařízení a počet:</strong><div id="place-info">${place}</div>`
35
  const currentNum = `<span id="digit-info">${number}</span>`
36
  const sumNum = `<span id="total-info" style="font-size: large">${sum ? '/' + sum : ''}</span>`
37
  const digitInfo = `<div id="number-info">${currentNum}${sumNum}</div>`
38
  let previousButton = '<button id="previous-info-btn" class="circle-button" onclick="previousInfo()"></button>'
39
  let nextButton = '<button id="next-info-btn" onclick="nextInfo()" class="circle-button next"></button>'
40
  let posInfo = `<div id="count-info">${currentPos} z ${maxPos}</div>`
41 084a5972 ballakt
42
  if (!sum) {
43 8feb1753 ballakt
    previousButton = ''
44
    nextButton = ''
45
    posInfo = ''
46 084a5972 ballakt
  }
47
  return `
48
  ${header}
49
  ${digitInfo}
50
  ${genPopUpControls([previousButton, posInfo, nextButton])}
51
  `
52
}
53 8feb1753 ballakt
// eslint-disable-next-line no-unused-vars
54
function initMap () {
55
  mymap = L.map('heatmap').setView([startX, startY], startZoom)
56 3fc08f2d vastja
57 c236b33a msebela
  L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
58
    attribution: '',
59
    maxZoom: 19
60 8feb1753 ballakt
  }).addTo(mymap)
61 3ae59f75 vastja
62 8feb1753 ballakt
  mymap.on('click', showInfo)
63 c236b33a msebela
}
64 3fc08f2d vastja
65 8feb1753 ballakt
var info = []
66
var currenInfo = 0
67 3ae59f75 vastja
68 8feb1753 ballakt
function showInfo (e) {
69 3ae59f75 vastja
  info = []
70 8feb1753 ballakt
  currenInfo = 0
71 3ae59f75 vastja
72
  // https://wiki.openstreetmap.org/wiki/Zoom_levels
73
  // Todo change to variable - it is used in heatmap init
74 8feb1753 ballakt
  var stile = 40075016.686 * Math.cos(startX) / Math.pow(2, mymap.getZoom())
75
  var radius = 25 * stile / 256
76 3ae59f75 vastja
77 8feb1753 ballakt
  var i = 0
78
  var lat = 0
79
  var lng = 0
80 3ae59f75 vastja
81 8feb1753 ballakt
  var total = 0
82
  data[currentTime].items.forEach(element => {
83 3ae59f75 vastja
    if (e.latlng.distanceTo(new L.LatLng(element.x, element.y)) < radius) {
84
      lat += element.x
85 8feb1753 ballakt
      lng += element.y
86
      info[i] = { place: element.place, number: element.number }
87
      total += parseInt(element.number)
88
      i++
89 3ae59f75 vastja
    }
90 8feb1753 ballakt
  })
91 3ae59f75 vastja
92
  if (info.length > 0) {
93 8feb1753 ballakt
    const { place, number } = info[currenInfo]
94
    L.popup({
95 dfcface9 Tomáš Ballák
      autoPan: false
96 8feb1753 ballakt
    })
97
      .setLatLng([lat / i, lng / i])
98
      .setContent(genPopUp(place, number, total, currenInfo + 1, info.length))
99
      .openOn(mymap)
100
101
    if (info.length === 1) {
102
      $('#previous-info-btn').prop('disabled', true)
103
      $('#next-info-btn').prop('disabled', true)
104
      $('.popup-controls').hide()
105 3ae59f75 vastja
    }
106
  }
107
}
108
109 8feb1753 ballakt
// eslint-disable-next-line no-unused-vars
110
function previousInfo () {
111
  currenInfo = (currenInfo + info.length - 1) % info.length
112
  displayInfoText()
113 3ae59f75 vastja
}
114
115 8feb1753 ballakt
// eslint-disable-next-line no-unused-vars
116
function nextInfo () {
117 3ae59f75 vastja
  currenInfo = (currenInfo + 1) % info.length
118 8feb1753 ballakt
  displayInfoText()
119 3ae59f75 vastja
}
120
121 8feb1753 ballakt
function displayInfoText () {
122 bc7738cd Martin Sebela
  $('#place-info').html(info[currenInfo].place)
123 61ff7718 vastja
  $('#digit-info').html(info[currenInfo].number)
124 8feb1753 ballakt
  $('#count-info').html(currenInfo + 1 + ' z ' + info.length)
125 3ae59f75 vastja
}
126 351696d5 Martin Sebela
127 8feb1753 ballakt
// eslint-disable-next-line no-unused-vars
128
function setMapView (latitude = startX, longitude = startY, zoom = startZoom) {
129
  mymap.setView([latitude, longitude], zoom)
130 3fc08f2d vastja
}
131
132 8feb1753 ballakt
// eslint-disable-next-line no-unused-vars
133
function changeAnimationState () {
134 a48642fb vastja
  isAnimationRunning = !isAnimationRunning
135
  if (isAnimationRunning) {
136 8feb1753 ballakt
    $('#play-pause').attr('class', 'pause')
137 a48642fb vastja
    timer = setInterval(
138 8feb1753 ballakt
      function () {
139
        next()
140 a48642fb vastja
      },
141
      800
142 8feb1753 ballakt
    )
143
  } else {
144
    clearTimeout(timer)
145
    $('#play-pause').attr('class', 'play')
146 351696d5 Martin Sebela
  }
147
}
148
149 8feb1753 ballakt
// eslint-disable-next-line no-unused-vars
150
function previous () {
151
  currentTime = (currentTime + 23) % 24
152
  drawHeatmap(data[currentTime])
153
  setTimeline()
154
  mymap.closePopup()
155
  updateHeaderControls()
156
  changeUrl()
157 a48642fb vastja
}
158
159 8feb1753 ballakt
function next () {
160
  currentTime = (currentTime + 1) % 24
161
  drawHeatmap(data[currentTime])
162
  setTimeline()
163
  mymap.closePopup()
164
  updateHeaderControls()
165
  changeUrl()
166 8b840eb7 vastja
}
167
168 8feb1753 ballakt
function changeUrl () {
169 8b840eb7 vastja
  window.history.pushState(
170 8feb1753 ballakt
    '',
171 8b840eb7 vastja
    document.title,
172 8feb1753 ballakt
    window.location.origin + window.location.pathname + `?data_set[date]=${$('#date').val()}&data_set[time]=${currentTime}&data_set[type]=${$('#type').children('option:selected').val()}`
173
  )
174 4e8c0e5b Martin Sebela
}
175
176 8feb1753 ballakt
function updateHeaderControls () {
177
  document.getElementById('time').value = currentTime
178 a48642fb vastja
}
179 351696d5 Martin Sebela
180 8feb1753 ballakt
function setTimeline () {
181
  $('#timeline').text(currentTime + ':00')
182
  $('#timeline').attr('class', 'time hour-' + currentTime)
183 351696d5 Martin Sebela
}
184
185 8feb1753 ballakt
// eslint-disable-next-line no-unused-vars
186
function loadCurrentTimeHeatmap (opendataRoute, positionsRoute) {
187
  dataSourceRoute = opendataRoute
188
  data = []
189 64bc2934 vastja
190 8feb1753 ballakt
  name = $('#type').children('option:selected').val()
191 03ccdd65 vastja
  date = $('#date').val()
192 8feb1753 ballakt
  currentTime = parseInt($('#time').children('option:selected').val())
193
  setTimeline()
194 61ff7718 vastja
  $.ajax({
195
    type: 'POST',
196
    url: positionsRoute + '/' + name,
197 8feb1753 ballakt
    success: function (result) {
198
      drawDataSourceMarks(result)
199 084a5972 ballakt
      $.ajax({
200 8feb1753 ballakt
        type: 'POST',
201
        url: dataSourceRoute + '/' + name + '/' + date + '/' + currentTime,
202
        success: function (result) {
203
          data[currentTime] = result
204
          drawHeatmap(data[currentTime])
205 084a5972 ballakt
        }
206
      })
207 61ff7718 vastja
    }
208 8feb1753 ballakt
  })
209 a48642fb vastja
210 8feb1753 ballakt
  preload(currentTime, 1)
211
  preload(currentTime, -1)
212 a48642fb vastja
}
213
214 8feb1753 ballakt
function drawDataSourceMarks (data) {
215 61ff7718 vastja
  if (marksLayer != null) {
216 8feb1753 ballakt
    L.removeLayer(marksLayer)
217 61ff7718 vastja
  }
218 8feb1753 ballakt
  marksLayer = L.layerGroup()
219 61ff7718 vastja
  for (var key in data) {
220 8feb1753 ballakt
    const { x, y, name } = data[key]
221
    const pop =
222
      L.popup({ autoPan: false })
223 084a5972 ballakt
        .setLatLng([x, y])
224 8feb1753 ballakt
        .setContent(genPopUp(name, 0, 0, 1, 1))
225
    const newCircle =
226
      L.circle([x, y], { radius: 2, fillOpacity: 0.8, color: '#004fb3', fillColor: '#004fb3', bubblingMouseEvents: true })
227
        .bindPopup(pop)
228
    globalMarkersHolder[x + '' + y] = [newCircle, pop] // add new marker to global holders
229 084a5972 ballakt
    marksLayer.addLayer(
230
      newCircle
231 8feb1753 ballakt
    )
232 61ff7718 vastja
  }
233
234 8feb1753 ballakt
  marksLayer.setZIndex(-1).addTo(mymap)
235 61ff7718 vastja
}
236
237 8feb1753 ballakt
function preload (time, change) {
238
  var ntime = time + change
239
  if (ntime >= 0 && ntime <= 23) {
240
    $.ajax({
241
      type: 'POST',
242
      url: dataSourceRoute + '/' + name + '/' + date + '/' + ntime,
243
      success: function (result) {
244
        data[ntime] = result
245
        preload(ntime, change)
246
      }
247
    })
248 a48642fb vastja
  }
249 3fc08f2d vastja
}
250
251 8feb1753 ballakt
function drawHeatmap (data) {
252 03c02899 vastja
  // Todo still switched
253 8feb1753 ballakt
  if (data.items != null) {
254
    // Bind back popups for markers (we dont know if there is any data for this marker or not)
255
    if (Object.keys(globalMarkersChanged).length) {
256
      Object.keys(globalMarkersChanged).forEach(function (key) {
257
        globalMarkersChanged[key][0].bindPopup(globalMarkersChanged[key][1])
258
      })
259
      globalMarkersChanged = {}
260 084a5972 ballakt
    }
261 8feb1753 ballakt
    const points = data.items.map((point) => {
262
      const { x, y, number } = point
263
      const key = x + '' + y
264
      const holder = globalMarkersHolder[key]
265
      if (!globalMarkersChanged[key] && number) {
266
        // There is data for this marker => unbind popup with zero value
267
        holder[0] = holder[0].unbindPopup()
268
        globalMarkersChanged[key] = holder
269 084a5972 ballakt
      }
270 8feb1753 ballakt
      return [x, y, number]
271
    })
272 a48642fb vastja
    if (heatmapLayer != null) {
273 8feb1753 ballakt
      mymap.removeLayer(heatmapLayer)
274 a48642fb vastja
    }
275 8feb1753 ballakt
    heatmapLayer = L.heatLayer(points, { max: data.max, minOpacity: 0.5, radius: 35, blur: 30 }).addTo(mymap)
276
  } else {
277 a48642fb vastja
    if (heatmapLayer != null) {
278 8feb1753 ballakt
      mymap.removeLayer(heatmapLayer)
279 a48642fb vastja
    }
280
  }
281
282 03c02899 vastja
  // var heat_01 = ...
283
  // on background map.addLayer(heat_01) -> map.removeLayer(heat_01);
284 64bc2934 vastja
  // $(.leaflet-heatmap-layer).css('opacity', 'value');
285 03c02899 vastja
}
286 3fc08f2d vastja
287 8feb1753 ballakt
// eslint-disable-next-line no-unused-vars
288
function checkDataSetsAvailability (route) {
289 03c02899 vastja
  $.ajax({
290 8feb1753 ballakt
    type: 'POST',
291 03c02899 vastja
    // Todo it might be good idea to change db collections format
292 03ccdd65 vastja
    url: route + '/' + $('#date').val(),
293 8feb1753 ballakt
    success: function (result) {
294
      updateAvailableDataSets(result)
295 03c02899 vastja
    }
296 8feb1753 ballakt
  })
297 03c02899 vastja
}
298
299 8feb1753 ballakt
var allOptionsDisabled = false
300 2dd5d57f vastja
301 8feb1753 ballakt
function updateAvailableDataSets (available) {
302
  var isOptionEnabled = true
303
  $('#type > option').each(function () {
304
    if ((this.value in available) === false) {
305
      $(this).prop('disabled', true)
306
      $(this).prop('selected', false)
307
    } else {
308 5d599617 vastja
      $(this).prop('disabled', false)
309 2dd5d57f vastja
      if (allOptionsDisabled) {
310 8feb1753 ballakt
        $(this).prop('selected', true)
311
        allOptionsDisabled = false
312 2dd5d57f vastja
      }
313 8feb1753 ballakt
      isOptionEnabled = false
314 5d599617 vastja
    }
315 8feb1753 ballakt
  })
316
  allOptionsDisabled = isOptionEnabled
317 dfe43218 vastja
318 8feb1753 ballakt
  $('#submit-btn').prop('disabled', isOptionEnabled)
319 03c02899 vastja
}
320 0a828a5a Martin Sebela
321 8feb1753 ballakt
function formatDate (date) {
322
  var day = String(date.getDate())
323
  var month = String(date.getMonth() + 1)
324 0a828a5a Martin Sebela
325
  if (day.length === 1) {
326 8feb1753 ballakt
    day = '0' + day
327 0a828a5a Martin Sebela
  }
328
329
  if (month.length === 1) {
330 8feb1753 ballakt
    month = '0' + month
331 0a828a5a Martin Sebela
  }
332
333 8feb1753 ballakt
  return date.getFullYear() + '-' + month + '-' + day
334 0a828a5a Martin Sebela
}
335
336 8feb1753 ballakt
// eslint-disable-next-line no-unused-vars
337
function initDatepicker (availableDatesSource) {
338
  var availableDates = ''
339 0a828a5a Martin Sebela
340
  $.ajax({
341
    type: 'GET',
342
    url: availableDatesSource,
343 8feb1753 ballakt
    success: function (result) {
344
      availableDates = String(result).split(',')
345 0a828a5a Martin Sebela
    }
346 a7e04778 Martin Sebela
  }).then(function () {
347
    $('#date').datepicker({
348
      format: 'yyyy-mm-dd',
349
      language: 'cs',
350 8feb1753 ballakt
      beforeShowDay: function (date) {
351 a7e04778 Martin Sebela
        if (availableDates.indexOf(formatDate(date)) < 0) {
352 8feb1753 ballakt
          return { enabled: false, tooltip: 'Žádná data' }
353
        } else {
354
          return { enabled: true }
355 a7e04778 Martin Sebela
        }
356
      },
357
      autoclose: true
358 8feb1753 ballakt
    })
359
  })
360
}