Projekt

Obecné

Profil

« Předchozí | Další » 

Revize c892003d

Přidáno uživatelem Martin Sebela před více než 3 roky(ů)

Re #8159 - CSS improvements, timeline clickable, code refactoring

Zobrazit rozdíly:

website/public/css/style.css
893 893
  position: relative;
894 894
  padding: 0 10px;
895 895
  border-radius: 100px;
896
  cursor: pointer;
896 897
  background-color: rgba(11, 21, 90, 0.7);
897 898
}
898 899

  
......
1101 1102
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
1102 1103
  font-family: 'Be Vietnam', sans-serif;
1103 1104
  text-align: center;
1104
  color: white;
1105
  color: #ffffff;
1105 1106
}
1106 1107

  
1107 1108
.leaflet-popup-content-wrapper .leaflet-popup-content strong {
......
1166 1167
}
1167 1168

  
1168 1169
header.map .nav-item .btn-secondary {
1170
  display: flex;
1171
  justify-content: center;
1172
  align-items: center;
1169 1173
  outline: none;
1170 1174
  border-radius: 50px;
1171 1175
  height: 40px;
......
1177 1181
  -webkit-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.17);
1178 1182
  -moz-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.17);
1179 1183
  box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.17);
1180
  text-align: center;
1181
  display: flex;
1182
  justify-content: center;
1183
  align-items: center;
1184 1184
}
1185 1185

  
1186 1186
@media (max-width: 991.98px) {
......
1229 1229
  color: #000;
1230 1230
}
1231 1231

  
1232
header.map .nav-item select:hover {
1233
  cursor: pointer;
1234
  background: rgba(255, 255, 255, 0.2);
1235
}
1236

  
1237
header.map .nav-item select:hover option {
1238
  background: #0048A9;
1239
}
1240

  
1241
header.map .nav-item select:focus {
1242
  background: #0048A9;
1243
  color: white;
1244
}
1245

  
1246
.custom-dropdown-item {
1247
  margin: 0px !important;
1248
}
1249

  
1250
.custom-dropdown-item .disabled {
1251
  cursor: not-allowed !important;
1252
}
1253

  
1254
.custom-control-label {
1255
  font-weight: 300 !important;
1256
  margin: 0px !important;
1232
.dropdown {
1233
  min-width: 200px;
1257 1234
}
1258 1235

  
1259
.custom-dropdown {
1260
  cursor: not-allowed;
1261
}
1262

  
1263
input[type=radio]:checked ~ label {
1236
.dropdown input[type="radio"]:checked ~ label {
1264 1237
  font-weight: 800;
1265 1238
}
1266 1239

  
......
1280 1253
  width: 100%;
1281 1254
  max-height: 300px;
1282 1255
  overflow-y: auto;
1256
  z-index: 1001;
1257
}
1258

  
1259
.dropdown .dropdown-item:active {
1260
  background: #0048A9;
1283 1261
}
1284 1262

  
1285 1263
.dropdown .dropdown-item label {
1286 1264
  width: 100% !important;
1265
  margin-left: 0;
1287 1266
  cursor: pointer;
1288 1267
}
1289 1268

  
1290
.dropdown #dataset-dropdown-time .dropdown-item:nth-of-type(even) {
1269
.dropdown #dropdown-time .dropdown-item:nth-of-type(even) {
1291 1270
  background: rgba(0, 0, 0, 0.05);
1292 1271
}
1293 1272

  
1294
.dropdown #dataset-dropdown-time .dropdown-item:nth-of-type(even):active {
1295
  background: #007bff;
1273
.dropdown #dropdown-time .dropdown-item:nth-of-type(even):active {
1274
  background: #0048A9;
1296 1275
}
website/public/css/style.scss
6 6

  
7 7
$primary-bg-color: #0048A9;
8 8
$primary-bg-color-darker: #004fb3;
9
$input-bg-hover: #336dba;
9 10
$secondary-bg-color: #0b155a;
10 11

  
11 12
$primary-text-color: #ffffff;
......
717 718
}
718 719

  
719 720

  
720
// PŘEHRÁVAČ HEATMAPY
721
// DOLNÍ OVLÁDACÍ PANEL HEATMAPY
721 722
.player {
722 723
  width: 100%;
723 724
  display: flex;
......
850 851
    position: relative;
851 852
    padding: 0 10px;
852 853
    border-radius: 100px;
854
    cursor: pointer;
853 855
    background-color: rgba(11, 21, 90, .7);
854 856

  
855 857
    @include media-breakpoint-down(md) {
......
955 957
  background: url($images-dir + 'footer-bg.svg') no-repeat;
956 958

  
957 959
  @include media-breakpoint-down(md) {
958
    
959 960
    width: 320px;
960 961
    height: 143px;
961 962
    background-size: 100%;
......
1003 1004
  }
1004 1005
}
1005 1006

  
1006
// INFORMACE O KONKRÉTNÍM BODĚ V HEATMAPĚ
1007

  
1008
// POPUP O KONKRÉTNÍM BODĚ V HEATMAPĚ
1007 1009
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
1008 1010
  font-family: 'Be Vietnam', sans-serif;
1009 1011
  text-align: center;
1010
  color: white;
1012
  color: $primary-text-color;
1011 1013
}
1012 1014

  
1013 1015
.leaflet-popup-content-wrapper {
......
1074 1076
  }
