Revize 2f227a6c
Přidáno uživatelem Tomáš Ballák před více než 3 roky(ů)
website/public/js/zcu-heatmap.js | ||
---|---|---|
1 | 1 |
/* global L */ |
2 | 2 |
/* global $ */ |
3 |
|
|
3 | 4 |
var mymap |
4 | 5 |
var heatmapLayer = null |
5 | 6 |
var marksLayer = null |
... | ... | |
10 | 11 |
|
11 | 12 |
var dataSourceRoute |
12 | 13 |
var currentTime |
13 |
var name |
|
14 |
var date |
|
15 | 14 |
|
16 | 15 |
var timer |
17 | 16 |
var isAnimationRunning = false |
18 | 17 |
var data = [] |
19 | 18 |
|
20 | 19 |
var info = [] |
21 |
var currenInfo = 0 |
|
20 |
let currentInfo = 0 |
|
21 |
|
|
22 |
var datasetSelected = [] |
|
22 | 23 |
|
23 |
// holds all instances of markers for bind/unbind popup purpose |
|
24 |
// contains: {key:[L.circle,L.pupup]} |
|
25 |
// key: x and y, x + '' + y string |
|
26 | 24 |
const globalMarkersHolder = {} |
25 |
const datasetColorDict = {} |
|
27 | 26 |
|
27 |
/* const genColor = (datasetNames) => { |
|
28 |
datasetNames.forEach((name) => { |
|
29 |
datasetColorDict[name] = |
|
30 |
}) |
|
31 |
} */ |
|
32 |
const fetchByNameDate = async (baseRoute, name, date, currentTime) => { |
|
33 |
const headers = new Headers() |
|
34 |
const myRequest = new Request(baseRoute + '/' + name + '/' + date + '/' + currentTime, { |
|
35 |
method: 'GET', |
|
36 |
headers: headers |
|
37 |
}) |
|
38 |
const beforeJson = await fetch(myRequest) |
|
39 |
return beforeJson.json() |
|
40 |
} |
|
41 |
const fetchDataSourceMarks = async (positionRoute, datasetName) => { |
|
42 |
const headers = new Headers() |
|
43 |
const myRequest = new Request(positionRoute + '/' + datasetName, { |
|
44 |
method: 'GET', |
|
45 |
headers: headers |
|
46 |
}) |
|
47 |
const beforeJson = await fetch(myRequest) |
|
48 |
return beforeJson.json() |
|
49 |
} |
|
28 | 50 |
// all marker from which popup was removed |
29 | 51 |
// contains: {key:[L.circle,L.pupup]} |
30 | 52 |
// key: x and y, x + '' + y string |
31 | 53 |
let globalMarkersChanged = {} |
32 | 54 |
|
55 |
const genPopUpControlButtons = (currentPage, numPages, onNextClick, onPreviousClick) => ({ |
|
56 |
previousButton: '<button id="previous-info-btn" class="circle-button" onclick="previousInfo()"></button>', |
|
57 |
nextButton: '<button id="next-info-btn" onclick="nextInfo()" class="circle-button next"></button>', |
|
58 |
posInfo: `<div id="count-info">${currentPage} z ${numPages}</div>` |
|
59 |
}) |
|
33 | 60 |
const genPopUpControls = (controls) => { |
34 |
return `<div class="popup-controls">${controls.reduce((sum, item) => sum + item, '')}</div>`
|
|
61 |
return `<div class="popup-controls">${controls ? controls.reduce((sum, item) => sum + item, '') : ''}</div>`
|
|
35 | 62 |
} |
63 |
const multipleDatasetsPopUp = (sum, currentPos, maxPos, datasetName) => { |
|
64 |
const header = `<strong>Dataset a počet:</strong><div id="place-info">${datasetName}</div>` |
|
65 |
const digitInfo = `<div id="number-info"><span id="digit-info">${sum}</span></div>` |
|
66 |
const { previousButton, nextButton, posInfo } = genPopUpControlButtons(currentPos, maxPos) |
|
67 |
return ` |
|
68 |
${header} |
|
69 |
${digitInfo} |
|
70 |
${genPopUpControls([previousButton, posInfo, nextButton])} |
|
71 |
` |
|
72 |
} |
|
73 |
const prepareLayerPopUp = (lat, lng, num, className) => L.popup({ |
|
74 |
autoPan: false, |
|
75 |
className: className |
|
76 |
}).setLatLng([lat / num, lng / num]) |
|
77 |
|
|
36 | 78 |
const genPopUp = (place, number, sum, currentPos, maxPos) => { |
37 | 79 |
const header = `<strong>Zařízení a počet:</strong><div id="place-info">${place}</div>` |
38 | 80 |
const currentNum = `<span id="digit-info">${number}</span>` |
39 | 81 |
// eslint-disable-next-line eqeqeq |
40 | 82 |
const sumNum = `<span id="total-info" style="font-size: large">${(sum && (sum != number)) ? '/' + sum : ''}</span>` |
41 | 83 |
const digitInfo = `<div id="number-info">${currentNum}${sumNum}</div>` |
42 |
let previousButton = '<button id="previous-info-btn" class="circle-button" onclick="previousInfo()"></button>' |
|
43 |
let nextButton = '<button id="next-info-btn" onclick="nextInfo()" class="circle-button next"></button>' |
|
44 |
let posInfo = `<div id="count-info">${currentPos} z ${maxPos}</div>` |
|
45 |
|
|
46 |
if (!sum) { |
|
47 |
previousButton = '' |
|
48 |
nextButton = '' |
|
49 |
posInfo = '' |
|
50 |
} |
|
84 |
const { previousButton, nextButton, posInfo } = genPopUpControlButtons(currentPos, maxPos) |
|
51 | 85 |
return ` |
52 | 86 |
${header} |
53 | 87 |
${digitInfo} |
54 |
${genPopUpControls([previousButton, posInfo, nextButton])}
|
|
88 |
${genPopUpControls(maxPos > 1 ? [previousButton, posInfo, nextButton] : null)}
|
|
55 | 89 |
` |
56 | 90 |
} |
57 | 91 |
/** |
... | ... | |
72 | 106 |
|
73 | 107 |
mymap.on('click', showInfo) |
74 | 108 |
} |
75 |
|
|
109 |
const getInfoLength = () => { |
|
110 |
const infoKeys = Object.keys(info) |
|
111 |
if (infoKeys.length === 1) { |
|
112 |
// return number of records in one dataset (one dataset in area) |
|
113 |
return info[infoKeys[0]].items.length |
|
114 |
} |
|
115 |
// return number of datasets (agregation of all datasets in area) |
|
116 |
return infoKeys.length |
|
117 |
} |
|
118 |
const getElFromObjectInfo = (position) => { |
|
119 |
const keys = Object.keys(info) |
|
120 |
return info[keys[position]] |
|
121 |
} |
|
122 |
const hasInfoMultipleDatasets = () => { |
|
123 |
return Object.keys(info).length > 1 |
|
124 |
} |
|
76 | 125 |
function showInfo (e) { |
77 | 126 |
info = [] |
78 |
currenInfo = 0 |
|
127 |
currentInfo = 0
|
|
79 | 128 |
|
80 | 129 |
// https://wiki.openstreetmap.org/wiki/Zoom_levels |
81 | 130 |
// Todo change to variable - it is used in heatmap init |
82 |
var stile = 40075016.686 * Math.cos(startX) / Math.pow(2, mymap.getZoom()) |
|
83 |
var radius = 25 * stile / 256 |
|
84 |
|
|
85 |
var i = 0 |
|
86 |
var lat = 0 |
|
87 |
var lng = 0 |
|
88 |
|
|
89 |
var total = 0 |
|
90 |
data[currentTime].items.forEach(element => { |
|
91 |
if (e.latlng.distanceTo(new L.LatLng(element.x, element.y)) < radius) { |
|
92 |
lat += element.x |
|
93 |
lng += element.y |
|
94 |
info[i] = { place: element.place, number: element.number } |
|
95 |
total += parseInt(element.number) |
|
96 |
i++ |
|
97 |
} |
|
131 |
const stile = 40075016.686 * Math.cos(startX) / Math.pow(2, mymap.getZoom()) |
|
132 |
const radius = 25 * stile / 256 |
|
133 |
|
|
134 |
let i = 0 |
|
135 |
let lat = 0 |
|
136 |
let lng = 0 |
|
137 |
|
|
138 |
let total = 0 |
|
139 |
|
|
140 |
const datasetsInRadius = {} |
|
141 |
|
|
142 |
Object.keys(data[currentTime]).forEach((key) => { |
|
143 |
const namedData = data[currentTime][key] |
|
144 |
namedData.items.forEach(element => { |
|
145 |
if (e.latlng.distanceTo(new L.LatLng(element.x, element.y)) < radius) { |
|
146 |
lat += element.x |
|
147 |
lng += element.y |
|
148 |
info[i] = { place: element.place, number: element.number, datasetName: key } |
|
149 |
total += parseInt(element.number) |
|
150 |
i++ |
|
151 |
datasetsInRadius[key] = true |
|
152 |
} |
|
153 |
}) |
|
98 | 154 |
}) |
99 | 155 |
|
100 |
if (info.length > 0) { |
|
101 |
const { place, number } = info[currenInfo] |
|
102 |
L.popup({ |
|
103 |
autoPan: false |
|
104 |
}) |
|
105 |
.setLatLng([lat / i, lng / i]) |
|
106 |
.setContent(genPopUp(place, number, total, currenInfo + 1, info.length)) |
|
107 |
.openOn(mymap) |
|
156 |
// Process info for more then one dataset |
|
108 | 157 |
|
109 |
if (info.length === 1) { |
|
158 |
info = info.reduce((acc, item) => { |
|
159 |
if (!acc[item.datasetName]) { |
|
160 |
acc[item.datasetName] = { |
|
161 |
items: [], |
|
162 |
number: 0, |
|
163 |
datasetName: item.datasetName |
|
164 |
} |
|
165 |
} |
|
166 |
acc[item.datasetName].items.push(item) |
|
167 |
acc[item.datasetName].number += Number(item.number) |
|
168 |
return acc |
|
169 |
}, {}) |
|
170 |
|
|
171 |
// There is one dataset |
|
172 |
|
|
173 |
const numDatasets = Object.keys(datasetsInRadius).length |
|
174 |
|
|
175 |
if (!numDatasets) { return } |
|
176 |
|
|
177 |
if (numDatasets === 1) { |
|
178 |
const infoDict = getElFromObjectInfo(0) |
|
179 |
const info_ = infoDict.items |
|
180 |
const { place, number } = info_[currentInfo] |
|
181 |
prepareLayerPopUp(lat, lng, i, `popup-${infoDict.datasetName}`) |
|
182 |
.setContent(genPopUp(place, number, total, currentInfo + 1, info_.length)) |
|
183 |
.openOn(mymap) |
|
184 |
if (info_.length === 1) { |
|
110 | 185 |
$('#previous-info-btn').prop('disabled', true) |
111 | 186 |
$('#next-info-btn').prop('disabled', true) |
112 | 187 |
$('.popup-controls').hide() |
113 | 188 |
} |
189 |
} else { |
|
190 |
const { datasetName, number } = getElFromObjectInfo(currentInfo) |
|
191 |
prepareLayerPopUp(lat, lng, i, `popup-${datasetName}`) |
|
192 |
.setContent(multipleDatasetsPopUp(number, currentInfo + 1, getInfoLength(), datasetName)) |
|
193 |
.openOn(mymap) |
|
114 | 194 |
} |
115 | 195 |
} |
116 | 196 |
|
117 | 197 |
// eslint-disable-next-line no-unused-vars |
118 | 198 |
function previousInfo () { |
119 |
currenInfo = (currenInfo + info.length - 1) % info.length |
|
120 |
displayInfoText() |
|
199 |
const infoLength = getInfoLength() |
|
200 |
const previousCurrentInfo = currentInfo |
|
201 |
currentInfo = (currentInfo + infoLength - 1) % infoLength |
|
202 |
displayInfoText(previousCurrentInfo) |
|
121 | 203 |
} |
122 | 204 |
|
123 | 205 |
// eslint-disable-next-line no-unused-vars |
124 | 206 |
function nextInfo () { |
125 |
currenInfo = (currenInfo + 1) % info.length |
|
126 |
displayInfoText() |
|
207 |
const infoLength = getInfoLength() |
|
208 |
const previousCurrentInfo = currentInfo |
|
209 |
currentInfo = (currentInfo + 1) % infoLength |
|
210 |
displayInfoText(previousCurrentInfo) |
|
127 | 211 |
} |
128 |
|
|
129 |
function displayInfoText () { |
|
130 |
$('#place-info').html(info[currenInfo].place) |
|
131 |
$('#digit-info').html(info[currenInfo].number) |
|
132 |
$('#count-info').html(currenInfo + 1 + ' z ' + info.length) |
|
212 |
function displayInfoText (previousInfoNum) { |
|
213 |
const previousInfo = hasInfoMultipleDatasets() ? getElFromObjectInfo(previousInfoNum) : getElFromObjectInfo(0).items[previousInfoNum] |
|
214 |
const info_ = hasInfoMultipleDatasets() ? getElFromObjectInfo(currentInfo) : getElFromObjectInfo(0).items[currentInfo] |
|
215 |
const infoLength = getInfoLength() |
|
216 |
$('#place-info').html(info_.place ? info_.place : info_.datasetName) |
|
217 |
$('#digit-info').html(info_.number) |
|
218 |
$('#count-info').html(currentInfo + 1 + ' z ' + infoLength) |
|
219 |
$('.leaflet-popup').removeClass(`popup-${previousInfo.datasetName}`) |
|
220 |
$('.leaflet-popup').addClass(`popup-${info_.datasetName}`) |
|
133 | 221 |
} |
134 | 222 |
|
135 | 223 |
// eslint-disable-next-line no-unused-vars |
... | ... | |
178 | 266 |
updateHeaderControls() |
179 | 267 |
changeUrl() |
180 | 268 |
} |
181 |
|
|
269 |
const typeUrlReducer = (accumulator, currentValue) => accumulator + currentValue |
|
182 | 270 |
/** |
183 | 271 |
* Change browser url based on animation step |
184 | 272 |
*/ |
... | ... | |
186 | 274 |
window.history.pushState( |
187 | 275 |
'', |
188 | 276 |
document.title, |
189 |
window.location.origin + window.location.pathname + `?data_set[date]=${$('#date').val()}&data_set[time]=${currentTime}&data_set[type]=${$('#type').children('option:selected').val()}`
|
|
277 |
window.location.origin + window.location.pathname + `?date=${$('#date').val()}&time=${currentTime}${datasetSelected.reduce((acc, current) => acc + '&type[]=' + current, '')}`
|
|
190 | 278 |
) |
191 | 279 |
} |
192 | 280 |
|
... | ... | |
205 | 293 |
* @param {string} positionsRoute route to dataset postitions source |
206 | 294 |
*/ |
207 | 295 |
// eslint-disable-next-line no-unused-vars |
208 |
function loadCurrentTimeHeatmap (opendataRoute, positionsRoute) { |
|
296 |
async function loadCurrentTimeHeatmap (opendataRoute, positionsRoute) {
|
|
209 | 297 |
dataSourceRoute = opendataRoute |
210 | 298 |
data = [] |
211 |
|
|
212 |
name = $('#type').children('option:selected').val()
|
|
213 |
date = $('#date').val() |
|
299 |
const dataSourceMarks = {} |
|
300 |
const allPromises = []
|
|
301 |
const date = $('#date').val()
|
|
214 | 302 |
currentTime = parseInt($('#time').children('option:selected').val()) |
215 | 303 |
setTimeline() |
216 |
$.ajax({ |
|
217 |
type: 'POST', |
|
218 |
url: positionsRoute + '/' + name, |
|
219 |
success: function (result) { |
|
220 |
drawDataSourceMarks(result) |
|
221 |
$.ajax({ |
|
222 |
type: 'POST', |
|
223 |
url: dataSourceRoute + '/' + name + '/' + date + '/' + currentTime, |
|
224 |
success: function (result) { |
|
225 |
data[currentTime] = result |
|
226 |
drawHeatmap(data[currentTime]) |
|
227 |
} |
|
228 |
}) |
|
229 |
} |
|
304 |
data[currentTime] = {} |
|
305 |
const dataSelectedHandler = async (datasetName) => { |
|
306 |
const marks = await fetchDataSourceMarks(positionsRoute, datasetName) |
|
307 |
const datasetData = await fetchByNameDate(dataSourceRoute, datasetName, date, currentTime) |
|
308 |
dataSourceMarks[datasetName] = marks |
|
309 |
data[currentTime][datasetName] = datasetData |
|
310 |
} |
|
311 |
await datasetSelected.forEach((datasetName) => { |
|
312 |
allPromises.push(dataSelectedHandler(datasetName)) |
|
230 | 313 |
}) |
231 |
|
|
232 |
preload(currentTime, 1) |
|
233 |
preload(currentTime, -1) |
|
314 |
Promise.all(allPromises).then( |
|
315 |
() => { |
|
316 |
drawDataSourceMarks(dataSourceMarks) |
|
317 |
drawHeatmap(data[currentTime]) |
|
318 |
preload(currentTime, 1, date) |
|
319 |
preload(currentTime, -1, date) |
|
320 |
} |
|
321 |
) |
|
234 | 322 |
} |
235 | 323 |
|
236 | 324 |
function drawDataSourceMarks (data) { |
... | ... | |
238 | 326 |
L.removeLayer(marksLayer) |
239 | 327 |
} |
240 | 328 |
marksLayer = L.layerGroup() |
241 |
for (var key in data) { |
|
242 |
const { x, y, name } = data[key] |
|
243 |
const pop = |
|
244 |
L.popup({ autoPan: false }) |
|
245 |
.setLatLng([x, y]) |
|
246 |
.setContent(genPopUp(name, 0, 0, 1, 1)) |
|
247 |
const newCircle = |
|
248 |
L.circle([x, y], { radius: 2, fillOpacity: 0.8, color: '#004fb3', fillColor: '#004fb3', bubblingMouseEvents: true }) |
|
249 |
.bindPopup(pop) |
|
250 |
globalMarkersHolder[x + '' + y] = [newCircle, pop] // add new marker to global holders |
|
251 |
marksLayer.addLayer( |
|
252 |
newCircle |
|
253 |
) |
|
254 |
} |
|
329 |
Object.keys(data).forEach((key_) => { |
|
330 |
for (var key in data[key_]) { |
|
331 |
const { x, y, name } = data[key_][key] |
|
332 |
const pop = |
|
333 |
prepareLayerPopUp(x, y, 1, `popup-${key_}`) |
|
334 |
.setContent(genPopUp(name, 0, 0, 1, 1)) |
|
335 |
const newCircle = |
|
336 |
L.circle([x, y], { radius: 2, fillOpacity: 0.8, color: '#004fb3', fillColor: '#004fb3', bubblingMouseEvents: true }) |
|
337 |
.bindPopup(pop) |
|
338 |
globalMarkersHolder[x + '' + y] = [newCircle, pop] // add new marker to global holders |
|
339 |
marksLayer.addLayer( |
|
340 |
newCircle |
|
341 |
) |
|
342 |
} |
|
343 |
}) |
|
255 | 344 |
|
256 | 345 |
marksLayer.setZIndex(-1).addTo(mymap) |
257 | 346 |
} |
258 | 347 |
|
259 |
function preload (time, change) { |
|
260 |
var ntime = time + change |
|
261 |
if (ntime >= 0 && ntime <= 23) { |
|
262 |
$.ajax({ |
|
263 |
type: 'POST', |
|
264 |
url: dataSourceRoute + '/' + name + '/' + date + '/' + ntime, |
|
265 |
success: function (result) { |
|
266 |
data[ntime] = result |
|
267 |
preload(ntime, change) |
|
268 |
} |
|
269 |
}) |
|
348 |
async function preload (time, change, date) { |
|
349 |
for (let nTime = time + change; nTime >= 0 && nTime <= 23; nTime = nTime + change) { |
|
350 |
if (!data[nTime]) { |
|
351 |
data[nTime] = {} |
|
352 |
datasetSelected.forEach(async (datasetName) => { |
|
353 |
data[nTime][datasetName] = await fetchByNameDate(dataSourceRoute, datasetName, date, nTime) |
|
354 |
}) |
|
355 |
} |
|
270 | 356 |
} |
271 | 357 |
} |
272 | 358 |
|
273 |
function drawHeatmap (data) { |
|
359 |
function drawHeatmap (dataRaw) {
|
|
274 | 360 |
// Todo still switched |
275 |
if (data.items != null) { |
|
361 |
const dataDict = dataRaw |
|
362 |
const mergedPoints = [] |
|
363 |
let max = 0 |
|
364 |
Object.keys(dataDict).forEach((key) => { |
|
365 |
const data = dataDict[key] |
|
366 |
max = Math.max(max, data.max) |
|
367 |
if (data != null) { |
|
276 | 368 |
// Bind back popups for markers (we dont know if there is any data for this marker or not) |
277 |
if (Object.keys(globalMarkersChanged).length) { |
|
278 |
Object.keys(globalMarkersChanged).forEach(function (key) { |
|
279 |
globalMarkersChanged[key][0].bindPopup(globalMarkersChanged[key][1]) |
|
280 |
}) |
|
281 |
globalMarkersChanged = {} |
|
282 |
} |
|
283 |
const points = data.items.map((point) => { |
|
284 |
const { x, y, number } = point |
|
285 |
const key = x + '' + y |
|
286 |
const holder = globalMarkersHolder[key] |
|
287 |
if (!globalMarkersChanged[key] && number) { |
|
369 |
if (Object.keys(globalMarkersChanged).length) {
|
|
370 |
Object.keys(globalMarkersChanged).forEach(function (key) {
|
|
371 |
globalMarkersChanged[key][0].bindPopup(globalMarkersChanged[key][1])
|
|
372 |
})
|
|
373 |
globalMarkersChanged = {}
|
|
374 |
}
|
|
375 |
const points = data.items.map((point) => {
|
|
376 |
const { x, y, number } = point
|
|
377 |
const key = x + '' + y
|
|
378 |
const holder = globalMarkersHolder[key]
|
|
379 |
if (!globalMarkersChanged[key] && number) {
|
|
288 | 380 |
// There is data for this marker => unbind popup with zero value |
289 |
holder[0] = holder[0].unbindPopup() |
|
290 |
globalMarkersChanged[key] = holder |
|
381 |
holder[0] = holder[0].unbindPopup() |
|
382 |
globalMarkersChanged[key] = holder |
|
383 |
} |
|
384 |
return [x, y, number] |
|
385 |
}) |
|
386 |
mergedPoints.push(...points) |
|
387 |
} else { |
|
388 |
if (heatmapLayer != null) { |
|
389 |
mymap.removeLayer(heatmapLayer) |
|
291 | 390 |
} |
292 |
return [x, y, number] |
|
293 |
}) |
|
294 |
if (heatmapLayer != null) { |
|
295 |
mymap.removeLayer(heatmapLayer) |
|
296 |
} |
|
297 |
heatmapLayer = L.heatLayer(points, { max: data.max, minOpacity: 0.5, radius: 35, blur: 30 }).addTo(mymap) |
|
298 |
} else { |
|
299 |
if (heatmapLayer != null) { |
|
300 |
mymap.removeLayer(heatmapLayer) |
|
301 | 391 |
} |
392 |
}) |
|
393 |
if (heatmapLayer != null) { |
|
394 |
mymap.removeLayer(heatmapLayer) |
|
395 |
} |
|
396 |
if (mergedPoints.length) { |
|
397 |
heatmapLayer = L.heatLayer(mergedPoints, { max: max, minOpacity: 0.5, radius: 35, blur: 30 }).addTo(mymap) |
|
302 | 398 |
} |
303 |
|
|
304 |
// var heat_01 = ... |
|
305 |
// on background map.addLayer(heat_01) -> map.removeLayer(heat_01); |
|
306 |
// $(.leaflet-heatmap-layer).css('opacity', 'value'); |
|
307 | 399 |
} |
308 | 400 |
|
309 | 401 |
/** |
... | ... | |
322 | 414 |
}) |
323 | 415 |
} |
324 | 416 |
|
325 |
var allOptionsDisabled = false |
|
326 |
|
|
327 | 417 |
function updateAvailableDataSets (available) { |
328 |
var isOptionEnabled = true |
|
329 |
$('#type > option').each(function () { |
|
330 |
if ((this.value in available) === false) { |
|
331 |
$(this).prop('disabled', true) |
|
332 |
$(this).prop('selected', false) |
|
418 |
let leastOneOptionEnabled = false |
|
419 |
// datasetSelected = [] |
|
420 |
$('#dataset-dropdown .dropdown-item').each(function () { |
|
421 |
const input = $(this).find('input') |
|
422 |
const inputVal = input[0].value |
|
423 |
if (!(inputVal in available)) { |
|
424 |
$(this).addClass('disabled') |
|
425 |
$(input).prop('checked', false) |
|
333 | 426 |
} else { |
334 |
$(this).prop('disabled', false) |
|
335 |
if (allOptionsDisabled) { |
|
336 |
$(this).prop('selected', true) |
|
337 |
allOptionsDisabled = false |
|
338 |
} |
|
339 |
isOptionEnabled = false |
|
427 |
leastOneOptionEnabled = true |
|
428 |
$(this).removeClass('disabled') |
|
340 | 429 |
} |
341 | 430 |
}) |
342 |
allOptionsDisabled = isOptionEnabled |
|
343 | 431 |
|
344 |
$('#submit-btn').prop('disabled', isOptionEnabled)
|
|
432 |
$('#submit-btn').prop('disabled', !leastOneOptionEnabled)
|
|
345 | 433 |
} |
346 | 434 |
|
347 | 435 |
function formatDate (date) { |
... | ... | |
403 | 491 |
|
404 | 492 |
$('#date').datepicker('show') |
405 | 493 |
} |
494 |
function onDocumentReady () { |
|
495 |
$('#dataset-dropdown').on('click', function (e) { |
|
496 |
e.stopPropagation() |
|
497 |
}) |
|
498 |
datasetSelected = [] |
|
499 |
$('#dataset-dropdown .dropdown-item').each(function () { |
|
500 |
const input = $(this).find('input') |
|
501 |
const inputVal = input[0].value |
|
502 |
if (input[0].checked) { |
|
503 |
datasetSelected.push(inputVal) |
|
504 |
} |
|
505 |
}) |
|
506 |
$('#submit-btn').prop('name', '') |
|
507 |
} |
Také k dispozici: Unified diff
Feature Re #8156 show all datasets