From c368b68297289b0978463f3e079d721e7707985f Mon Sep 17 00:00:00 2001 From: Amon Date: Wed, 15 Apr 2020 19:09:27 +0200 Subject: [PATCH 1/3] Study types can be hidden/shown --- nginx/covid_website/assets/css/style.css | 9 + .../covid_website/assets/js/cumulativePlot.js | 10 +- nginx/covid_website/assets/js/map.js | 421 ++++++++++-------- .../assets/js/time-dimension-by-type.js | 59 +++ nginx/covid_website/clinical_trials.html | 1 + 5 files changed, 317 insertions(+), 183 deletions(-) create mode 100644 nginx/covid_website/assets/js/time-dimension-by-type.js diff --git a/nginx/covid_website/assets/css/style.css b/nginx/covid_website/assets/css/style.css index 9883eaf..fd32cf2 100644 --- a/nginx/covid_website/assets/css/style.css +++ b/nginx/covid_website/assets/css/style.css @@ -1011,3 +1011,12 @@ header { max-height: 25px !important; max-width: 65px !important; } + +.studyLegend { + cursor: pointer; +} +.studyLegend i { + color: black; + font-style: normal; + padding-left: 3px; +} diff --git a/nginx/covid_website/assets/js/cumulativePlot.js b/nginx/covid_website/assets/js/cumulativePlot.js index ccaa9a9..6e46893 100644 --- a/nginx/covid_website/assets/js/cumulativePlot.js +++ b/nginx/covid_website/assets/js/cumulativePlot.js @@ -156,10 +156,10 @@ function makeCumPlot(geojsonData, cumPlotDiv) { } - console.log(cumFreqATMP); - console.log(cumFreqVaccines); - console.log(cumFreqTradChin); - console.log(cumFreqImpHelpers); + // console.log(cumFreqATMP); + // console.log(cumFreqVaccines); + // console.log(cumFreqTradChin); + // console.log(cumFreqImpHelpers); //---------------------------------------- @@ -320,4 +320,4 @@ function makeCumPlot(geojsonData, cumPlotDiv) { var maxDate = regDates[regDates.length - 1] return maxDate -}; \ No newline at end of file +}; diff --git a/nginx/covid_website/assets/js/map.js b/nginx/covid_website/assets/js/map.js index b6e0063..48bf5dc 100644 --- a/nginx/covid_website/assets/js/map.js +++ b/nginx/covid_website/assets/js/map.js @@ -1,231 +1,296 @@ function loadAllMaps() { - mapDivs = ['map-study-categories'] + mapDivs = ['map-study-categories'] + + for (i = 0; i < mapDivs.length; i++) { + initMap(mapDivs[i]) + } - for (i = 0; i < mapDivs.length; i++) { - initMap(mapDivs[i]) - } - } function initMap(mapDiv) { + window.mapDiv = mapDiv // get current date and format to the right format var currentDate = new Date().toISOString().split('T')[0]; - var map = L.map(mapDiv, { + var map = window.map = L.map(mapDiv, { zoom: 2, minZoom: 1, maxZoom: 12, center: [0.0, 0.0], timeDimension: true, timeDimensionOptions: { - timeInterval: "2020-01-20/".concat(currentDate), - period: "P1D" + timeInterval: "2020-01-20/".concat(currentDate), + period: "P1D" }, timeDimensionControl: false, timeDimensionControlOptions: { - position: "topright", + position: "topright", } }); - L.tileLayer( 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', { + L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', { attribution: 'Map tiles by Carto, under CC BY 3.0. Data by OpenStreetMap, under ODbL.', - subdomains: ['a','b','c'] - }).addTo( map ); + subdomains: ['a', 'b', 'c'] + }).addTo(map); // load geojson file projectCentroidsUrl = 'assets/data/covid-19-trials.geojson'; - setTimeout(function(){ map.invalidateSize()}, 400); + setTimeout(function () { + map.invalidateSize() + }, 400); var plotDiv = mapDiv.replace('map', 'plot'); var plotCumDiv = mapDiv.replace('map', 'cumplot'); addGeojsonLayer(map, projectCentroidsUrl, mapDiv, plotDiv, plotCumDiv); - // add custom date format to the time dimension control + // add custom date format to the time dimension control L.Control.TimeDimensionCustom = L.Control.TimeDimension.extend({ - _getDisplayDateFormat: function(date){ - return date.toISOString().split('T')[0]; + _getDisplayDateFormat: function (date) { + return date.toISOString().split('T')[0]; } }); var timeDimensionControl = new L.Control.TimeDimensionCustom({ position: "topright" }); map.addControl(timeDimensionControl); + setMapOverlayers(); +} +function setMapOverlayers() { // add legend if (mapDiv == "map-study-types") { addLegend_studyType(map); } else if (mapDiv == "map-study-categories") { addLegend_studyCategory(map); } - + if (window.scale) { + map.removeControl(scale); + } // add scale bar - var scale = L.control.scale( - { - 'imperial': false, - 'updateWhenIdle': true - } - ); - scale.addTo(map); + window.scale = L.control.scale({ + 'imperial': false, + 'updateWhenIdle': true + }); + scale.addTo(map); + if (window.logo) { + map.removeControl(logo); + } // add HeiGIT logo - var logo = L.control({position: 'bottomleft'}); - logo.onAdd = function(map){ + window.logo = L.control({ + position: 'bottomleft' + }); + logo.onAdd = function (map) { var div = L.DomUtil.create('div', 'logoContainer'); - div.innerHTML= ""; + div.innerHTML = ""; return div; } - logo.addTo(map); - + logo.addTo(window.map); } function addLegend_studyType(map) { - legend = L.control({position: 'bottomleft'}); - legend.onAdd = function (map) { - var div = L.DomUtil.create('div', 'info legend') - div.innerHTML += 'Observational Study
' - div.innerHTML += 'Interventional Study
' - div.innerHTML += 'Other
' - return div; + if (window.legendByType) { + map.removeControl(legendByType); + } + legendByType = L.control({ + position: 'bottomleft' + }); + legendByType.onAdd = function (map) { + var div = L.DomUtil.create('div', 'info legend') + div.innerHTML += 'Observational Study
' + div.innerHTML += 'Interventional Study
' + div.innerHTML += 'Other
' + return div; }; - legend.addTo(map); + legendByType.addTo(map); } function addLegend_studyCategory(map) { - legend = L.control({position: 'bottomleft'}); - legend.onAdd = function (map) { - var div = L.DomUtil.create('div', 'info legend') - div.innerHTML += 'Diagnosis
' - div.innerHTML += 'Disease understanding
' - div.innerHTML += 'Therapeutic stategies
' - div.innerHTML += 'Drugs
' - div.innerHTML += 'Advanced therapy medicinal products
' - div.innerHTML += 'Vaccines
' - div.innerHTML += 'Traditional Chinese medicine
' - div.innerHTML += 'Impact on helpers
' - //div.innerHTML += 'Epidemiological Study
' - div.innerHTML += 'Other
' - return div; + if (window.legendByCategory) { + map.removeControl(legendByCategory); + } + legendByCategory = L.control({ + position: 'bottomleft' + }); + legendByCategory.onAdd = function (map) { + var div = L.DomUtil.create('div', 'info legend') + div.innerHTML += 'Study types (click to hide/show)