1075 1077

  
1076 1078
  .btn-secondary {
1079
    display: flex;
1080
    justify-content: center;
1081
    align-items: center;
1077 1082
    outline: none;
1078 1083
    border-radius: 50px;
1079 1084
    height: 40px;
......
1085 1090
    -webkit-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.17);
1086 1091
    -moz-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.17);
1087 1092
    box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.17);
1088
    text-align: center;
1089
    display: flex;
1090
    justify-content: center;
1091
    align-items: center;
1092 1093

  
1093 1094
    @include media-breakpoint-down(md) {
1094 1095
      width: 100%;
......
1098 1099
      margin-bottom: -10px;
1099 1100
    }
1100 1101

  
1101
    &:after{
1102
    &:after {
1102 1103
      padding-bottom: 4px;
1103 1104
      content: '↺';
1104 1105
      font-weight: 400;
......
1136 1137
      color: #000;
1137 1138
    }
1138 1139
  }
1140
}
1139 1141

  
1140
  select {
1141
    &:hover {
1142
      cursor: pointer;
1143
      background: rgba(255, 255, 255, .2);
1144 1142

  
1145
      option {
1146
        background: $primary-bg-color;
1147
      }
1148
    }
1143
// MENU PRO VÝBĚR ČASU/DATOVÝCH SAD
1144
.dropdown {
1145
  min-width: 200px;
1149 1146

  
1150
    &:focus {
1151
      background: $primary-bg-color;
1152
      color: white;
1153
    }
1147
  input[type="radio"]:checked ~ label {
1148
    font-weight: 800;
1154 1149
  }
1155
}
1156
.custom-dropdown-item {
1157
  margin: 0px !important;
1158
}
1159
.custom-dropdown-item .disabled {
1160
  cursor: not-allowed !important;
1161
}
1162
.custom-control-label {
1163
  font-weight: 300 !important;
1164
  margin: 0px !important;
1165
}
1166
.custom-dropdown {
1167
  cursor: not-allowed;
1168
}
1169 1150

  
1170
input[type=radio]:checked~label {
1171
  font-weight: 800;
1172
}
1173

  
1174
.dropdown {
1175 1151
  .btn {
1176 1152
    width: 100%;
1177 1153
    text-align: left;
......
1180 1156
    background: $primary-bg-color;
1181 1157

  
1182 1158
    &:hover {
1183
      background: #336dba;
1159
      background: $input-bg-hover;
1184 1160
    }
1185 1161
  }
1186 1162

  
......
1188 1164
    width: 100%;
1189 1165
    max-height: 300px;
1190 1166
    overflow-y: auto;
1167
    z-index: 1001;
1191 1168
  }
1192 1169

  
1193
  .dropdown-item label {
1194
    width: 100% !important;
1195
    cursor: pointer;
1170
  .dropdown-item {
1171
    &:active {
1172
      background: $primary-bg-color;
1173
    }
1174
    
1175
    label {
1176
      width: 100% !important;
1177
      margin-left: 0;
1178
      cursor: pointer;
1179
    }
1196 1180
  }
1197 1181

  
1198
  #dataset-dropdown-time .dropdown-item:nth-of-type(even) {
1182
  #dropdown-time .dropdown-item:nth-of-type(even) {
1199 1183
    background: rgba(0,0,0,.05);
1200 1184

  
1201 1185
    &:active {
1202
      background: #007bff;
1186
      background: $primary-bg-color;
1203 1187
    }
1204 1188
  }
1205 1189
}
website/public/js/zcu-heatmap.js
29 29
// key: x and y, x + '' + y string
30 30
let globalMarkersChanged = {}
31 31

  
32

  
32 33
const fetchByNameDate = async (baseRoute, name, date, currentTime) => {
33 34
  const headers = new Headers()
34 35
  const myRequest = new Request(baseRoute + '/' + name + '/' + date + '/' + currentTime, {
......
38 39
  const beforeJson = await fetch(myRequest)
39 40
  return beforeJson.json()
40 41
}
42

  
43

  
41 44
const fetchDataSourceMarks = async (positionRoute, datasetName) => {
42 45
  const headers = new Headers()
43 46
  const myRequest = new Request(positionRoute + '/' + datasetName, {
......
48 51
  return beforeJson.json()
49 52
}
50 53

  
54

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

  
61

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

  
66

  
59 67
const genMultipleDatasetsPopUp = (sum, currentPos, maxPos, datasetName) => {
60
  const header = `<strong id="dataset-info">${datasetName}</strong>`
61
  const digitInfo = `<div id="number-info"><span id="digit-info">${sum}</span></div>`
68
  const popupHeader = `<strong id="dataset-info">${datasetName}</strong>`
69
  const popupData = `<div id="number-info"><span id="digit-info">${sum}</span></div>`
62 70
  const { previousButton, nextButton, posInfo } = genPopUpControlButtons(currentPos, maxPos)
71

  
63 72
  return `
64
  ${header}
65
  ${digitInfo}
73
  ${popupHeader}
74
  ${popupData}
66 75
  ${genPopUpControls([previousButton, posInfo, nextButton])}
67 76
  `
68 77
}
78

  
79

  
69 80
const prepareLayerPopUp = (lat, lng, num, className) => L.popup({
70 81
  autoPan: false,
71 82
  className: className
72 83
}).setLatLng([lat / num, lng / num])
73 84

  
85

  
74 86
const genPopUp = (datasetName, place, count, sum, currentPos, maxPos) => {
75 87
  const popupHeader = `
76 88
    <strong>${datasetName}</strong>
......
88 100
  ${genPopUpControls(maxPos > 1 ? [previousButton, posInfo, nextButton] : null)}
89 101
  `
90 102
}
103

  
104

  
91 105
const onCheckboxClicked = async (checkbox) => {
92 106
  if ($(checkbox).prop('checked')) {
93 107
    loadCurrentTimeHeatmap(dataSourceRoute, positionsSourceRoute)
94 108
    changeUrl()
95
  } else {
109
  }
110
  else {
96 111
    loadCheckboxDatasetNameData()
112

  
97 113
    data.forEach((item, index) => {
98 114
      Object.keys(item).forEach((datasetName) => {
99 115
        if (datasetName === $(checkbox).val()) {
......
102 118
      })
103 119
      drawHeatmap(data[currentTime])
104 120
    })
121

  
105 122
    changeUrl()
106 123
  }
107 124
}
125

  
126

  
108 127
const debounce = (func, delay) => {
109 128
  let inDebounce
110 129
  return function () {
......
115 134
  }
116 135
}
117 136

  
137

  
118 138
const onValueChangeRegister = () => {
119 139
  $('#date').change(function () {
120 140
    data = []
......
124 144
    changeUrl()
125 145
  })
126 146

  
127
  $('#dataset-dropdown-time input[type="radio"]').each(function () {
147
  $('#dropdown-time input[type="radio"]').each(function () {
128 148
    $(this).change(function () {
129 149
      currentTime = parseInt($(this).val())
130 150
      updateHeaderControls()
......
134 154
    })
135 155
  })
136 156

  
137
  $('input[type=checkbox]').each(function () {
157
  $('#dropdown-dataset input[type="checkbox"]').each(function () {
138 158
    $(this).change(
139 159
      debounce(() => onCheckboxClicked(this), 1000)
140 160
    )
141 161
  })
142 162
}
143 163

  
164

  
144 165
/**
145 166
 * Initialize leaflet map on start position which can be default or set based on user action
146 167
 */
......
159 180

  
160 181
  mymap.on('click', showInfo)
161 182
}
183

  
184

  
162 185
const getInfoLength = () => {
163 186
  const infoKeys = Object.keys(info)
164 187
  if (infoKeys.length === 1) {
......
168 191
  // return number of datasets (agregation of all datasets in area)
169 192
  return infoKeys.length
170 193
}
194

  
195

  
171 196
const getElFromObjectInfo = (position) => {
172 197
  const keys = Object.keys(info)
173 198
  return info[keys[position]]
174 199
}
200

  
201

  
175 202
const hasInfoMultipleDatasets = () => {
176 203
  return Object.keys(info).length > 1
177 204
}
205

  
206

  
178 207
function showInfo (e) {
179 208
  info = []
180 209
  currentInfo = 0
......
216 245
        datasetName: item.datasetName
217 246
      }
218 247
    }
248

  
219 249
    acc[item.datasetName].items.push(item)
220 250
    acc[item.datasetName].number += Number(item.number)
221 251
    return acc
......
236 266
    prepareLayerPopUp(lat, lng, i, `popup-${infoDict.datasetName}`)
237 267
      .setContent(genPopUp(datasetDictNameDisplayName[infoDict.datasetName], place, number, total, currentInfo + 1, info_.length))
238 268
      .openOn(mymap)
269

  
239 270
    if (info_.length === 1) {
240 271
      $('#previous-info-btn').prop('disabled', true)
241 272
      $('#next-info-btn').prop('disabled', true)
242 273
      $('.popup-controls').hide()
243 274
    }
244
  } else {
275
  }
276
  else {
245 277
    const { datasetName, number } = getElFromObjectInfo(currentInfo)
278

  
246 279
    prepareLayerPopUp(lat, lng, i, `popup-${datasetName}`)
247 280
      .setContent(genMultipleDatasetsPopUp(number, currentInfo + 1, getInfoLength(), datasetDictNameDisplayName[datasetName]))
248 281
      .openOn(mymap)
249 282
  }
250 283
}
251 284

  
285

  
252 286
// eslint-disable-next-line no-unused-vars
253 287
function previousInfo () {
254 288
  const infoLength = getInfoLength()
255 289
  const previousCurrentInfo = currentInfo
290

  
256 291
  currentInfo = (currentInfo + infoLength - 1) % infoLength
257 292
  displayInfoText(previousCurrentInfo)
258 293
}
259 294

  
295

  
260 296
// eslint-disable-next-line no-unused-vars
261 297
function nextInfo () {
262 298
  const infoLength = getInfoLength()
263 299
  const previousCurrentInfo = currentInfo
300

  
264 301
  currentInfo = (currentInfo + 1) % infoLength
265 302
  displayInfoText(previousCurrentInfo)
266 303
}
304

  
305

  
267 306
function displayInfoText (previousInfoNum) {
268 307
  const previousInfo = hasInfoMultipleDatasets() ? getElFromObjectInfo(previousInfoNum) : getElFromObjectInfo(0).items[previousInfoNum]
269 308
  const info_ = hasInfoMultipleDatasets() ? getElFromObjectInfo(currentInfo) : getElFromObjectInfo(0).items[currentInfo]
270 309
  const infoLength = getInfoLength()
271 310
  const datasetInfo = $('#dataset-info')
311

  
272 312
  if (datasetInfo) {
273 313
    $(datasetInfo).html(datasetDictNameDisplayName[info_.datasetName])
274 314
  }
315
  
275 316
  $('#place-info').html(info_.place ? info_.place : info_.datasetName)
276 317
  $('#digit-info').html(info_.number)
277 318
  $('#count-info').html(currentInfo + 1 + ' z ' + infoLength)
319

  
278 320
  $('.leaflet-popup').removeClass(`popup-${previousInfo.datasetName}`)
279 321
  $('.leaflet-popup').addClass(`popup-${info_.datasetName}`)
280 322
}
281 323

  
324

  
282 325
// eslint-disable-next-line no-unused-vars
283 326
function setMapView (latitude, longitude, zoom) {
284 327
  localStorage.setItem('lat', latitude)
......
287 330
  mymap.setView([latitude, longitude], zoom)
288 331
}
289 332

  
333

  
290 334
/**
291 335
 * Change animation start from playing to stopped or the other way round
292 336
 */
293 337
// eslint-disable-next-line no-unused-vars
294 338
function changeAnimationState () {
295 339
  isAnimationRunning = !isAnimationRunning
340

  
296 341
  if (isAnimationRunning) {
297 342
    $('#play-pause').attr('class', 'pause')
298
    timer = setInterval(
299
      function () {
300
        next()
301
      },
302
      800
303
    )
304
  } else {
343
    timer = setInterval(function() { next() }, 800)
344
  }
345
  else {
305 346
    clearTimeout(timer)
306 347
    $('#play-pause').attr('class', 'play')
307 348
  }
308 349
}
309 350

  
351

  
310 352
// eslint-disable-next-line no-unused-vars
311 353
function previous () {
312 354
  currentTime = (currentTime + 23) % 24
......
317 359
  changeUrl()
318 360
}
319 361

  
362

  
320 363
function next () {
321 364
  currentTime = (currentTime + 1) % 24
322 365
  drawHeatmap(data[currentTime])
......
325 368
  updateHeaderControls()
326 369
  changeUrl()
327 370
}
328
const typeUrlReducer = (accumulator, currentValue) => accumulator + currentValue
371

  
372

  
329 373
/**
330
 * Change browser url based on animation step
374
 * Change browser url based on animation step.
331 375
 */
332 376
function changeUrl () {
333 377
  window.history.pushState(
334 378
    '',
335 379
    document.title,
336
    window.location.origin + window.location.pathname + `?date=${$('#date').val()}&time=${currentTime}${datasetSelected.reduce((acc, current) => acc + '&type[]=' + current, '')}`
380
    window.location.origin + window.location.pathname + `?date=${$('#date').val()}&time=${currentTime}${datasetSelected.reduce((acc, current) => acc + '&type=' + current, '')}`
337 381
  )
338 382
}
339 383

  
384

  
340 385
function updateHeaderControls () {
341 386
  $(`#time_${currentTime}`).prop('checked', true)
342 387
  $('#dropdownMenuButtonTime').html((currentTime < 10 ? '0' : '') + `${currentTime}:00`)
343 388
}
344 389

  
390

  
345 391
function setTimeline () {
346 392
  $('#timeline').text(currentTime + ':00')
347 393
  $('#timeline').attr('class', 'time hour-' + currentTime)
348 394
}
349 395

  
396

  
397
function changeHour(hour) {
398
  currentTime = hour
399
  updateHeaderControls()
400
  setTimeline()
401
  drawHeatmap(data[currentTime])
402
  changeUrl()
403
}
404

  
405

  
350 406
/**
351 407
 * Load and display heatmap layer for current data
352 408
 * @param {string} opendataRoute route to dataset source
......
355 411
// eslint-disable-next-line no-unused-vars
356 412
async function loadCurrentTimeHeatmap (opendataRoute, positionsRoute) {
357 413
  loadCheckboxDatasetNameData()
414

  
358 415
  dataSourceRoute = opendataRoute
359 416
  positionsSourceRoute = positionsRoute
360 417
  const dataSourceMarks = {}
361 418
  const allPromises = []
362 419
  const date = $('#date').val()
363
  currentTime = parseInt($('#dataset-dropdown-time input[type="radio"]:checked').val())
420
  currentTime = parseInt($('#dropdown-time input[type="radio"]:checked').val())
364 421

  
365 422
  setTimeline()
366 423
  data[currentTime] = {}
......
370 427
    dataSourceMarks[datasetName] = marks
371 428
    data[currentTime][datasetName] = datasetData
372 429
  }
430

  
373 431
  await datasetSelected.forEach((datasetName) => {
374 432
    allPromises.push(dataSelectedHandler(datasetName))
375 433
  })
434

  
376 435
  Promise.all(allPromises).then(
377 436
    () => {
378 437
      drawDataSourceMarks(dataSourceMarks)
......
383 442
  )
384 443
}
385 444

  
445

  
386 446
function drawDataSourceMarks (data) {
387 447
  if (marksLayer != null) {
388 448
    mymap.removeLayer(marksLayer)
389 449
  }
450

  
390 451
  marksLayer = L.layerGroup()
452

  
391 453
  Object.keys(data).forEach((key_) => {
392 454
    for (var key in data[key_]) {
393 455
      const { x, y, name } = data[key_][key]
......
407 469
  marksLayer.setZIndex(-1).addTo(mymap)
408 470
}
409 471

  
472

  
410 473
async function preload (time, change, date) {
411 474
  for (let nTime = time + change; nTime >= 0 && nTime <= 23; nTime = nTime + change) {
412 475
    if (!data[nTime]) {
413 476
      data[nTime] = {}
414 477
    }
478

  
415 479
    datasetSelected.forEach(async (datasetName) => {
416 480
      if (!data[nTime][datasetName]) {
417 481
        data[nTime][datasetName] = await fetchByNameDate(dataSourceRoute, datasetName, date, nTime)
......
420 484
  }
421 485
}
422 486

  
487

  
423 488
function drawHeatmap (dataRaw) {
424 489
  // Todo still switched
425 490
  const dataDict = dataRaw
426 491
  const mergedPoints = []
427 492
  let max = 0
493
  
428 494
  if (Object.keys(globalMarkersChanged).length) {
429 495
    Object.keys(globalMarkersChanged).forEach(function (key) {
430 496
      globalMarkersChanged[key][0].bindPopup(globalMarkersChanged[key][1])
431 497
    })
432 498
    globalMarkersChanged = {}
433 499
  }
500

  
434 501
  Object.keys(dataDict).forEach((key) => {
435 502
    const data = dataDict[key]
436 503
    max = Math.max(max, data.max)
504

  
437 505
    if (data != null) {
438 506
    // Bind back popups for markers (we dont know if there is any data for this marker or not)
439 507
      const points = data.items.map((point) => {
440 508
        const { x, y, number } = point
441 509
        const key = x + '' + y
442 510
        const holder = globalMarkersHolder[key]
511

  
443 512
        if (!globalMarkersChanged[key] && number) {
444 513
        // There is data for this marker => unbind popup with zero value
445 514
          holder[0] = holder[0].unbindPopup()
446 515
          globalMarkersChanged[key] = holder
447 516
        }
517

  
448 518
        return [x, y, number]
449 519
      })
450 520
      mergedPoints.push(...points)
451
    } else {
521
    }
522
    else {
452 523
      if (heatmapLayer != null) {
453 524
        mymap.removeLayer(heatmapLayer)
454 525
      }
455 526
    }
456 527
  })
528

  
457 529
  if (heatmapLayer != null) {
458 530
    mymap.removeLayer(heatmapLayer)
459 531
  }
532

  
460 533
  if (mergedPoints.length) {
461 534
    heatmapLayer = L.heatLayer(mergedPoints, { max: max, minOpacity: 0.5, radius: 35, blur: 30 }).addTo(mymap)
462 535
  }
463 536
}
464 537

  
538

  
465 539
/**
466 540
 * Checks dataset availibility
467 541
 * @param {string} route authority for datasets availibility checks
......
478 552
  })
479 553
}
480 554

  
555

  
481 556
function updateAvailableDataSets (available) {
482 557
  let leastOneOptionEnabled = false
483 558
  // datasetSelected = []
484
  $('#dataset-dropdown .dropdown-item').each(function () {
559

  
560
  $('#dropdown-dataset .dropdown-item').each(function () {
485 561
    const input = $(this).find('input')
486 562
    const inputVal = input[0].value
563

  
487 564
    if (!(inputVal in available)) {
488 565
      $(this).addClass('disabled')
489 566
      $(input).prop('checked', false)
490
    } else {
567
    }
568
    else {
491 569
      leastOneOptionEnabled = true
492 570
      $(this).removeClass('disabled')
493 571
    }
......
496 574
  $('#btn-update-heatmap').prop('disabled', !leastOneOptionEnabled)
497 575
}
498 576

  
577

  
499 578
function formatDate (date) {
500 579
  var day = String(date.getDate())
501 580
  var month = String(date.getMonth() + 1)
......
511 590
  return date.getFullYear() + '-' + month + '-' + day
512 591
}
513 592

  
593

  
514 594
// eslint-disable-next-line no-unused-vars
515 595
function initDatepicker (availableDatesSource) {
516 596
  var availableDates = ''
......
528 608
      beforeShowDay: function (date) {
529 609
        if (availableDates.indexOf(formatDate(date)) < 0) {
530 610
          return { enabled: false, tooltip: 'Žádná data' }
531
        } else {
611
        }
612
        else {
532 613
          return { enabled: true }
533 614
        }
534 615
      },
......
537 618
  })
538 619
}
539 620

  
621

  
540 622
function initLocationsMenu () {
541 623
  var locationsWrapper = '.locations'
542 624
  var locationsDisplayClass = 'show'
543 625

  
544 626
  if ($(window).width() <= 480) {
545 627
    $(locationsWrapper).removeClass(locationsDisplayClass)
546
  } else {
628
  }
629
  else {
547 630
    $(locationsWrapper).addClass(locationsDisplayClass)
548 631
  }
549 632
}
550 633

  
634

  
551 635
function openDatepicker () {
552 636
  if ($(window).width() <= 990) {
553 637
    $('.navbar-collapse').collapse()
......
555 639

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

  
643

  
558 644
function onDocumentReady () {
559
  $('#dataset-dropdown').on('click', function (e) {
645
  $('#dropdown-dataset').on('click', function (e) {
560 646
    e.stopPropagation()
561 647
  })
562 648

  
563 649
  $('#btn-update-heatmap').prop('name', '')
564 650
  onValueChangeRegister()
565 651
}
652

  
653

  
566 654
const loadCheckboxDatasetNameData = () => {
567 655
  datasetSelected = []
568
  $('#dataset-dropdown .dropdown-item').each(function () {
656
  $('#dropdown-dataset .dropdown-item').each(function () {
569 657
    const input = $(this).find('input')
570 658
    const inputVal = input[0].value
659

  
571 660
    if (input[0].checked) {
572 661
      datasetSelected.push(inputVal)
573 662
    }
663

  
574 664
    datasetDictNameDisplayName[inputVal] = $(input).data('dataset-display-name')
575 665
  })
576 666
}
website/templates/base.html.twig
1 1
<!DOCTYPE html>
2 2
<html lang="cs">
3
    <head>
4
        <meta charset="utf-8">
3
  <head>
4
    <meta charset="utf-8">
5 5
        
6
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7
        <meta name="description" content="Heatmapa kampusu Západočeské univerzity v Plzni">
8
        <meta name="keywords" content="heatmap, opendata, západočeská univerzita, zču, plzeň">
9
        <meta name="author" content="Tým BHVS &ndash; Tomáš Ballák, Petr Hlaváč, Jakub Vašta, Martin Šebela">
6
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7
    <meta name="description" content="Heatmapa kampusu Západočeské univerzity v Plzni">
8
    <meta name="keywords" content="heatmap, opendata, otevřená data, západočeská univerzita, zču, plzeň">
9
    <meta name="author" content="Tým BHVS &ndash; Tomáš Ballák, Petr Hlaváč, Jakub Vašta, Martin Šebela">
10 10

  
11
        <meta property="og:url" content="https://heatmap.zcu.cz">
12
        <meta property="og:type" content="website">
13
        <meta property="og:title" content="Heatmapa kampusu Západočeské univerzity v Plzni">
14
        <meta property="og:description" content="Hodina po hodině, den po dni.">
15
        <meta property="og:image" content="https://heatmap.zcu.cz/img/banner.jpg">
11
    <meta property="og:url" content="https://heatmap.zcu.cz">
12
    <meta property="og:type" content="website">
13
    <meta property="og:title" content="Heatmapa kampusu Západočeské univerzity v Plzni">
14
    <meta property="og:description" content="Hodina po hodině, den po dni.">
15
    <meta property="og:image" content="https://heatmap.zcu.cz/img/banner.jpg">
16 16

  
17
        <link rel="shortcut icon" href="favicon.ico">
17
    <link rel="shortcut icon" href="favicon.ico">
18 18

  
19
        <title>{% block title %}{% endblock %}</title>
20
        {% block stylesheets %}{% endblock %}
21
    </head>
22
    <body{% block bodyClass %}{% endblock %}>
23
        {% block body %}{% endblock %}
24
        {% block javascripts %}{% endblock %}
25
        {% block style %}{% endblock %}
26
    </body>
19
    <title>{% block title %}{% endblock %}</title>
20
    
21
    {% block stylesheets %}{% endblock %}
22
    {% block style %}{% endblock %}
23
 </head>
24
 <body{% block bodyClass %}{% endblock %}>
25
    {% block body %}{% endblock %}
26
    {% block javascripts %}{% endblock %}
27
  </body>
27 28
</html>
website/templates/heatmap.html.twig
2 2

  
3 3
{% block title %}Heatmap.ZČU{% endblock %}
4 4
{% block stylesheets %}
5
  <link rel="stylesheet" href="{{ asset('css/leaflet.css') }}">
6
  <link rel="stylesheet" href="{{ asset('css/bootstrap.min.css') }}">
7
  <link rel="stylesheet" href="{{ asset('css/style.css') }}">
8
  <link rel="stylesheet" href="{{ asset('css/bootstrap-datepicker3.css') }}">
5
<link rel="stylesheet" href="{{ asset('css/leaflet.css') }}">
6
    <link rel="stylesheet" href="{{ asset('css/bootstrap.min.css') }}">
7
    <link rel="stylesheet" href="{{ asset('css/style.css') }}">
8
    <link rel="stylesheet" href="{{ asset('css/bootstrap-datepicker3.css') }}">
9 9
{% endblock %}
10 10

  
11 11
{% block body %}
......
47 47
                <button type="button" class="btn dropdown-toggle" id="dropdownMenuButtonTime" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
48 48
                  {{ current_time }}
49 49
                </button>
50
                <div id="dataset-dropdown-time" class="dropdown-menu" aria-labelledby="dropdownMenuButtonTime">
50
                <div id="dropdown-time" class="dropdown-menu" aria-labelledby="dropdownMenuButtonTime">
51 51
                  {% for hour in form.time.children %}
52 52
                  <div class="dropdown-item custom-dropdown-item">
53 53
                    {{ form_widget(hour, {attr: {class: 'd-none'}}) }}
......
62 62
                <button type="button" class="btn dropdown-toggle font-weight-bold" id="dropdownMenuButtonDataset" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
63 63
                  Vyberte datovou sadu
64 64
                </button>
65
                <div id="dataset-dropdown" class="dropdown-menu" aria-labelledby="dropdownMenuButtonDataset">
65
                <div id="dropdown-dataset" class="dropdown-menu" aria-labelledby="dropdownMenuButtonDataset">
66 66
                  {% for dataset in form.type.children %}
67 67
                  <div class="dropdown-item custom-dropdown-item">
68 68
                    <div class="custom-control custom-checkbox custom-checkbox-{{dataset.vars.value}}">
......
84 84
            <li class="nav-item">
85 85
              {{ form_widget(form.submit,
86 86
                {
87
                  'name' : '',
88
                  'label' : '',
89 87
                  'type' : 'submit',
88
                  'name' : '',
90 89
                  'id' : 'btn-update-heatmap',
91 90
                  'attr' : {
92 91
                    'class': 'btn btn-secondary'
......
126 125
        <div class="time hour-0" id="timeline">0:00</div>
127 126

  
128 127
        {% for i in 0..23 %}
129
        <div class="hour"></div>
128
        <div class="hour" title="{{ i }}:00" onclick="changeHour('{{ i }}')"></div>
130 129
        {% endfor %}
131 130
        <div class="end-dot"></div>
132 131
      </div>
......
138 137
{% endblock %}
139 138

  
140 139
{% block javascripts %}
141

  
142 140
    <script src="{{ asset('js/vendor/jquery-3.4.1.min.js') }}"></script>
143 141
    <script src="{{ asset('js/vendor/bootstrap.min.js') }}"></script>
144 142
    <script src="{{ asset('js/vendor/bootstrap-datepicker.min.js') }}"></script>
......
147 145
    <script src="{{ asset('js/vendor/leaflet-heat.js') }}"></script>
148 146
    <script src="{{ asset('js/zcu-heatmap.js') }}"></script>
149 147
    <script>
150
        initDatepicker("{{ path('dates') }}");
148
      initDatepicker("{{ path('dates') }}");
149
      initLocationsMenu();
150
      initMap();
151

  
152
      $(document).ready(function() {
153
        onDocumentReady();
154
        checkDataSetsAvailability("{{ path('available') }}")
155
        {% if submitted %}
156
        loadCurrentTimeHeatmap("{{ path('opendata') }}", "{{ path('positions') }}");
157
        {% endif %}
158
      });
159
      
160
      $(window).resize(function() {
151 161
        initLocationsMenu();
152
        initMap();
153

  
154
        $(document).ready(function() {
155
          onDocumentReady();
156
          checkDataSetsAvailability("{{ path('available') }}")
157
          {% if submitted %}
158
          loadCurrentTimeHeatmap("{{ path('opendata') }}", "{{ path('positions') }}");
159
          {% endif %}
160
        });
161
        
162
        $(window).resize(function() {
163
          initLocationsMenu();
164
        });
162
      });
165 163
  </script>
166

  
167 164
{% endblock %}
168 165

  
169 166
{% block style %}
170
  <style type="text/css">
171
    {% for dataset_name, dataset_color in dataset_colors %}
172
      .custom-control-input-{{ dataset_name }}:focus~.custom-control-label::before {
173
        border-color: {{ dataset_color }} !important;
174
        box-shadow: 0 0 0 0.2rem rgba(192,192,192, 0.4) !important;
175
      }
176

  
177
      .custom-control-input-{{ dataset_name }}:checked~.custom-control-label::before {
178
        border-color: {{ dataset_color }} !important;
179
        background-color: {{ dataset_color }} !important;
180
      }
181

  
182
      .custom-control-input-{{ dataset_name }}:focus:not(:checked)~.custom-control-label::before {
183
        border-color: {{ dataset_color }} !important;
184
      }
185

  
186
      .custom-control-input-{{ dataset_name }}:not(:disabled):active~.custom-control-label::before {
187
        background-color: {{ dataset_color }} !important;
188
        border-color: {{ dataset_color }} !important;
189
      }
190

  
191
      .popup-{{ dataset_name }} > .leaflet-popup-content-wrapper, .popup-{{ dataset_name }} .leaflet-popup-tip {
192
        background-color: {{ dataset_color }} !important;
193
      }
194
    {% endfor %}
195
  </style>
167
<style type="text/css">
168
{% for dataset_name, dataset_color in dataset_colors %}
169
    .custom-control-input-{{ dataset_name }}:focus~.custom-control-label::before {
170
      border-color: {{ dataset_color }} !important;
171
      box-shadow: 0 0 0 0.2rem rgba(192,192,192, 0.4) !important;
172
    }
173

  
174
    .custom-control-input-{{ dataset_name }}:checked~.custom-control-label::before {
175
      border-color: {{ dataset_color }} !important;
176
      background-color: {{ dataset_color }} !important;
177
    }
178

  
179
    .custom-control-input-{{ dataset_name }}:focus:not(:checked)~.custom-control-label::before {
180
      border-color: {{ dataset_color }} !important;
181
    }
182

  
183
    .custom-control-input-{{ dataset_name }}:not(:disabled):active~.custom-control-label::before {
184
      background-color: {{ dataset_color }} !important;
185
      border-color: {{ dataset_color }} !important;
186
    }
187

  
188
    .popup-{{ dataset_name }} > .leaflet-popup-content-wrapper, .popup-{{ dataset_name }} .leaflet-popup-tip {
189
      background-color: {{ dataset_color }} !important;
190
    }
191
{% endfor %}
192
</style>
196 193
{% endblock %}

Také k dispozici: Unified diff