' + div.innerHTML += `${typeVisible('diagnosis')}Diagnosis
` + div.innerHTML += `${typeVisible('understanding')}Disease understanding
` + div.innerHTML += `${typeVisible('management')}Therapeutic stategies
` + div.innerHTML += `${typeVisible('drugs')}Drugs
` + div.innerHTML += `${typeVisible('ATMP')}Advanced therapy medicinal products
` + div.innerHTML += `${typeVisible('vaccine')}Vaccines
` + div.innerHTML += `${typeVisible('traditional chinese medicine')}Traditional Chinese medicine
` + div.innerHTML += `${typeVisible('impact on the helpers')}Impact on helpers
` + div.innerHTML += `${typeVisible('other')}Other
` + return div; }; - legend.addTo(map); + legendByCategory.addTo(map); +} + +function typeVisible (type) { + if (window.timeDimension_layer !== undefined) { + let visible = timeDimension_layer.disabledTypes.indexOf(type) > -1; + return visible ? '' : 'X'; + } + return 'X'; +} + +function toggleType (type) { + timeDimension_layer.disabledTypes = timeDimension_layer.disabledTypes || []; + const typeIndex = timeDimension_layer.disabledTypes.indexOf(type); + if (typeIndex > -1) { + timeDimension_layer.disabledTypes.splice(typeIndex, 1); + } else { + timeDimension_layer.disabledTypes.push(type); + } + timeDimension_layer._update(type); + setMapOverlayers(); } function set_style_studyType(feature) { - if (feature.properties.study_type == "Observational study") { - return { - fillColor: 'orange', color:'black', radius: 7, - fillOpacity: 0.5} - } else if (feature.properties.study_type == "Interventional study") { - return { - fillColor: 'blue', - radius: 7} - } else { - return { - fillColor: 'grey', - radius: 7} - } + if (feature.properties.study_type == "Observational study") { + return { + fillColor: 'orange', + color: 'black', + radius: 7, + fillOpacity: 0.5 + } + } else if (feature.properties.study_type == "Interventional study") { + return { + fillColor: 'blue', + radius: 7 + } + } else { + return { + fillColor: 'grey', + radius: 7 + } + } } function set_style_studyCategory(feature) { - varStrokeOpacity= .7 - if (feature.properties.classification == "drugs") { - return { - fillColor: '#7FC97F', color:'grey', radius: 7, opacity: varStrokeOpacity, - fillOpacity: 0.5} - } else if (feature.properties.classification == "vaccine") { - return { - fillColor: '#BEAED4', - fillOpacity: 0.5, opacity: varStrokeOpacity, - radius: 7} - } else if (feature.properties.classification == "ATMP") { - return { - fillColor: '#FDC086', color:'grey', - fillOpacity: 0.5, opacity: varStrokeOpacity, - radius: 7} - } else if (feature.properties.classification == "impact on the helpers") { - return { - fillColor: '#FFFF99', color:'grey', - fillOpacity: 0.5, opacity: varStrokeOpacity, - radius: 7} - } else if (feature.properties.classification == "management") { - return { - fillColor: '#386CB0', - fillOpacity: 0.5, opacity: varStrokeOpacity, - radius: 7} - } else if (feature.properties.classification == "traditional chinese medicine") { - return { - fillColor: '#F0027F', - fillOpacity: 0.5, opacity: varStrokeOpacity, - radius: 7} - } else if (feature.properties.classification == "diagnosis") { - return { - fillColor: '#1B9E77', - fillOpacity: 0.5, opacity: varStrokeOpacity, - radius: 7} - } else if (feature.properties.classification == "understanding") { - return { - fillColor: '#BF5B17', - fillOpacity: 0.5, opacity: varStrokeOpacity, - radius: 7} - } else { - return { - fillColor: '#666666', - fillOpacity: 0.5, opacity: varStrokeOpacity, - radius: 7} - } + varStrokeOpacity = .7 + if (feature.properties.classification == "drugs") { + return { + fillColor: '#7FC97F', + color: 'grey', + radius: 7, + opacity: varStrokeOpacity, + fillOpacity: 0.5 + } + } else if (feature.properties.classification == "vaccine") { + return { + fillColor: '#BEAED4', + fillOpacity: 0.5, + opacity: varStrokeOpacity, + radius: 7 + } + } else if (feature.properties.classification == "ATMP") { + return { + fillColor: '#FDC086', + color: 'grey', + fillOpacity: 0.5, + opacity: varStrokeOpacity, + radius: 7 + } + } else if (feature.properties.classification == "impact on the helpers") { + return { + fillColor: '#FFFF99', + color: 'grey', + fillOpacity: 0.5, + opacity: varStrokeOpacity, + radius: 7 + } + } else if (feature.properties.classification == "management") { + return { + fillColor: '#386CB0', + fillOpacity: 0.5, + opacity: varStrokeOpacity, + radius: 7 + } + } else if (feature.properties.classification == "traditional chinese medicine") { + return { + fillColor: '#F0027F', + fillOpacity: 0.5, + opacity: varStrokeOpacity, + radius: 7 + } + } else if (feature.properties.classification == "diagnosis") { + return { + fillColor: '#1B9E77', + fillOpacity: 0.5, + opacity: varStrokeOpacity, + radius: 7 + } + } else if (feature.properties.classification == "understanding") { + return { + fillColor: '#BF5B17', + fillOpacity: 0.5, + opacity: varStrokeOpacity, + radius: 7 + } + } else { + return { + fillColor: '#666666', + fillOpacity: 0.5, + opacity: varStrokeOpacity, + radius: 7 + } + } } -function addGeojsonLayer (map, url, mapDiv, plotDiv, cumPlotDiv) { +function addGeojsonLayer(map, url, mapDiv, plotDiv, cumPlotDiv) { var geojsonData = $.ajax({ - url:url, + url: url, dataType: "json", - success: console.log("clinical trials data successfully loaded."), - /*error: function (xhr) { - alert(xhr.statusText) - }*/ + success: console.log("clinical trials data successfully loaded.") }) // Specify that this code should run once the county data request is complete - $.when(geojsonData).done(function() { + $.when(geojsonData).done(function () { // define default point style var geojsonMarker = { - radius: 6, - fillColor: "grey", - color: "white", - weight: 1, - opacity: 1, - fillOpacity: 0.8 + radius: 6, + fillColor: "grey", + color: "white", + weight: 1, + opacity: 1, + fillOpacity: 0.8 }; // create geojson layer if (mapDiv == "map-study-categories") { - // classification layer - layer = L.geoJSON(geojsonData.responseJSON, { - pointToLayer: function (feature, latlng) { - let marker = L.circleMarker(latlng, geojsonMarker); - marker.on("click", function(data) { - circleMarkerClick(data, map) - }); - return marker; - }, - style: set_style_studyCategory + // classification layer + layer = L.geoJSON(geojsonData.responseJSON, { + pointToLayer: function (feature, latlng) { + let marker = L.circleMarker(latlng, geojsonMarker); + marker.on("click", function (data) { + circleMarkerClick(data, map) + }); + return marker; + }, + style: set_style_studyCategory }) } else if (mapDiv == "map-study-types") { - layer = L.geoJSON(geojsonData.responseJSON, { + layer = L.geoJSON(geojsonData.responseJSON, { pointToLayer: function (feature, latlng) { - let marker = L.circleMarker(latlng, geojsonMarker); - marker.on("click", function(data) { - circleMarkerClick(data, map) - }); - return marker; + let marker = L.circleMarker(latlng, geojsonMarker); + marker.on("click", function (data) { + circleMarkerClick(data, map) + }); + return marker; }, style: set_style_studyType }) } - timeDimension_layer = L.timeDimension.layer.geoJson(layer) + timeDimension_layer = L.timeDimension.layer.geoJsonByType(layer); + timeDimension_layer.disabledTypes = [] timeDimension_layer.bindPopup(function (timeDimension_layer) { - // popup with a link to the project page with detailed information - popup = '

'+layer.feature.properties.name+'

' - return popup; + // popup with a link to the project page with detailed information + popup = '

' + layer.feature.properties.name + '

' + return popup; }); timeDimension_layer.addTo(map) @@ -235,7 +300,7 @@ function addGeojsonLayer (map, url, mapDiv, plotDiv, cumPlotDiv) { // add plot only for first map makePlot(geojsonData.responseJSON, plotDiv) maxDate = makeCumPlot(geojsonData.responseJSON, cumPlotDiv) - console.log(maxDate) + // console.log(maxDate) // populate table var tableDivID = 'clinicalTrialsTable' populateDataTable(geojsonData.responseJSON, tableDivID) @@ -247,11 +312,14 @@ function addGeojsonLayer (map, url, mapDiv, plotDiv, cumPlotDiv) { }) } -function circleMarkerClick (event, map) { +function circleMarkerClick(event, map) { let properties = event.target.feature.properties let geometry = event.target.feature.geometry var popup = new L.Popup(); - var center = {lat: geometry.coordinates[1], lng: geometry.coordinates[0]} + var center = { + lat: geometry.coordinates[1], + lng: geometry.coordinates[0] + } var popupContent = ` Name: ${properties.name}
Description: ${properties.description}
@@ -266,56 +334,55 @@ function circleMarkerClick (event, map) { } function populateDataTable(geojsonData, tableDivID) { - var tableRef = document.getElementById(tableDivID).getElementsByTagName('tbody')[0]; + var tableRef = document.getElementById(tableDivID).getElementsByTagName('tbody')[0]; - geojsonData.features.forEach(function(element) { + geojsonData.features.forEach(function (element) { tr = tableRef.insertRow(); td = document.createElement('td') - td.innerHTML = '

'+element.properties.name+'

' + td.innerHTML = '

' + element.properties.name + '

' tr.appendChild(td) td = document.createElement('td') - td.innerHTML = '

'+element.properties.description+'

' + td.innerHTML = '

' + element.properties.description + '

' tr.appendChild(td) td = document.createElement('td') - td.innerHTML = '

'+element.properties.study_type+'

' + td.innerHTML = '

' + element.properties.study_type + '

' tr.appendChild(td) td = document.createElement('td') - td.innerHTML = '

'+element.properties.classification+'

' + td.innerHTML = '

' + element.properties.classification + '

' tr.appendChild(td) td = document.createElement('td') - td.innerHTML = '

'+element.properties.time+'

' + td.innerHTML = '

' + element.properties.time + '

' tr.appendChild(td) td = document.createElement('td') - td.innerHTML = '

'+element.properties.dateEnrollment+'

' + td.innerHTML = '

' + element.properties.dateEnrollment + '

' tr.appendChild(td) td = document.createElement('td') - td.innerHTML = '

'+element.properties.primaryOutcome+'

' + td.innerHTML = '

' + element.properties.primaryOutcome + '

' tr.appendChild(td) }) - $('#'+tableDivID + ' tfoot th').each( function () { + $('#' + tableDivID + ' tfoot th').each(function () { var title = $(this).text(); - $(this).html( '' ); - } ); + $(this).html(''); + }); - var table = $('#'+tableDivID).DataTable({ + var table = $('#' + tableDivID).DataTable({ "scrollX": true, scroller: true - } - ); + }); // Put top scroller $('.dataTables_scrollHead').css({ - 'overflow-x':'scroll' - }).on('scroll', function(e){ + 'overflow-x': 'scroll' + }).on('scroll', function (e) { var scrollBody = $(this).parent().find('.dataTables_scrollBody').get(0); scrollBody.scrollLeft = this.scrollLeft; $(scrollBody).trigger('scroll'); @@ -323,20 +390,18 @@ function populateDataTable(geojsonData, tableDivID) { $('.dataTables_length').addClass('bs-select'); - // Apply the search - table.columns().every( function () { - var that = this; - - $( 'input', this.footer() ).on( 'keyup change clear', function () { - console.log("event") - if ( that.search() !== this.value ) { - that - .search( this.value ) - .draw(); - } - } ); + // Apply the search + table.columns().every(function () { + var that = this; + + $('input', this.footer()).on('keyup change clear', function () { + console.log("event") + if (that.search() !== this.value) { + that + .search(this.value) + .draw(); + } }); + }); }; - - diff --git a/nginx/covid_website/assets/js/time-dimension-by-type.js b/nginx/covid_website/assets/js/time-dimension-by-type.js new file mode 100644 index 0000000..c17cbd4 --- /dev/null +++ b/nginx/covid_website/assets/js/time-dimension-by-type.js @@ -0,0 +1,59 @@ +L.TimeDimension.Layer.GeoJsonByType = L.TimeDimension.Layer.GeoJson.extend({ + + initialize: function (geoJsonLayer, options) { + this.geoJsonLayer = geoJsonLayer + L.TimeDimension.Layer.GeoJson.prototype.initialize.call(this, geoJsonLayer, options); + }, + + /** + * Overwrites the _update method to implement the + * clustering feature to the map items vizualization + */ + _update: function () { + if (!this._map) + return; + if (!this._loaded) { + return; + } + + var maxTime = this._timeDimension.getCurrentTime(), minTime = 0; + + if (this._duration) { + var date = new Date(maxTime); + L.TimeDimension.Util.subtractTimeDuration(date, this._duration, true); + minTime = date.getTime(); + } + + // new coordinates: + var layer = L.geoJson(null, this._baseLayer.options); + var layers = this._baseLayer.getLayers(); + + for (var i = 0, l = layers.length; i < l; i++) { + var feature = this._getFeatureBetweenDates(layers[i].feature, minTime, maxTime); + if (feature && this.disabledTypes.indexOf(feature.properties.classification) === -1) { + layer.addData(feature); + + if (this._addlastPoint && feature.geometry.type == "LineString") { + if (feature.geometry.coordinates.length > 0) { + var properties = feature.properties; + properties.last = true; + let coordinates = feature.geometry.coordinates[feature.geometry.coordinates.length - 1] + layer.addData({ type: 'Feature', properties: properties, geometry: {type: 'Point', coordinates: coordinates }}); + } + } + } + } + + if (this._currentLayer) { + this._map.removeLayer(this._currentLayer); + } + if (layer.getLayers().length) { + layer.addTo(this._map); + this._currentLayer = layer; + } + }, +}); + +L.timeDimension.layer.geoJsonByType = function (geoJsonLayer, options) { + return new L.TimeDimension.Layer.GeoJsonByType(geoJsonLayer, options); +}; diff --git a/nginx/covid_website/clinical_trials.html b/nginx/covid_website/clinical_trials.html index 1455ebf..147b5db 100644 --- a/nginx/covid_website/clinical_trials.html +++ b/nginx/covid_website/clinical_trials.html @@ -41,6 +41,7 @@ crossorigin=""> + -- GitLab From 924212c9c3f75fb44a4b9e7140c8f31008763346 Mon Sep 17 00:00:00 2001 From: Amon Date: Thu, 16 Apr 2020 19:14:36 +0200 Subject: [PATCH 2/3] Implemented toggle category visible and refactored js --- nginx/covid_website/assets/css/style.css | 2 +- nginx/covid_website/assets/js/map.js | 407 ---------------- ...-type.js => time-dimension-by-taxonomy.js} | 3 +- nginx/covid_website/assets/js/trials-map.js | 444 ++++++++++++++++++ nginx/covid_website/clinical_trials.html | 411 ++++++++-------- 5 files changed, 651 insertions(+), 616 deletions(-) delete mode 100644 nginx/covid_website/assets/js/map.js rename nginx/covid_website/assets/js/{time-dimension-by-type.js => time-dimension-by-taxonomy.js} (93%) create mode 100644 nginx/covid_website/assets/js/trials-map.js diff --git a/nginx/covid_website/assets/css/style.css b/nginx/covid_website/assets/css/style.css index fd32cf2..7e236fd 100644 --- a/nginx/covid_website/assets/css/style.css +++ b/nginx/covid_website/assets/css/style.css @@ -1018,5 +1018,5 @@ header { .studyLegend i { color: black; font-style: normal; - padding-left: 3px; + padding-left: 4px; } diff --git a/nginx/covid_website/assets/js/map.js b/nginx/covid_website/assets/js/map.js deleted file mode 100644 index 48bf5dc..0000000 --- a/nginx/covid_website/assets/js/map.js +++ /dev/null @@ -1,407 +0,0 @@ -function loadAllMaps() { - - mapDivs = ['map-study-categories'] - - for (i = 0; i < mapDivs.length; i++) { - initMap(mapDivs[i]) - } - -} - -function initMap(mapDiv) { - window.mapDiv = mapDiv - // get current date and format to the right format - var currentDate = new Date().toISOString().split('T')[0]; - var map = window.map = L.map(mapDiv, { - zoom: 2, - minZoom: 1, - maxZoom: 12, - center: [0.0, 0.0], - timeDimension: true, - timeDimensionOptions: { - timeInterval: "2020-01-20/".concat(currentDate), - period: "P1D" - }, - timeDimensionControl: false, - timeDimensionControlOptions: { - position: "topright", - } - }); - L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', { - attribution: 'Map tiles by
Carto, under CC BY 3.0. Data by OpenStreetMap, under ODbL.', - subdomains: ['a', 'b', 'c'] - }).addTo(map); - - // load geojson file - projectCentroidsUrl = 'assets/data/covid-19-trials.geojson'; - setTimeout(function () { - map.invalidateSize() - }, 400); - var plotDiv = mapDiv.replace('map', 'plot'); - var plotCumDiv = mapDiv.replace('map', 'cumplot'); - addGeojsonLayer(map, projectCentroidsUrl, mapDiv, plotDiv, plotCumDiv); - - // add custom date format to the time dimension control - L.Control.TimeDimensionCustom = L.Control.TimeDimension.extend({ - _getDisplayDateFormat: function (date) { - return date.toISOString().split('T')[0]; - } - }); - var timeDimensionControl = new L.Control.TimeDimensionCustom({ - position: "topright" - }); - map.addControl(timeDimensionControl); - setMapOverlayers(); -} - -function setMapOverlayers() { - // add legend - if (mapDiv == "map-study-types") { - addLegend_studyType(map); - } else if (mapDiv == "map-study-categories") { - addLegend_studyCategory(map); - } - if (window.scale) { - map.removeControl(scale); - } - // add scale bar - window.scale = L.control.scale({ - 'imperial': false, - 'updateWhenIdle': true - }); - scale.addTo(map); - - if (window.logo) { - map.removeControl(logo); - } - // add HeiGIT logo - window.logo = L.control({ - position: 'bottomleft' - }); - logo.onAdd = function (map) { - var div = L.DomUtil.create('div', 'logoContainer'); - div.innerHTML = ""; - return div; - } - logo.addTo(window.map); -} - -function addLegend_studyType(map) { - if (window.legendByType) { - map.removeControl(legendByType); - } - legendByType = L.control({ - position: 'bottomleft' - }); - legendByType.onAdd = function (map) { - var div = L.DomUtil.create('div', 'info legend') - div.innerHTML += 'Observational Study
' - div.innerHTML += 'Interventional Study
' - div.innerHTML += 'Other
' - return div; - }; - legendByType.addTo(map); -} - -function addLegend_studyCategory(map) { - if (window.legendByCategory) { - map.removeControl(legendByCategory); - } - legendByCategory = L.control({ - position: 'bottomleft' - }); - legendByCategory.onAdd = function (map) { - var div = L.DomUtil.create('div', 'info legend') - div.innerHTML += 'Study types (click to hide/show)

' - div.innerHTML += `${typeVisible('diagnosis')}Diagnosis
` - div.innerHTML += `${typeVisible('understanding')}Disease understanding
` - div.innerHTML += `${typeVisible('management')}Therapeutic stategies
` - div.innerHTML += `${typeVisible('drugs')}Drugs
` - div.innerHTML += `${typeVisible('ATMP')}Advanced therapy medicinal products
` - div.innerHTML += `${typeVisible('vaccine')}Vaccines
` - div.innerHTML += `${typeVisible('traditional chinese medicine')}Traditional Chinese medicine
` - div.innerHTML += `${typeVisible('impact on the helpers')}Impact on helpers
` - div.innerHTML += `${typeVisible('other')}Other
` - return div; - }; - legendByCategory.addTo(map); -} - -function typeVisible (type) { - if (window.timeDimension_layer !== undefined) { - let visible = timeDimension_layer.disabledTypes.indexOf(type) > -1; - return visible ? '' : 'X'; - } - return 'X'; -} - -function toggleType (type) { - timeDimension_layer.disabledTypes = timeDimension_layer.disabledTypes || []; - const typeIndex = timeDimension_layer.disabledTypes.indexOf(type); - if (typeIndex > -1) { - timeDimension_layer.disabledTypes.splice(typeIndex, 1); - } else { - timeDimension_layer.disabledTypes.push(type); - } - timeDimension_layer._update(type); - setMapOverlayers(); -} - -function set_style_studyType(feature) { - if (feature.properties.study_type == "Observational study") { - return { - fillColor: 'orange', - color: 'black', - radius: 7, - fillOpacity: 0.5 - } - } else if (feature.properties.study_type == "Interventional study") { - return { - fillColor: 'blue', - radius: 7 - } - } else { - return { - fillColor: 'grey', - radius: 7 - } - } -} - - -function set_style_studyCategory(feature) { - varStrokeOpacity = .7 - if (feature.properties.classification == "drugs") { - return { - fillColor: '#7FC97F', - color: 'grey', - radius: 7, - opacity: varStrokeOpacity, - fillOpacity: 0.5 - } - } else if (feature.properties.classification == "vaccine") { - return { - fillColor: '#BEAED4', - fillOpacity: 0.5, - opacity: varStrokeOpacity, - radius: 7 - } - } else if (feature.properties.classification == "ATMP") { - return { - fillColor: '#FDC086', - color: 'grey', - fillOpacity: 0.5, - opacity: varStrokeOpacity, - radius: 7 - } - } else if (feature.properties.classification == "impact on the helpers") { - return { - fillColor: '#FFFF99', - color: 'grey', - fillOpacity: 0.5, - opacity: varStrokeOpacity, - radius: 7 - } - } else if (feature.properties.classification == "management") { - return { - fillColor: '#386CB0', - fillOpacity: 0.5, - opacity: varStrokeOpacity, - radius: 7 - } - } else if (feature.properties.classification == "traditional chinese medicine") { - return { - fillColor: '#F0027F', - fillOpacity: 0.5, - opacity: varStrokeOpacity, - radius: 7 - } - } else if (feature.properties.classification == "diagnosis") { - return { - fillColor: '#1B9E77', - fillOpacity: 0.5, - opacity: varStrokeOpacity, - radius: 7 - } - } else if (feature.properties.classification == "understanding") { - return { - fillColor: '#BF5B17', - fillOpacity: 0.5, - opacity: varStrokeOpacity, - radius: 7 - } - } else { - return { - fillColor: '#666666', - fillOpacity: 0.5, - opacity: varStrokeOpacity, - radius: 7 - } - } -} - - -function addGeojsonLayer(map, url, mapDiv, plotDiv, cumPlotDiv) { - var geojsonData = $.ajax({ - url: url, - dataType: "json", - success: console.log("clinical trials data successfully loaded.") - }) - // Specify that this code should run once the county data request is complete - $.when(geojsonData).done(function () { - - // define default point style - var geojsonMarker = { - radius: 6, - fillColor: "grey", - color: "white", - weight: 1, - opacity: 1, - fillOpacity: 0.8 - }; - - // create geojson layer - if (mapDiv == "map-study-categories") { - // classification layer - layer = L.geoJSON(geojsonData.responseJSON, { - pointToLayer: function (feature, latlng) { - let marker = L.circleMarker(latlng, geojsonMarker); - marker.on("click", function (data) { - circleMarkerClick(data, map) - }); - return marker; - }, - style: set_style_studyCategory - }) - } else if (mapDiv == "map-study-types") { - layer = L.geoJSON(geojsonData.responseJSON, { - pointToLayer: function (feature, latlng) { - let marker = L.circleMarker(latlng, geojsonMarker); - marker.on("click", function (data) { - circleMarkerClick(data, map) - }); - return marker; - }, - style: set_style_studyType - }) - } - timeDimension_layer = L.timeDimension.layer.geoJsonByType(layer); - timeDimension_layer.disabledTypes = [] - timeDimension_layer.bindPopup(function (timeDimension_layer) { - // popup with a link to the project page with detailed information - popup = '

' + layer.feature.properties.name + '

' - return popup; - }); - timeDimension_layer.addTo(map) - - // fit to layer extent - map.fitBounds(layer.getBounds()); - - // add plot only for first map - makePlot(geojsonData.responseJSON, plotDiv) - maxDate = makeCumPlot(geojsonData.responseJSON, cumPlotDiv) - // console.log(maxDate) - // populate table - var tableDivID = 'clinicalTrialsTable' - populateDataTable(geojsonData.responseJSON, tableDivID) - - // add timestamp of date to text - document.getElementById("last_update").innerHTML = maxDate - document.getElementById("trials_count").innerHTML = geojsonData.responseJSON.features.length - - }) -} - -function circleMarkerClick(event, map) { - let properties = event.target.feature.properties - let geometry = event.target.feature.geometry - var popup = new L.Popup(); - var center = { - lat: geometry.coordinates[1], - lng: geometry.coordinates[0] - } - var popupContent = ` - Name: ${properties.name}
- Description: ${properties.description}
- Study type: ${properties.study_type}
- Classification: ${properties.classification}
- Registration Date: ${properties.time}
- Date Enrollment: ${properties.dateEnrollment}
- Contact: ${properties.contactEmail}`; - popup.setLatLng(center); - popup.setContent(popupContent); - map.openPopup(popup); -} - -function populateDataTable(geojsonData, tableDivID) { - var tableRef = document.getElementById(tableDivID).getElementsByTagName('tbody')[0]; - - geojsonData.features.forEach(function (element) { - - tr = tableRef.insertRow(); - - td = document.createElement('td') - td.innerHTML = '

' + element.properties.name + '

' - tr.appendChild(td) - - td = document.createElement('td') - td.innerHTML = '

' + element.properties.description + '

' - tr.appendChild(td) - - td = document.createElement('td') - td.innerHTML = '

' + element.properties.study_type + '

' - tr.appendChild(td) - - td = document.createElement('td') - td.innerHTML = '

' + element.properties.classification + '

' - tr.appendChild(td) - - td = document.createElement('td') - td.innerHTML = '

' + element.properties.time + '

' - tr.appendChild(td) - - td = document.createElement('td') - td.innerHTML = '

' + element.properties.dateEnrollment + '

' - tr.appendChild(td) - - td = document.createElement('td') - td.innerHTML = '

' + element.properties.primaryOutcome + '

' - tr.appendChild(td) - }) - - $('#' + tableDivID + ' tfoot th').each(function () { - var title = $(this).text(); - $(this).html(''); - }); - - var table = $('#' + tableDivID).DataTable({ - "scrollX": true, - scroller: true - }); - - // Put top scroller - $('.dataTables_scrollHead').css({ - 'overflow-x': 'scroll' - }).on('scroll', function (e) { - var scrollBody = $(this).parent().find('.dataTables_scrollBody').get(0); - scrollBody.scrollLeft = this.scrollLeft; - $(scrollBody).trigger('scroll'); - }); - - $('.dataTables_length').addClass('bs-select'); - - // Apply the search - table.columns().every(function () { - var that = this; - - $('input', this.footer()).on('keyup change clear', function () { - console.log("event") - if (that.search() !== this.value) { - that - .search(this.value) - .draw(); - } - }); - }); - -}; diff --git a/nginx/covid_website/assets/js/time-dimension-by-type.js b/nginx/covid_website/assets/js/time-dimension-by-taxonomy.js similarity index 93% rename from nginx/covid_website/assets/js/time-dimension-by-type.js rename to nginx/covid_website/assets/js/time-dimension-by-taxonomy.js index c17cbd4..7d365a6 100644 --- a/nginx/covid_website/assets/js/time-dimension-by-type.js +++ b/nginx/covid_website/assets/js/time-dimension-by-taxonomy.js @@ -2,6 +2,7 @@ L.TimeDimension.Layer.GeoJsonByType = L.TimeDimension.Layer.GeoJson.extend({ initialize: function (geoJsonLayer, options) { this.geoJsonLayer = geoJsonLayer + this.disabledTaxonomies = [] L.TimeDimension.Layer.GeoJson.prototype.initialize.call(this, geoJsonLayer, options); }, @@ -30,7 +31,7 @@ L.TimeDimension.Layer.GeoJsonByType = L.TimeDimension.Layer.GeoJson.extend({ for (var i = 0, l = layers.length; i < l; i++) { var feature = this._getFeatureBetweenDates(layers[i].feature, minTime, maxTime); - if (feature && this.disabledTypes.indexOf(feature.properties.classification) === -1) { + if (feature && this.disabledTaxonomies.indexOf(feature.properties.classification) === -1) { layer.addData(feature); if (this._addlastPoint && feature.geometry.type == "LineString") { diff --git a/nginx/covid_website/assets/js/trials-map.js b/nginx/covid_website/assets/js/trials-map.js new file mode 100644 index 0000000..d52a654 --- /dev/null +++ b/nginx/covid_website/assets/js/trials-map.js @@ -0,0 +1,444 @@ +/** + * TrialsMap class + * Creates a leaft let map instance, makePlot and populate table + */ +class TrialsMap { + + /** + * Constructor of TrialsMap that set the class properties, + * set the taxonomies colors and init that leaflet map + * @param {*} mapEl + * @param {*} trialsEl + * @param {*} options + */ + constructor(mapEl, trialsEl, options= {}) { + this.trialsEl = trialsEl + this.mapEl = mapEl + this.loadByTaxonomy = options.loadByTaxonomy || 'categories' // can be category or type + this.lastUpdateEl = options.lastUpdateEl || 'last_update' + this.trialsCountEl = options.trialsCountEl || 'trials_count' + this.plotEl = options.plotEl || this.mapEl.replace('map', 'plot') + this.cumplotEl = options.cumplotEl || this.mapEl.replace('map', 'cumplot') + this.projectCentroidsUrl = 'assets/data/covid-19-trials.geojson' + this.logoSrc = 'assets/img/logos/heigit_logo.png' + this.tileServiceUrl = 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png' + this.mapAttribution = 'Map tiles by
Carto, under CC BY 3.0. Data by OpenStreetMap, under ODbL.' + + this.studyCategoryColors = [] + this.studyTypeColors = [] + + // Set study taxonomies (type and categories) colors + this.setTaxonomiesColors() + this.initMap() + } + + /** + * Init map component using leaflet and timedimension + * and set the map overlays + */ + initMap = () => { + let mapOptions = this.buildMapOptions() + this.map = L.map(this.mapEl, mapOptions) + L.tileLayer(this.tileServiceUrl, { attribution: this.mapAttribution, subdomains: ['a', 'b', 'c'] }).addTo(this.map) + + let that = this + // load geojson file + setTimeout(function () { that.map.invalidateSize() }, 400) + this.addGeojsonLayer() + + // add custom date format to the time dimension control + L.Control.TimeDimensionCustom = L.Control.TimeDimension.extend({ + _getDisplayDateFormat: function (date) { + return date.toISOString().split('T')[0] + } + }); + var timeDimensionControl = new L.Control.TimeDimensionCustom({ position: "topright" }) + this.map.addControl(timeDimensionControl) + this.setMapOverlayers() + } + + /** + * Build map options object + * @returns {*} options + */ + buildMapOptions = () => { + var currentDate = new Date().toISOString().split('T')[0] + let mapOptions = { + zoom: 2, + minZoom: 1, + maxZoom: 12, + center: [0.0, 0.0], + timeDimension: true, + timeDimensionOptions: { + timeInterval: "2020-01-20/".concat(currentDate), + period: "P1D" }, + timeDimensionControl: false, + timeDimensionControlOptions: { position: "topright"} + } + return mapOptions + } + + /** + * Set the type and categories study colors + * by creating the studyCategoryColors and + * studyTypeColors props + */ + setTaxonomiesColors = () => { + this.studyCategoryColors = { + drugs : '#7FC97F', + vaccine: '#BEAED4', + ATMP: '#FDC086', + 'impact on the helpers': '#FFFF99', + management: '#386CB0', + 'traditional chinese medicine': '#F0027F', + diagnosis: '#1B9E77', + understanding: '#BF5B17', + other: '#666666' + } + this.studyTypeColors = { + 'Observational study': 'orange', + 'Interventional study': 'blue', + } + } + + /** + * Set map layers (legends, scale and logo) + * if the layers already exist, remove them + * and add again, refreshing the data + */ + setMapOverlayers = () => { + // add legend + if (this.loadByTaxonomy=== "types") { + this.addLegendStudyType(); + } else if (this.loadByTaxonomy== "categories") { + this.addLegendStudyCategory(); + } + if (this.scale) { + this.map.removeControl(this.scale) + } + // add scale bar + this.scale = L.control.scale({'imperial': false, 'updateWhenIdle': true }); + this.scale.addTo(this.map) + + if (this.logo) { + this.map.removeControl(this.logo) + } + // add HeiGIT logo + this.logo = L.control({ position: 'bottomleft' }) + let that = this + this.logo.onAdd = function () { + var logoContainer = L.DomUtil.create('div', 'logoContainer') + logoContainer.innerHTML = `` + return logoContainer + } + this.logo.addTo(this.map) + } + + /** + * Add the study type legend overlayer + */ + addLegendStudyType = () => { + // If it was already loaded before, remove before loading again + if (this.legendByType) { + this.map.removeControl(legendByType) + } + this.legendByType = L.control({ position: 'bottomleft' }) + let that = this + this.legendByType.onAdd = function () { + return that.buildStudyTypesFragment() + }; + this.legendByType.addTo(this.map); + } + + /** + * Build types legend html fragment + * @returns {DocumentFragment} fragment + */ + buildStudyTypesFragment = () => { + var typesFragment = L.DomUtil.create('div', 'info legend') + typesFragment.innerHTML += 'Study types (click to hide/show)

' + let fragment = new DocumentFragment() + + for (let type in this.studyTypeColors) { + // Create span element for each category + let spanEl = document.createElement('span') + spanEl.innerText = type.charAt(0).toUpperCase() + type.slice(1) + spanEl.className = 'studyLegend' + spanEl.title = 'Click to hide/show' + + // Create i element to be appended to each span + let iEl = document.createElement('i') + iEl.style.background = this.studyTypeColors[type] + + // Append i element to the span + spanEl.appendChild(iEl); + + // Append span and a line break + fragment.appendChild(spanEl); + fragment.appendChild(document.createElement('br')) + } + + // Append the types listing to the legend + typesFragment.appendChild(fragment) + return typesFragment + } + + /** + * Add study cateogires legend overlayer + * with toggle cagetegory visibility function + */ + addLegendStudyCategory = () => { + // If it was already loaded before, remove before loading again + if (this.legendByCategory) { + this.map.removeControl(this.legendByCategory) + } + this.legendByCategory = L.control({ position: 'bottomleft' }) + let that = this + this.legendByCategory.onAdd = function () { + return that.buildCategoriesLegendFragment() + } + this.legendByCategory.addTo(this.map) + } + + /** + * Build categories legend html fragment + * @returns {DocumentFragment} fragment + */ + buildCategoriesLegendFragment = () => { + var categoriesFragment = L.DomUtil.create('div', 'info legend') + categoriesFragment.innerHTML += 'Study categories (click to hide/show)

' + let fragment = new DocumentFragment(); + + for (let category in this.studyCategoryColors) { + // Create span element for each category + let spanEl = document.createElement('span') + spanEl.innerText = category.charAt(0).toUpperCase() + category.slice(1) + spanEl.className = 'studyLegend' + spanEl.title = 'Click to hide/show' + spanEl.onclick = () => { this.toggleCategoryVisibility(category) } + + // Create i element to be appended to each span + let iEl = document.createElement('i') + iEl.style.background = this.studyCategoryColors[category] + iEl.innerText = this.timeDimension_layer && this.timeDimension_layer.disabledTaxonomies.indexOf(category) > -1 ? '' : 'X' + + // Append i element to the span + spanEl.appendChild(iEl); + + // Append span and a line break + fragment.appendChild(spanEl); + fragment.appendChild(document.createElement('br')) + } + + // Append the categories listing/toggle to the legend + categoriesFragment.appendChild(fragment) + return categoriesFragment + } + + /** + * Toggle the visibility of a given category + * when run, the function will update the studies loaded + * on the map and also refresh the map overlays + * in order to update the given category overlay status (visible or not) + * @param {String} category + */ + toggleCategoryVisibility = (category) => { + let catIndex = this.timeDimension_layer.disabledTaxonomies.indexOf(category) + if (catIndex > -1) { + this.timeDimension_layer.disabledTaxonomies.splice(catIndex, 1) + } else { + this.timeDimension_layer.disabledTaxonomies.push(category) + } + this.timeDimension_layer._update(category) + this.setMapOverlayers() + } + + /** + * Buind and return the style object for a given study + * type circle marker + * @param {*} feature + * @return {*} style + */ + getStyleStudyType = (feature) => { + let type = feature.properties.study_type + + let style = { fillColor: 'grey', color: 'black', radius: 7, fillOpacity: 0.5, weight: 1, opacity: 1 } + if (this.studyTypeColors[type]) { + style.fillColor = this.studyTypeColors[type] + } + return style + } + + /** + * Buind and return the style object for a given study + * category circle marker + * @param {*} feature + * @return {*} style + */ + getStyleStudyCategory = (feature) => { + let category = feature.properties.classification + + let style = { fillColor: '#666666', color: 'grey', radius: 7, fillOpacity: 0.5, weight: 1, opacity: .7, } + if (this.studyCategoryColors[category]) { + style.fillColor = this.studyCategoryColors[category] + } + + return style + } + + /** + * Add the geojson layer after loading the geojson data from projectCentroidsUrl + */ + addGeojsonLayer = () => { + let that = this + var geojsonData = $.ajax({ url: this.projectCentroidsUrl, dataType: "json" }) + + // Specify that this code should run once the county data request is complete + $.when(geojsonData).done(function () { + let layer = that.buidGeojsonLayer(geojsonData.responseJSON) + + that.timeDimension_layer = L.timeDimension.layer.geoJsonByType(layer) + // popup with a link to the project page with detailed information + that.timeDimension_layer.bindPopup(function () { popup = '

' + layer.feature.properties.name + '

'; return popup; }) + that.timeDimension_layer.addTo(that.map) + + // fit to layer extent + that.map.fitBounds(layer.getBounds()) + + // add plot only for first map + makePlot(geojsonData.responseJSON, this.plotEl) + populateDataTable(geojsonData.responseJSON, that.trialsEl) + + // add timestamp of date to text + document.getElementById(that.lastUpdateEl).innerHTML = makeCumPlot(geojsonData.responseJSON, this.cumplotEl) + document.getElementById(that.trialsCountEl).innerHTML = geojsonData.responseJSON.features.length + }) + } + + /** + * Build geojson layer based on jsonData + * @param {*} jsonData + * @returns {*} layer + */ + buidGeojsonLayer = (jsonData) => { + let layer + let that = this + // create geojson layer + if (this.loadByTaxonomy=== "categories") { + // classification layer + layer = L.geoJSON(jsonData, { + pointToLayer: function (feature, latlng) { + let marker = L.circleMarker(latlng, {}) + marker.on("click", function (data) { that.circleMarkerClick(data, that.map) }) + return marker + }, + style: this.getStyleStudyCategory + }) + } else if (this.loadByTaxonomy== "types") { + layer = L.geoJSON(jsonData, { + pointToLayer: function (feature, latlng) { + let marker = L.circleMarker(latlng, {}); + marker.on("click", function (data) { that.circleMarkerClick(data, that.map) }) + return marker + }, + style: this.getStyleStudyType + }) + } + return layer + } + + /** + * Handle the study marker click + * and show the popup for the given study + * @param event + */ + circleMarkerClick = (event) => { + let properties = event.target.feature.properties + let geometry = event.target.feature.geometry + var popup = new L.Popup() + var center = { + lat: geometry.coordinates[1], + lng: geometry.coordinates[0] + } + var popupContent = ` + Name: ${properties.name}
+ Description: ${properties.description}
+ Study type: ${properties.study_type}
+ Classification: ${properties.classification}
+ Registration Date: ${properties.time}
+ Date Enrollment: ${properties.dateEnrollment}
+ Contact: ${properties.contactEmail}`; + popup.setLatLng(center); + popup.setContent(popupContent) + this.map.openPopup(popup) + } + + /** + * Populate the datatable using the geojsonData into the tableEl + * and set table scroll and search functions + * @param {*} geojsonData + * @param {String} tableEl + */ + populateDataTable = (geojsonData, tableEl) => { + var tableRef = document.getElementById(tableEl).getElementsByTagName('tbody')[0] + + geojsonData.features.forEach(function (element) { + tr = tableRef.insertRow() + + td = document.createElement('td') + td.innerHTML = '

' + element.properties.name + '

' + tr.appendChild(td) + + td = document.createElement('td') + td.innerHTML = '

' + element.properties.description + '

' + tr.appendChild(td) + + td = document.createElement('td') + td.innerHTML = '

' + element.properties.study_type + '

' + tr.appendChild(td) + + td = document.createElement('td') + td.innerHTML = '

' + element.properties.classification + '

' + tr.appendChild(td) + + td = document.createElement('td') + td.innerHTML = '

' + element.properties.time + '

' + tr.appendChild(td) + + td = document.createElement('td') + td.innerHTML = '

' + element.properties.dateEnrollment + '

' + tr.appendChild(td) + + td = document.createElement('td') + td.innerHTML = '

' + element.properties.primaryOutcome + '

' + tr.appendChild(td) + }) + + $('#' + tableEl + ' tfoot th').each(function () { + var title = $(this).text(); + $(this).html('') + }) + + var table = $('#' + tableEl).DataTable({ "scrollX": true, scroller: true }) + + // Put top scroller + $('.dataTables_scrollHead').css({ 'overflow-x': 'scroll' }).on('scroll', function (e) { + var scrollBody = $(this).parent().find('.dataTables_scrollBody').get(0) + scrollBody.scrollLeft = this.scrollLeft + $(scrollBody).trigger('scroll') + }) + + $('.dataTables_length').addClass('bs-select') + + // Apply the search + table.columns().every(function () { + var that = this + $('input', this.footer()).on('keyup change clear', function () { + console.log("event") + if (that.search() !== this.value) { + that.search(this.value).draw() + } + }) + }) + } +} diff --git a/nginx/covid_website/clinical_trials.html b/nginx/covid_website/clinical_trials.html index 147b5db..89cefdc 100644 --- a/nginx/covid_website/clinical_trials.html +++ b/nginx/covid_website/clinical_trials.html @@ -1,225 +1,222 @@ - - - - - Research on Covid-19 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- + +
-
-
-

Mapping COVID-19 Research

-

The "Map of Hope" provides a geographical overview of planned, ongoing and completed clinical trials.

-
-
-
- -
-
-
-

Clinical Trials Map

- -

The information on clinical trials is based on data from the WHO Clinical Trials Search Portal for COVID-19 related clinical trials. The Clinical Trials Search Portal provides access to a central database containing the trial registration data sets provided by many international registries

-

The WHO portal gets updated every Friday by six important registries and every 4 weeks by additional registries. We aim at updating our maps without too much delay.

-

The data shown reflects the WHO portal updated at 03 April 2020 and contains clinical trials.

+
+
+

Mapping COVID-19 Research

+

The "Map of Hope" provides a geographical overview of planned, ongoing and + completed clinical trials.

+
-
- -
-
-
- -
- - -
-
- -
- -
- -

The map shows the clinical trial locations classified by the study category. The time slider allows browsing by the temporal dimension. Only clinical trials that were registered before a specified date are shown. The location of the clinical trial is only accurate to the level of the city and does not identify the institution where the trial took place. Click on an individual study to display more detailed information about the study.

-

-
-
- -
-
-

Cumulative plots by study category. It is possible to switch categories on and off by clicking on the respective legend item. If you hover across the plot area you will see a context menu that allows you to zoom, show data, toogle spike lines and to export the figure.

-

+
+
+
+

Clinical Trials Map

+

The information on clinical trials is based on data from the WHO Clinical Trials Search Portal for COVID-19 related + clinical trials. The Clinical Trials Search Portal provides access to a central database containing the + trial registration data sets provided by many international registries

+

The WHO portal gets updated every Friday by six important registries and every 4 weeks by additional + registries. We aim at updating our maps without too much delay.

+

The data shown reflects the WHO portal updated at 03 April 2020 and + contains clinical trials.

+
+
-
-
- - -
-
-
-
-

Data

-

The following table presents some of the details on the records displayed on the map as offered by the WHO Clinical Trials Search Portal. Horizontal scroll bars allow to access the full content of the table. Follow the links for full detail.

-

Filter options

-

The Search field performs a full text query on all fields. Further search fields at the bottom of the table allow you to filter the table for each column individually.

+
+
+
+
+ +
+
+ +
+
+

The map shows the clinical trial locations classified by the study category. The time slider allows + browsing by the temporal dimension. Only clinical trials that were registered before a specified date are + shown. The location of the clinical trial is only accurate to the level of the city and does not identify + the institution where the trial took place. Click on an individual study to display more detailed + information about the study.

+

+
+
+ +
+
+

Cumulative plots by study category. It is possible to switch categories on and off by clicking on the + respective legend item. If you hover across the plot area you will see a context menu that allows you to + zoom, show data, toogle spike lines and to export the figure.

+

+
-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
TrialIDDescriptionStudy TypeClassificationRegistration dateEnrollment datePrimary outcome
TrialIDDescriptionStudy TypeClassificationRegistration dateEnrollment datePrimary outcome
+
+
+
+
+
+

Data

+

The following table presents some of the details on the records displayed on the map as offered by the WHO Clinical Trials Search Portal. Horizontal scroll bars + allow to access the full content of the table. Follow the links for full detail.

+

Filter options

+

The Search field performs a full text query on all fields. Further search fields at the bottom of + the table allow you to filter the table for each column individually.

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
TrialIDDescriptionStudy TypeClassificationRegistration dateEnrollment datePrimary outcome
TrialIDDescriptionStudy TypeClassificationRegistration dateEnrollment datePrimary outcome
+
-
-
- -
-
-
-

Disclaimer: Trials posted on this search portal are neither endorsed by WHO nor by HeiGIT, but are provided as a service to our users. In no event shall the World Health Organization or HeiGIT be liable for any damages arising from the use of the information linked to in this section. None of the information obtained through use of the services provided should in any way be used in clinical care without consulting a physician or licensed health professional. Neither WHO nor HeiGIT is responsible for the accuracy, completeness and/or use made of the content displayed for any trial record.

-
-
- -
- -
-
-
- -
- - - - - - - - - - - - + + + + + + + + + -- GitLab From 8866735f2d2dcdf997721df5ea35dbee217514b0 Mon Sep 17 00:00:00 2001 From: Amon Date: Wed, 22 Apr 2020 18:21:07 +0200 Subject: [PATCH 3/3] Fixed make plot and populate datatable --- nginx/covid_website/assets/js/trials-map.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/nginx/covid_website/assets/js/trials-map.js b/nginx/covid_website/assets/js/trials-map.js index d52a654..7bb8348 100644 --- a/nginx/covid_website/assets/js/trials-map.js +++ b/nginx/covid_website/assets/js/trials-map.js @@ -306,11 +306,13 @@ class TrialsMap { that.map.fitBounds(layer.getBounds()) // add plot only for first map - makePlot(geojsonData.responseJSON, this.plotEl) - populateDataTable(geojsonData.responseJSON, that.trialsEl) + // makePlot a global function + makePlot(geojsonData.responseJSON, that.plotEl) + + that.populateDataTable(geojsonData.responseJSON, that.trialsEl) // add timestamp of date to text - document.getElementById(that.lastUpdateEl).innerHTML = makeCumPlot(geojsonData.responseJSON, this.cumplotEl) + document.getElementById(that.lastUpdateEl).innerHTML = makeCumPlot(geojsonData.responseJSON, that.cumplotEl) document.getElementById(that.trialsCountEl).innerHTML = geojsonData.responseJSON.features.length }) } @@ -383,9 +385,9 @@ class TrialsMap { var tableRef = document.getElementById(tableEl).getElementsByTagName('tbody')[0] geojsonData.features.forEach(function (element) { - tr = tableRef.insertRow() + let tr = tableRef.insertRow() - td = document.createElement('td') + let td = document.createElement('td') td.innerHTML = '

' + element.properties.name + '

' tr.appendChild(td) -- GitLab