From 7c7915ea1029874db2e52a295961321cad282d74 Mon Sep 17 00:00:00 2001 From: steps39 Date: Wed, 7 Feb 2024 13:25:52 +0000 Subject: [PATCH] First commit after restructuring from iiipahdataplot.html --- SedimentDataExplorer.html | 139 +++++ SedimentDataExplorer.js | 988 +++++++++++++++++++++++++++++++++ markers/marker-icon-black.png | Bin 0 -> 1523 bytes markers/marker-icon-blue.png | Bin 0 -> 1747 bytes markers/marker-icon-gold.png | Bin 0 -> 1862 bytes markers/marker-icon-green.png | Bin 0 -> 1822 bytes markers/marker-icon-grey.png | Bin 0 -> 1691 bytes markers/marker-icon-orange.png | Bin 0 -> 1862 bytes markers/marker-icon-red.png | Bin 0 -> 1870 bytes markers/marker-icon-violet.png | Bin 0 -> 1859 bytes markers/marker-icon-yellow.png | Bin 0 -> 1862 bytes markers/marker-shadow.png | Bin 0 -> 618 bytes sdeCharts.js | 971 ++++++++++++++++++++++++++++++++ sdeMaps.js | 226 ++++++++ sdeSelections.js | 442 +++++++++++++++ 15 files changed, 2766 insertions(+) create mode 100644 SedimentDataExplorer.html create mode 100644 SedimentDataExplorer.js create mode 100644 markers/marker-icon-black.png create mode 100644 markers/marker-icon-blue.png create mode 100644 markers/marker-icon-gold.png create mode 100644 markers/marker-icon-green.png create mode 100644 markers/marker-icon-grey.png create mode 100644 markers/marker-icon-orange.png create mode 100644 markers/marker-icon-red.png create mode 100644 markers/marker-icon-violet.png create mode 100644 markers/marker-icon-yellow.png create mode 100644 markers/marker-shadow.png create mode 100644 sdeCharts.js create mode 100644 sdeMaps.js create mode 100644 sdeSelections.js diff --git a/SedimentDataExplorer.html b/SedimentDataExplorer.html new file mode 100644 index 0000000..fc676a3 --- /dev/null +++ b/SedimentDataExplorer.html @@ -0,0 +1,139 @@ + + + + + + Sediment Template Data Explorer + + + + +

Sediment Template Data Explorer - v0.20240203

+ Excel files - + + + + + + + +
+ Selection tools - + + + + + + + + +
+ Sheetanmes - + + + + + + + + + + + + + + +
+ +
+ Chart types - + + + + + + + + + + + + +
+ +
+ Location co-ordinate files - + + + + +
+ + Status - + + + + Load - + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SedimentDataExplorer.js b/SedimentDataExplorer.js new file mode 100644 index 0000000..8225926 --- /dev/null +++ b/SedimentDataExplorer.js @@ -0,0 +1,988 @@ + +// import {parse, stringify, toJSON, fromJSON} from 'flatted'; + const autocolors = window['chartjs-plugin-autocolors']; + Chart.register(autocolors); + const annotationPlugin = window['chartjs-plugin-annotation']; + Chart.register(annotationPlugin); + + markerPngs = ['marker-icon-red.png', 'marker-icon-orange.png', 'marker-icon-yellow.png', + 'marker-icon-green.png', 'marker-icon-blue.png', 'marker-icon-violet.png', + 'marker-icon-grey.png', 'marker-icon-gold.png','marker-icon-black.png']; + +// Define the projection for British National Grid (OSGB 1936) + proj4.defs("EPSG:27700", "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +towgs84=446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894 +units=m +no_defs"); + + let lastInstanceNo = 0; + let noInstances = 16; + let chartInstance = []; + let instanceType = []; + let instanceSheet = []; + let highlighted = []; + for (i = 1; i < noInstances; i++) { + chartInstance[i] = null; + instanceType[i] = null; + instanceSheet[i] = null; + } + dataSheetNames = ['Physical Data','Trace metal data','PAH data','PCB data','BDE data','Organotins data','Organochlorine data']; + dataSheetNamesCheckboxes = []; + for (let i = 0; i < dataSheetNames.length; i++) { + dataSheetNamesCheckboxes[i] = dataSheetNames[i].replace(/\s/g, '').toLowerCase(); + } + sheetsToDisplay = {}; + for (i = 0; i < dataSheetNames.length; i++) { + sheetName = dataSheetNames[i]; + sheetsToDisplay[sheetName] = true; + } + subChartNames = ['samplegroup','chemicalgroup','gorhamtest','totalHC','congenertest'] + subsToDisplay = {}; + for (i = 0; i < subChartNames.length; i++) { + subName = subChartNames[i]; + subsToDisplay[sheetName] = true; + } + calcSheetNames = ['Physical Stats','PSA Charts','Metals calcs','PAH calcs','PCB calcs','BDE calcs','Organotin calcs','Organochlorine calcs']; + let map; // Declare map as a global variable + let fred; + let sampleMeasurements = {}; + let selectedSampleMeasurements = {}; + let sampleInfo = {}; + let selectedSampleInfo = {}; + let blankMeasurements = {}; + let namedLocations = {}; + //All actions level mg/kg + const actionLevels = {}; + actionLevels['Trace metal data'] = { + 'Arsenic (As)':[20,100], + 'Cadmium (Cd)': [0.4,5], + 'Chromium (Cr)': [40,400], + 'Copper (Cu)': [40,400], + 'Mercury (Hg)': [0.3,3], + 'Nickel (Ni)': [20,200], + 'Lead (Pb)': [50,500], + 'Zinc (Zn)': [130,800] + }; + actionLevels['Organotins data'] = { + 'Dibutyltine (DBT)': [0.1,1], + 'Tributyltin (TBT)': [0.1,1] + }; + actionLevels['PAH data'] = { + 'Acenapthene': [0.1,0], + 'Acenapthylene': [0.1,0], + 'Anthracene': [0.1,0], + 'Benz[a]anthracene': [0.1,0], + 'Benzo[a]pyrene': [0.1,0], + 'Benzo[b]fluoranthene': [0.1,0], + 'Benzo[g,h,i]perylene': [0.1,0], + 'Benzo[e]pyrene': [0.1,0], + 'Benzo[k]fluoranthene': [0.1,0], + 'C1-Napthalenes': [0.1,0], + 'C1-Phenanthrenes': [0.1,0], + 'C2-Napthalenes': [0.1,0], + 'C3-Napthalenes': [0.1,0], + 'Chrysene': [0.1,0], + 'Dibenz[a,h]anthracene': [0.01,0], + 'Fluoranthene': [0.1,0], + 'Fluorene': [0.1,0], + 'Indeno[123-c,d]pyrene': [0.1,0], + 'Napthalene': [0.1,0], + 'Perylene': [0.1,0], + 'Phenanthrene': [0.1,0], + 'Pyrene': [0.1,0] + }; + actionLevels['Organochlorine data'] = { + 'Dieldrin': [0.005,0], + 'Dichlorodiphenyltrichloroethane (PPDDT)': [0.001,0.2] + }; + let actionLevelColors = ['rgba(255, 255, 0, 1)','rgba(255, 0, 0, 0.5)']; + let actionLevelDashes = [[3,3],[5,5]]; + + firstTime = true; + + importData(); + + function saveSnapShot() { + const fileSave = document.getElementById('fileSave'); + const fileName = fileSave.value; + saveStatus(fileName); + } + + function loadSnapShotURL() { + const urlLoad = document.getElementById('urlLoad'); + const fileUrl = urlLoad.value; + loadStatus(fileUrl); + } + + function loadSnapShotFile() { + const fileInput = document.getElementById('fileLoad'); + const file = fileInput.files[0]; + if (file) { + const reader = new FileReader(); + reader.onload = function (e) { + // Read file as text + const textData = e.target.result; + // Decode the base64 data (if it was encoded) + const decodedData = decodeURIComponent(escape(atob(textData))); + // Parse the JSON data + const jsonData = JSON.parse(decodedData); + // Use the loaded data + // Now jsonData contains the loaded data + sampleInfo = jsonData.sampleInfo; + sampleMeasurements = jsonData.sampleMeasurements; + selectedSampleInfo = jsonData.selectedSampleInfo; + selectedSampleMeasurements = jsonData.selectedSampleMeasurements; + updateChart(); + }; + + reader.readAsText(file); + } + } + + function saveStatus(fileName) { + // Save data to a file + const dataBlob = new Blob([btoa(unescape(encodeURIComponent(JSON.stringify({ sampleInfo, sampleMeasurements, selectedSampleInfo, selectedSampleMeasurements }))))], { type: 'application/octet-stream' }); + const downloadLink = document.createElement('a'); + downloadLink.href = URL.createObjectURL(dataBlob); + downloadLink.download = fileName; + downloadLink.click(); + } + + // Function to load data from a file URL + async function loadStatus(fileURL) { + try { + // Fetch the data from the URL + const response = await fetch(fileURL); + + // Check if the fetch was successful (status code 200) + if (!response.ok) { + throw new Error(`Failed to fetch data. Status: ${response.status}`); + } + + // Read the response as text + const textData = await response.text(); + + // Decode the base64 data (if it was encoded) + const decodedData = decodeURIComponent(escape(atob(textData))); + + // Parse the JSON data + const jsonData = JSON.parse(decodedData); + + // Now jsonData contains the loaded data + sampleInfo = jsonData.sampleInfo; + sampleMeasurements = jsonData.sampleMeasurements; + selectedSampleInfo = jsonData.selectedSampleInfo; + selectedSampleMeasurements = jsonData.selectedSampleMeasurements; + updateChart(); + return jsonData; + } catch (error) { + console.error('Error loading data:', error.message); + } + } + + function clearData() { + sampleMeasurements = {}; + selectedSampleMeasurements = {}; + sampleInfo = {}; + selectedSampleInfo = {}; +/* if (map) { + map.remove(); + }*/ + const canvas = []; + for (i = 1; i < noInstances; i++) { + canvas[i] = document.getElementById('chart' + i); + clearCanvasAndChart(canvas[i], i); + } + } + + function importLocations() { + const fileInput = document.getElementById('fileLocations'); + const urlInput = document.getElementById('urlLocations'); + const files = fileInput.files; // Files is now a FileList object containing multiple files + const urls = urlInput.value.trim().split(',').map(url => url.trim()); // Split comma-separated URLs + + if (files.length === 0 && urls.length === 0) { + alert('Please select files or enter URLs.'); + return; + } + // Process files + for (let i = 0; i < files.length; i++) { + filename = files[i].name; + const reader = new FileReader(); + reader.onload = function (e) { + const data = new Uint8Array(e.target.result); + processExcelLocations(data,filename); + }; + reader.readAsArrayBuffer(files[i]); + } + + // Process URLs only if URLs are supplied + if (urls.length > 0) { + urls.forEach(url => { + // Check if the URL is a valid URL before fetching + if (!/^https?:\/\//i.test(url)) { + console.error('Invalid URL:', url); + return; + } + + fetch(url) + .then(response => response.arrayBuffer()) + .then(data => { + processExcelLocations(new Uint8Array(data),url); + }) + .catch(error => { + console.error('Error fetching the locations file:', error); + }); + }); + } + // Clear the input field after reading locations + fileInput.value = ''; + urlInput.value = ''; + } + + function processExcelLocations(data,url) { + // Based on simple Excel data in first sheet + // row 1 column titles + // column 1 location as per name used as sample in MMO templates + // column 2 latitude in decimal degrees + // column 3 longitude in decimal degrees +// console.log('processexcellocations',url); +//console.log('prcoessing ',url); + const workbook = XLSX.read(data, { type: 'array' }); +//console.log(workbook); + sheetData = workbook.Sheets['Sheet1']; +//console.log(sheetData); + const df = XLSX.utils.sheet_to_json(sheetData, { header: 1 }); + for (let r = 1; r < df.length; r++) { + const sample = df[r][0]; + namedLocations[sample] = {}; + namedLocations[sample].latitude = df[r][1]; + namedLocations[sample].longitude = df[r][2]; +console.log(sample,namedLocations[sample]); + } + } + + function importData() { + urls = {}; + if (firstTime) { + firstTime = false; + files = {}; + // Get the current URL + const currentURL = window.location.href; + + // Parse the URL to get the search parameters + const suppliedParams = new URLSearchParams(window.location.search); + // Get the value of the 'file' parameter + const statusParam = suppliedParams.get('status'); + if (statusParam) { + loadStatus(statusParam); + } else { + const urlParam = suppliedParams.get('urls'); + if (urlParam) { + urls = urlParam.split(',').map(url => url.trim()); // Split comma-separated URLs + } + } + const selParam = suppliedParams.get('selcharts'); + if (selParam) { + selcharts = selParam.split(',').map(sel => sel.trim()); // Split comma-separated URLs + if (selcharts) { + // Blank all the checkboxes + for (let i = 0; i < dataSheetNamesCheckboxes.length; i++) { +console.log(i,dataSheetNamesCheckboxes[i]); + const checkbox = document.getElementById(dataSheetNamesCheckboxes[i]); + checkbox.checked = false; + } + // Check all the boxes set in url + for (let i = 0; i < selcharts.length; i++) { + const checkbox = document.getElementById(selcharts[i]); + checkbox.checked = true; + } + } + } + const subParam = suppliedParams.get('subcharts'); + if (subParam) { + subcharts = subParam.split(',').map(subch => subch.trim()); // Split comma-separated URLs + if (subcharts) { + // Blank all the checkboxes + for (let i = 0; i < subChartNames.length; i++) { + const checkbox = document.getElementById(subChartNames[i]); + checkbox.checked = false; + } + // Check all the boxes set in url + for (let i = 0; i < subcharts.length; i++) { + const checkbox = document.getElementById(subcharts[i]); + checkbox.checked = true; + } + } + } + + } else { + const fileInput = document.getElementById('fileInput'); + const urlInput = document.getElementById('urlInput'); + files = fileInput.files; // Files is now a FileList object containing multiple files + urls = urlInput.value.trim().split(',').map(url => url.trim()); // Split comma-separated URLs + } + if (files.length === 0 && urls.length === 0) { + alert('Please select files or enter URLs.'); + return; + } + // Process files + for (let i = 0; i < files.length; i++) { + const filename = files[i].name; +console.log(filename); + const reader = new FileReader(); + + reader.onload = function (e) { + const data = new Uint8Array(e.target.result); + processExcelData(data,filename); + }; + reader.readAsArrayBuffer(files[i]); + } + + // Process URLs only if URLs are supplied + if (urls.length > 0) { + urls.forEach(url => { + // Check if the URL is a valid URL before fetching + if (!/^https?:\/\//i.test(url)) { + console.error('Invalid URL:', url); + return; + } + + fetch(url) + .then(response => response.arrayBuffer()) + .then(data => { + processExcelData(new Uint8Array(data),url); + }) + .catch(error => { + console.error('Error fetching the file:', error); + }); + }); + } + // Clear the input field after reading data + fileInput.value = ''; + urlInput.value = ''; + } + + function processExcelData(data, url) { +// console.log('processexceldata',url); + const workbook = XLSX.read(data, { type: 'array' }); + + function extractDataFromSheet(sheetName, sheetData, dateSampled) { + if (sheetData === null || sheetData == undefined) { + return null; + } +//console.log('ext data ',sheetData); + const df = XLSX.utils.sheet_to_json(sheetData, { header: 1 }); +// const df = XLSX.utils.sheet_to_json(sheetData, { header: 1, cellText: true }); + let startRow = -1; + let startCol = -1; + let measurementUnit = 'Not set'; + let totalSum = 0; + meas = {}; + // Read in date of analysis +//console.log('df ', df); + if (df[18][1] === 'Date of analysis:') { + row = 18; + column = 2; + } else { + if (df[17][1] === 'Date of analysis:') { + row = 17; + column = 2; + } else { + if (df[18][2] === 'Date of analysis:') { + row = 18; + column = 3; + } else { + if (df[17][2] === 'Date of analysis:') { + row = 17; + column = 3; + } else { + row = null; + dataAnalysed = 'AD: missing'; + contractor = 'Not listed'; + } + } + } + } + dateAnalysed = 'AD: missing'; + contractor = 'Not listed'; + for (let cc = 0; cc < 30; cc++) { + for (let r = 0; r < 30; r++) { + const cellValue = df[r][cc]; +//console.log(sheetName,r,cc); + if (typeof cellValue === 'string' && cellValue.includes('Date of analysis')) { + dateAnalysed = parseDates(df[r][cc + 1])[0]; + contractor = df[r - 1][cc + 1]; + break; + } + } + } + + for (let r = 0; r < df.length; r++) { + for (let cc = 0; cc < df[r].length; cc++) { + const cellValue = df[r][cc]; + if (typeof cellValue === 'string' && cellValue.includes('Dredge Area')) { + c = cc - 1; + measurementUnit = df[r][c+4]; + corec = 0; + extraValue = df[r][c]; + if (typeof extraValue === 'string' && extraValue.includes('Laboratory sample number')) { +console.log('Lab sampl numb'); + corec = 0; + measurementUnit = df[r][c+4]; + } else { +console.log('No Lab sampl numb'); + corec = 0; + measurementUnit = df[r][c+3]; + } + //} +//console.log('unit ',measurementUnit); + if (!(sheetName === 'Physical Data')) { + if(!(sheetName === 'PCB data')) { + startRow = r + 2; + } else { + startRow = r + 3; + } + startCol = c; + for (let col = startCol + 1; col < df[startRow].length; col++) { + if(!(sheetName === 'PCB data')) { + chemical = df[startRow - 1][col]; + } else { + chemical = df[startRow - 2][col]; + congener = df[startRow - 1][col]; + } + if (chemical !== null && chemical !== undefined) { + if (!meas.chemicals){ + meas.chemicals = {}; + meas.total = {}; + if(sheetName === 'PCB data') { + meas.congeners = {}; + } + } + if (!meas.chemicals[chemical]) { + meas.chemicals[chemical] = {}; + if(sheetName === 'PCB data') { + meas.congeners[chemical] = congener; + } + } + for (let row = startRow; row < df.length; row++) { + sample = df[row][startCol+2]; //bodge to pick up sample id + // If sample id not present then use Laboratory sample number instead + if (sample == undefined || sample == null) { + sample = df[row][startCol]; + } + if (!(sample == undefined || sample == null)) { +//console.log(sample); + const concentration = df[row][col+corec]; + if(sample.includes('detection')) { + meas.chemicals[chemical][sample] = concentration; + //.push(parseFloat(concentration) || 0); + } else { + if (!meas.chemicals[chemical].samples) { + meas.chemicals[chemical].samples = {}; + } + if (!meas.chemicals[chemical].samples[sample]) { + meas.chemicals[chemical].samples[sample] = {}; + } + if (!meas.total[sample]) { + meas.total[sample] = 0; + } + if (concentration !== null && concentration !== undefined) { + meas.chemicals[chemical].samples[sample]= parseFloat(concentration); + meas.total[sample] += parseFloat(concentration) || 0; + totalSum += parseFloat(concentration) || 0; + } + } + } + } + } else if (sheetName === 'PAH data') { + hydrocarbon = df[startRow - 2][col]; + if (hydrocarbon !== null && hydrocarbon !== undefined) { + if (hydrocarbon === 'Total hydrocarbon content (mg/kg)') { + for (let row = startRow; row < df.length; row++) { + sample = df[row][startCol+2]; //bodge to pick up sample id + // If sample id not present then use Laboratory sample number instead + if (sample == undefined || sample == null) { + sample = df[row][startCol]; + } + if (!(sample == undefined || sample == null)) { + const concentration = df[row][col+corec]; + if(sample.includes('detection')) { + meas[sample] = concentration; + //.push(parseFloat(concentration) || 0); + } else { + if (!meas.totalHC) { + meas.totalHC = {}; + meas.totalHCUnit = hydrocarbon; + } + meas.totalHC[sample] = parseFloat(concentration); + } + } + } + } + } + } + } + } else { + measurementUnit = df[r][c+7]; + meas.samples = {}; + meas.sizes = []; + startRow = r + 3; + startCol = c; + for (let col = startCol + 7; col < df[startRow - 1].length; col++) { + meas.sizes.push(parseFloat(df[startRow - 2][col]) || 0); + for (let row = startRow; row < 38; row++) { + sample = df[row][startCol+2]; //bodge to pick up sample id + // If sample id not present then use Laboratory sample number instead + if (sample == undefined || sample == null) { + sample = df[row][startCol]; + } + if (!(sample == undefined || sample == null)) { +//console.log(sheetName, col, row, sample); + if (!meas.samples) { + meas.samples = {} + } + if (!meas.samples[sample]) { + meas.samples[sample] = {}; + meas.samples[sample].psd = []; + meas.samples[sample]['Visual Appearance'] = df[row][startCol+3]; + meas.samples[sample]['Total solids (% total sediment)'] = df[row][startCol+5]; + meas.samples[sample]['Organic matter (total organic carbon)'] = df[row][startCol+6]; + } + +//console.log(sample); + meas.samples[sample].psd.push(parseFloat(df[row][col]) || 0); +//console.log('meas.psd ',df[row][col]); + } + } + } +//console.log(sheetName, ' in else ','meas ', meas); + } + break; + } + } + if (startRow !== -1 && startCol !== -1) { + break; + } + } + meas['Date analysed'] = dateAnalysed; + meas['Unit of measurement'] = measurementUnit; + meas['Laboratory/contractor'] = contractor; + if(!totalSum>0 && !(sheetName === 'Physical Data')) { + return 'No data for ' + sheetName; + } +//console.log(sheetName, 'meas ', meas); + sampleMeasurements[dateSampled][sheetName] = meas; + const sums = {}; + if (sheetName === "PCB data") { + const ICES7 = ["2,2',5,5'-Tetrachlorobiphenyl","2,4,4'-Trichlorobiphenyl","2,2',3,4,4',5,5'-Heptachlorobiphenyl", + "2,2',4,4',5,5'-Hexachlorobiphenyl","2,2',3,4,4',5'-Hexachlorobiphenyl", + "2,3',4,4',5-Pentachlorobiphenyl","2,2',4,5,5'-Pentachlorobiphenyl"]; + + for (const chemical in meas.chemicals) { + for (const sample in meas.chemicals[chemical].samples) { + //console.log(chemical,sample); + if (!sums[sample]) { + sums[sample] = { + ICES7: 0, + All: 0 + }; + } + //console.log(meas[chemical][sample]); +// const congenerConcentration = meas.chemicals[chemical].samples[sample].reduce((acc, val) => acc + val, 0); + const congenerConcentration = meas.chemicals[chemical].samples[sample] || 0; + if (ICES7.includes(chemical)) { + sums[sample].ICES7 += congenerConcentration; + } + sums[sample].All += congenerConcentration; + } + } + sampleMeasurements[dateSampled][sheetName].congenerTest = sums; + } + if (sheetName === "PAH data") { + // Goring Test protocol here, but results stored by sample + const lmw = ['Acenaphthene', 'Acenaphthylene', 'Anthracene', 'Fluorene', 'C1-Naphthalenes', 'Naphthalene', 'Phenanthrene']; + const hmw = ['Benz[a]anthracene', 'Benzo[a]pyrene', 'Chrysene', 'Dibenz[a,h]anthracene', 'Fluoranthene', 'Pyrene']; + + for (const chemical in meas.chemicals) { + for (const sample in meas.chemicals[chemical].samples) { + //console.log(chemical,sample); + if (!sums[sample]) { + sums[sample] = { + lmwSum: 0, + hmwSum: 0 + }; + } + //console.log(meas[chemical][sample]); + if (lmw.includes(chemical)) { + const lmwConcentrationSum = meas.chemicals[chemical].samples[sample] || 0; + sums[sample].lmwSum += lmwConcentrationSum; + } else if (hmw.includes(chemical)) { + const hmwConcentrationSum = meas.chemicals[chemical].samples[sample] || 0; + sums[sample].hmwSum += hmwConcentrationSum; + } + } + } + sampleMeasurements[dateSampled][sheetName].gorhamTest = sums; + } + return dateAnalysed; + } + +function parseDates(dateString) { +// Check if the date field is empty +if (!dateString) { + return ['Missing']; +} + +const dates = []; + +// Split the input by commas or hyphens +const dateParts = dateString.split(/,|-/); +dateParts.forEach(part => { + // Trim leading/trailing spaces + const trimmedPart = part.trim(); + + // Check if it's a range (contains a hyphen) + if (trimmedPart.includes('/')) { + const ukDate = convertToUKFormat(trimmedPart); + if (ukDate) { + dates.push(ukDate); + } + } else { + // Single date + const ukDate = convertToUKFormat(trimmedPart); + if (ukDate) { + dates.push(ukDate); + } + } +}); + +return dates.length > 0 ? dates : ['Missing']; +} + +function convertToUKFormat(dateString) { +const parts = dateString.split('/'); +if (parts.length === 3) { + // Assuming the format is mm/dd/yy + const mm = parts[0].padStart(2, '0'); + const dd = parts[1].padStart(2, '0'); + const yy = parts[2].padStart(2, '0'); + + // Construct the UK format: dd/mm/yy + return `${yy}/${mm}/${dd}`; +} + +// Return null for invalid date formats +return null; +} + + function extractApplicationDataFromSheet(sheetName, sheetData, url) { +// console.log('extractappdata',url); + const df = XLSX.utils.sheet_to_json(sheetData, { header: 1 }); +// const df = XLSX.utils.sheet_to_json(sheetData, { header: 1, cellText: true }); + + +// console.log(sheetName); //Output each cell value to console +// console.log(df.length); + let startRow = -1; + let startCol = -1; + + // This code should have found Applicant: but doesn't so bodged above +/* if (typeof cellValue === 'string' && cellValue.includes('Applicant:')) { + console.log('found applicant'); + const applicant = df[r][c+1]; + const applicationNumber = df[r+1][c+1]; + const applicationTitle = df[r+2][c+1]; + const dateSampled = df[r+3][c+1]; + const samplingLocation = df[r+4][c+1]; + } +*/ + + +/* // This relies on template first page not changing at all + const applicant = df[14][4]; + const applicationNumber = df[15][4]; + const applicationTitle = df[16][4];*/ + for (i = 16; 19; i++) { + dateRow = i; + if (df[dateRow][2].includes('Date sampled:')) { + break; + } + dateRow = 0; +// dateSampled = 'SD: missing'; + } + if (dateRow > 0) { + applicant = df[dateRow-3][4]; + applicationNumber = df[dateRow-2][4]; + applicationTitle = df[dateRow-1][4]; + dateSampled = parseDates(df[dateRow][4])[0]; + } else { + applicant = df[14][4]; + applicationNumber = df[15][4]; + applicationTitle = df[16][4]; + dateSampled = 'SD: missing'; + dateRow = 17; + } + sampleInfo[dateSampled] = {}; + sampleInfo[dateSampled]['Applicant'] = applicant; + sampleInfo[dateSampled]['Application number'] = applicationNumber; + sampleInfo[dateSampled]['Application title'] = applicationTitle; + sampleInfo[dateSampled]['Date sampled'] = dateSampled; + sampleInfo[dateSampled]['fileURL'] = url; +console.log('extractapplicationdatafromsheet ', dateSampled,url); + sampleInfo[dateSampled].position = {}; + sampleMeasurements[dateSampled] = {}; + + const samplingLocation = df[dateRow + 1][4]; + for (let c = 0; c < df.length; c++) { + + //Bodge as didn't read enough of columns when set by length alone +// for (let r = 0; r < df[c].length; r++) { + if (df[c].length < 40 ) { + cdepth = 40; + } else { + cdepth = df[c].length; + } + for (let r = 0; r < cdepth; r++) { + const cellValue = df[r][c]; +// console.log(c,r,cellValue); +// if (typeof cellValue === 'string' && cellValue.includes('Excluded sample (MMO use)')) { + if (typeof cellValue === 'string' && cellValue.includes('Sample location (decimal degrees, WGS84)')) { +console.log('Sample Location'); + const extraValue = df[r][c-1] +console.log(extraValue); + if (typeof extraValue === 'string' && extraValue.includes('Excluded sample (MMO use)')) { + startRow = r + 2; + startCol = c-2; + samCol = startCol; + excCol = startCol + 1; + latCol = startCol + 2; + lonCol = startCol + 3; + namCol = startCol + 4; + depCol = startCol + 5; + dreCol = startCol + 6; + } else { + startRow = r + 2; + startCol = c-1; + samCol = startCol; + excCol = startCol + 6; // not present here + dreCol = startCol + 5; + latCol = startCol + 1; + lonCol = startCol + 2; + namCol = startCol + 3; + depCol = startCol + 4; + } + + for (let row = startRow; row < df.length; row++) { + const sample = df[row][samCol]; //bodge to pick up sample id + if (!(sample == undefined || sample == null)) { + sInfo = {}; + sInfo['Excluded sample (MMO use)'] = df[row][excCol]; + sInfo['Dredge area'] = df[row][dreCol]; + point = parseCoordinates(df[row][latCol],df[row][lonCol]); + if (point === null || point === undefined) { + // latitude and longitude aren't specified so try to retrieve latlon from previously entered locations + if (namedLocations[sample] !== null && namedLocations[sample] !== undefined) { + point = {}; + point['latitude'] = namedLocations[sample].latitude; + point['longitude'] = namedLocations[sample].longitude; + } else { +//console.log('lat and long undefined does not match', sample); + point = {}; + point['latitude'] = undefined; + point['longitude'] = undefined; + } + } + sInfo['Position latitude'] = point['latitude']; + sInfo['Position longitude'] = point['longitude']; + sInfo['Location name (as per sampling plan)'] = df[row][namCol]; + sInfo['Sampling depth (m)'] = processDepth(df[row][depCol]); + sInfo['Sampling location']= samplingLocation; + sampleInfo[dateSampled].position[sample] = sInfo; + } + } + break; + } + } + if (startRow !== -1 && startCol !== -1) { +// console.log('Breaking up'); + break; + } + } + return dateSampled; + } + + +// workbook.SheetNames.forEach(sheetName => { +// const sheetData = workbook.Sheets[sheetName]; +// extractDataFromSheet(sheetName, sheetData); +// }); + sheetName = 'Application info'; + sheetData = workbook.Sheets[sheetName]; + dateSampled = extractApplicationDataFromSheet(sheetName, sheetData, url); + sheetName = 'PAH data'; + sheetData = workbook.Sheets[sheetName]; + dateAnalysed = extractDataFromSheet(sheetName, sheetData, dateSampled); + if (dateSampled.includes('SD: Missing')) { + dateSampled = dateAnalysed + 'ADMSD'; +// sampleMeasurements[dateSampled] = sampleMeasurements['holder']; +// delete sampleMeasurements['holder']; +// sampleInfo[dateSampled] = sampleInfo['holder']; +// delete sampleInfo['holder']; + sampleMeasurements[dateSampled] = sampleMeasurements['SD: Missing']; + delete sampleMeasurements['SD: Missing']; + sampleInfo[dateSampled] = sampleInfo['SD: Missing']; + delete sampleInfo['SD: Missing']; + } else if (dateSampled > dateAnalysed) { + sampleMeasurements[dateAnalysed + 'ADWSD'] = sampleMeasurements[dateSampled]; + delete sampleMeasurements[dateSampled]; + sampleInfo[dateAnalysed + 'ADWSD'] = sampleInfo[dateSampled]; + delete sampleInfo[dateSampled]; + dateSampled = dateAnalysed + 'ADWSD'; + } + sheetName = 'PCB data'; + sheetData = workbook.Sheets[sheetName]; + dateAnalysed = extractDataFromSheet(sheetName, sheetData, dateSampled); + sheetName = 'Trace metal data'; + sheetData = workbook.Sheets[sheetName]; + dateAnalysed = extractDataFromSheet(sheetName, sheetData, dateSampled); + sheetName = 'BDE data'; + sheetData = workbook.Sheets[sheetName]; + dateAnalysed = extractDataFromSheet(sheetName, sheetData, dateSampled); + sheetName = 'Organotins data'; + sheetData = workbook.Sheets[sheetName]; + dateAnalysed = extractDataFromSheet(sheetName, sheetData, dateSampled); + sheetName = 'Organochlorine data'; + sheetData = workbook.Sheets[sheetName]; + dateAnalysed = extractDataFromSheet(sheetName, sheetData, dateSampled); + + sheetName = 'Physical Data'; + sheetData = workbook.Sheets[sheetName]; + dateAnalysed = extractDataFromSheet(sheetName, sheetData, dateSampled); + + + selectedSampleMeasurements = sampleMeasurements; + selectedSampleInfo = sampleInfo; + updateChart(); + }; + + function processDepth(enteredDepth) { +// console.log(enteredDepth); + if (!enteredDepth) { + return { + minDepth: 0.0, + maxDepth: 0.0, + }; + } + // Remove any non-numeric characters, except for dots and hyphens + const cleanedDepth = enteredDepth.replace(/[^0-9.\-]/g, ''); + + // Split the cleaned depth by hyphens to handle ranges + const depthParts = cleanedDepth.split('-'); + + // Convert the parts to numbers + const numericDepths = depthParts.map(parseFloat); + + // Determine min and max depths + const minDepth = Math.min(...numericDepths); + const maxDepth = Math.max(...numericDepths); + + // Return the result + return { + minDepth: isNaN(minDepth) ? 0.0 : minDepth, + maxDepth: isNaN(maxDepth) ? 0.0 : maxDepth, + }; + } + +// Function to create a new canvas for a chart +function createCanvas(instanceNo) { +const container = document.getElementById('chartContainer'); +const canvas = document.createElement('canvas'); +canvas.id = 'chart' + instanceNo; // Unique chart ID +container.appendChild(canvas); // Append the canvas to the container +} + +// Function to create a button for resetting zoom +function createResetZoomButton(chart,instanceNo) { +const button = document.createElement('button'); +button.id = 'button'+instanceNo +button.textContent = 'Reset Zoom'; +button.addEventListener('click', () => { + chart.resetZoom(); +}); +const container = document.getElementById('chartContainer'); +container.appendChild(button); +} + +function clearCanvasAndChart(canvas, chartInstanceNo) { + if (canvas) { + const ctx = canvas.getContext('2d'); + ctx.clearRect(0, 0, canvas.width, canvas.height); + if (chartInstance[chartInstanceNo]) { + chartInstance[chartInstanceNo].destroy(); + chartInstance[chartInstanceNo] = null; + } + /* // Hide the canvas + const convas = document.getElementById("chart" + chartInstanceNo); + convas.style.display = "none";*/ + // Remove the canvas + const convas = document.getElementById("chart" + chartInstanceNo); + convas.remove(); + // Remove a reset button if created + const buttonToRemove = document.getElementById('button' + chartInstanceNo); + // Check if the button exists + if (buttonToRemove) { + // Remove the button + buttonToRemove.remove(); + } else { + console.log('Button not found', chartInstanceNo); + } + } +} + +function chemicalTypeHasData(sheetName) { + chemicalTypeData = false; + for (const ds in selectedSampleMeasurements) { + const chemicalTypes = Object.keys(selectedSampleMeasurements[ds]); + //console.log(ds, sheetName, chemicalTypes); + if (chemicalTypes.includes(sheetName)) { + chemicalTypeData = true; + return chemicalTypeData; + } + } +} + +function filenameDisplay() { + + const fileDisplayDiv = document.getElementById("fileDisplay"); + // blank it each time + fileDisplayDiv.innerHTML = ""; + + iconNo = 0; + for (dateSampled in selectedSampleInfo) { + currentIcon = markerPngs[iconNo]; + iconNo = (iconNo + 1) % 9; + + const fileURL = sampleInfo[dateSampled].fileURL; + + // Create an image element for the icon + const iconElement = document.createElement("img"); + iconElement.src = currentIcon; + iconElement.alt = "Marker Icon"; + iconElement.style.width = "20px"; // Adjust the width as needed + + // Create a link element for each file and append it to the div + const linkElement = document.createElement("a"); + linkElement.href = fileURL; + // console.log(fileURL); + // console.log(dateSampled); + linkElement.textContent = `File for ${dateSampled}: ${fileURL}`; + linkElement.target = "_blank"; // Open link in a new tab/window + + // Append the icon before the link + fileDisplayDiv.appendChild(iconElement); + fileDisplayDiv.appendChild(linkElement); + + // Add a line break for better readability + fileDisplayDiv.appendChild(document.createElement("br")); + }; +} + + diff --git a/markers/marker-icon-black.png b/markers/marker-icon-black.png new file mode 100644 index 0000000000000000000000000000000000000000..d262ae42eef90a127232ef9102438247d6e995d2 GIT binary patch literal 1523 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 literal 0 HcmV?d00001 diff --git a/markers/marker-icon-gold.png b/markers/marker-icon-gold.png new file mode 100644 index 0000000000000000000000000000000000000000..162fada6bb5ec9283873074f87c94bed4a183ce4 GIT binary patch literal 1862 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 literal 0 HcmV?d00001 diff --git a/markers/marker-icon-grey.png b/markers/marker-icon-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..ebbab8effc42123c5fb5f83344561dcb4af0eabd GIT binary patch literal 1691 zcmV;M24wk(P)P001cn1^@s6z>|W`00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3$s2GAD}NWF!Cp1}I5H zK~z}7rB}^w6v-9;RrU9@$AJvk;GMZdLQ8IuBMVL|J`Ul^A%`frL=bTX91B?+O|%kP zP-YKd*_FnSokbxeibx#gA3#BZ!>*N$!i9*hNMLKte9<%AT{YeHk&Ao8c*gdal=KeW z^@f<3f|aHzdcEF`XKvdz zY}-bw)e@~%OKPouQmIsyhd}1%=l214Ix{o#om?)5IF6x|!nlJ{3eWSvImg=CT0|** z|LWDNs{laX()%)>&%2)Iq1)|3N(rs?kYq90EK*8@VF=fCF*!MDN-2Ne-v9udKY#wG zgpiZ__wRQYV?zrVh5_IAkllJbd4WX_`a2j4>1n1&304^umP;zW@Mo@#4jt zl(Jqd7IUU)f^$A_44&t~FbuR>Eksd-BuQYJCMG5(uy^lX06?~}Y`CrqAp~B%dc_UH zD40TsS<^I0E|){6(-}~990yWLynOi*v$L}}cI+6Yrl!zrHu2!W13Y~A5C;w%fNk3Y zo8z2ga&i)eVJIQQtf{r0a~ub0nhpe-QVQF)v9`8`Q>RYhz zA0Y%h&+`C$K(*FK9ml~a5Y9Oc9XbR;$d;*l`0!yQNdijg5QyVA&{`igrIa~B2$WI- z@z7dBDFxSccPzy0m^a%~N}-hUD1d)4#)ftxrG#Z!c=F`QwjfWRK80ZzLnlEg&9d$r zs+79V7)vRo1IB5Z!uNfwuCC(IqemkFUc7jL$B!Q)pU*=GF~k6ju|z5L5305PI*OuX z!?nJoX$m0(_U+q;rKKg@zkk1UCdWEt4&^Bgb=?QxK99}R;zsr;M3QyU%!(#S@qZJbq3&* zTeogChd?$8@Z%_oz&X!&XV+dZ#*|?gzZodZw?8(}D~(2jIgT?j)3%F6yV{p!el=8PjYi|Crw6xR#aJkWF^kefjU2K-DF6#Aq z4B(?$trqSGvQanJk|gQHal9kdyRMtv{ai}<*~oTj)X!?Q8f&e~&1RF?w!LK=LZW`mo(@Gt07u zyve+1x7!TB;`Qs-lU;*s+#6pAA=;z7aa}j_qERZ9Zf)DbZZ}!0)r8ji(wjGLm~Gqr zE1FW8dBL^TmokoeClCO5_Uzdogb?3$yWPGwuIr-H=|D=k`uzFxKke9z@1$_=-aQ3i zAqWC)Sr#nIf@zuvf`Ai37B=SpKM(*Yl}dk+QvNp#L+$%My4|i;N_1J@{DBbSo0~Up{&4IE5_UJ{g%D&n lUW`rUZ_Al8XD;p5=6`+tS@~>Hl+6GD002ovPDHLkV1lF>BccER literal 0 HcmV?d00001 diff --git a/markers/marker-icon-orange.png b/markers/marker-icon-orange.png new file mode 100644 index 0000000000000000000000000000000000000000..fbbce7b2ab1e5de921b5f5488960a333ed37d054 GIT binary patch literal 1862 zcmV-M2f6r(P)P001cn1^@s6z>|W`00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3tN{D;cm-z$E|x2GdDI zK~z}7rI%}rT~!sw|7-7a?z!ijduKYG>9ougD~4o{4_fFm#t_t)HU^^~-j9O{&6*ZVhgaj*XZKaKfQtWiz@B2KDefHkV54WAp?YwcH z{J-3@*ZS?X*WPR0L(GijjOX{iXSL4IP1>vx4kj7i(9UnXIKCWPS`6~X2j1I5Y(C4N zPcd`15F(b2tBua2wbqw{#vt)CYweGAe(l7oD}p?@io~{E+xCLQSHnUPVHkQ|-iL5< zAR;g`tkO_fgeZzsrCcIr{$|h_Jaqe){;ZdT{C?locQDDLuIs*Y?RDLO>quCwz$R4KyS;pC8MgYnVfC{yVL9qBti{GF4pF9`Yd-fcUipkKAFYLlzmJ6z6Un6$p+ zp39sM%7vJon$*)%lg2VW{*iC}?YTLS-`&5t!$|o?S65eS82Hdp32Y6PJ4i@4ehZ>R zVR&e;PI=jL$Ad2q0)V(O$w>L*La`+u_<5-61gz0u<~ah1d4IP?L)E6>=RFi#S{)Oc zXRi1b0PyVnTR+JpKd^RPyJzAuz_v+3I&fRskSlgT_^XgBcEAnWAe`Ksxh5{7qkXkU zLT*34d+Xf*K)=0jQ;>qj-?qLh$UA^Zt4-VBge|bhV|=QNdc6*<5=h5IP-sDCTLBUV zI;#NMUd@qLM52Mdf#D<%+wLR+w@Pv-Ec#H@F+j|o93oYOzM%nJf6ESRzWoy@uGxV4 z5|E`&L#m)`b_|f~YYW+<(bLn(!7w}l1Iw?;Lh zxGWMbD&+{2Z$;1hK0WV=di&-NA?&;X)0KK7KeOzuQ3wm3PvF~xWo-8Y7p&9fWP1+c zB*mH=w}6NiJi6<8wj(hbCip6uDu9}3?{8N*^`hcC#lkelXT>Zw{)@M z{!KS`3mZ>?O*VTuaKkp#Q^v*N8sa!cOZz(1rpF*17dLbj(Gob&$pkpNnh%mLgufc6 z|2b%o>26|XJax~;S2lFDZs{lpn7G^&Hai6A6dM;aV=0P;jKCHqDq97;_WOj~N8E_oK)T-b(29%z6o}fHRr37ha zYQfH)-^@UI51z^_I$_)LwX^21&_!DsKyzpwaik%{q}6XO^|z^er=LL2QH07vCM^+&+zi1 zkhu_j!}Z8A9_~GOs=Ocs0JO*-sMNHnL<%w&g1}44@d~I!3iW!XjWLg1>vIm|^FKII zA@JAx2IE+`0W3Gl$UdGrmXF@wJHnaBQ{EE@sZ>2W>1KPdW^1GuVLjV8(07*qoM6N<$f@n2+ ANB{r; literal 0 HcmV?d00001 diff --git a/markers/marker-icon-red.png b/markers/marker-icon-red.png new file mode 100644 index 0000000000000000000000000000000000000000..3e64e06d1db4eecf0d6e4446630fc4f9b97694b2 GIT binary patch literal 1870 zcmV-U2eJ5xP)P001cn1^@s6z>|W`00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3$s2DJLWAuf6~P2HQzQ zK~z}7rI%}rRaX_q|9kIq?mdtDm=_dhinS(Y;uopV!qk}Bl$f@L!Ut@OuNZ3_W2=5D z1dRqIF=(V8wDD16Ta7VRQ>X%>X|+&D3<52*kWi~2!^{+hdEI;G-t*XJ@3s7JVd!OM zm^-?Y|Cf{fU%#^-YprtxGozjH;)gbM8OT0i#WD$+IMv6)ds;^y~vi_r0+s$almBxo(}a6;ggXEEW-lK|b&M zkU1AZ2rx6q06LmM6h*pLsS0NPUJ%fZdtcsb7KI#GyYaoOZvt_$HhkU1BbwHUv2DaulP&KUXdL&tajb3w=-*KNFC3Gs(=XQ%4w>2Wzu zU>otGd#-#BBJ?pmIccURCoKV=-1LvVFU*1LzjITMRs8SX-rjQP`!JOmu(fD+2&LeZ z3W#)yOQWL=p=|$#zyE0z0OYkvR`D+jrIHtT9`wXC$QUs596`!?pOZ1rQx*96Jc{MA zW3Br2wb&8>o?pA+)2!tBTe>^*wps^>S|l9@Zf60xo-W9aB62-la68M8Id{%nTdkv~ zt2-~08rZY;p)Ue}*tce5kP0*Y?%uw@gM^)Fv}}V@@VS|E`Hm7++`R_=ie-4~Z->!U>;PvLY`N)Y0qH6< z44Wj&-jss*o-ptFq%(l7OSledQ36pep#QU*=e<$y`Ph93Z(oV&MjbMjYw?rL5awN9 zFyA8y81P*MPIYsuu1Y!rahhV;U8^93Sn%qu7+8(Oq!5Z*{G4j|t^xrAjv*T~O9g?M zX3fkD%LJ!TSTqsM)l6vh6NC^TB3}YH6(tFTQmt>2WymWBW3Rq`Q^?rKGsv@@vlBuo zL`ebypOi%6a3jq!p;U{Rk`(2s6SD&XuLm0C);on|qi`L_t`599I&5LkCzu(}-0{(4x0TCx^+*@CI@7Xj78a^lZYCyMBw8cy z=HN*Mie_MHbqH?VYE>>`f-)YeR*yY$>ZJh(05rs|k$U~v<;#}^re>RUXqE!l>NKcU zfy}umI1Z>@htACGJO;I_UV08j$EIQp@%`BXDV_KQZH%tz4AKjmb?64M72w#w&LrU2 z00#5UlU|5QqLEr#?|!gz?<{2S#F31^Ke=45#maZUoV8rXwgo_iK1Lh$*fKrw@Xp`a z)_!8`lM_j*BC?Qy59Vyil7Wl5j!;b#VKaKVrJn%6qh}6X2Jqz2OcX2MYc{AGdc{oz zKn6Z8*6T5VCmuU{XmSn&0F1UfD>^~lWKf|$ZwFjRGVn2zY0PAngsXq>&bTd*$Ic#_ zWFdB4jG|bD!PV4nZxt%^G1O>81l~D#;z)Ht2mlx_x2tBXt?3jh3?LYb$|;1X=@gC3 z7;EhhZ;Uwy@|B|pYJ&N@Lvb3*zz2arL<@=qAbbxOq9`KCJ03lAsJc{6H=EWxXCZ`u^g;}!SvR7(owN-B03Fd&skQYfoj?}y^WG>?3^An>q}J5BZSaeQVl4>y>c0-Amg$?rnT>@X z0#deSx0H}x9>ZA{la$~1_?dlr$q)b->we!enrM1Tr%+)IAU!LmkjIoxky@JQez5yj zH;Z#q$o7Lz87r{uB60IGF!s9lo6MTaP001cn1^@s6z>|W`00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3$s2E;XMMNHG8a2GB`F zK~z}7rI%}rRaX_q|7-7a?z!ijduNyjl+H+Ls|lzHVkxi2v?hL_F&e+v4?Y`BoJ6XL z8X(kIN1GC)P?FN9v9Ybjn5rq%R->jSHrB+@0tJBtUm(NW%N^!@U+1yU-h26BV3^yP zVeaTj{vYl+`@eo?uf5mW_YgCqo$KlQUhB@F`?aB!F2scO`0DOA9vo}OOSgg?{?H%R zv7s-3__NI1FNBC4S8AOZX|44I$x#WsXsvzW>&G8FyDZ4v^j)!Y>()Ia@SQ?2L>Pvi z=X-E+0z?F6hSC-~Qi!5RRi|sj%->rT1dl)brw{8TAy01k-Q6VlSFY>6cXj`5fg@cQ zWnnXh$r#o!gd|9pAY6jX322jHv@#Z{G`kpS{m{2heEc7aLiTTcWrrmB>&~uD+0)zY z>X@OL2DC)ZU0=cp36m33dTL_ISlCZJ`sOEIo(I`??{9mBH2?1F>+1~t5b?AIoAx#Z z0FWf)I~>F+LZw`3dXmYqh$a<$ z&quMd=)}hSY&JFkJhA1a&yeJgtnRtZORENK(IVjp6uMl5y*YR*1j61N{4N(VC+3Y! zs|LN@y`GS?ZQqt-UjhJnV$*K|rgUsg-yMOAJXGDZq#@{VVDlCe)iE@iO=O9N<4S}b z0eT9nKt>{~X&8IclPgMONHAO(O33DW971xBa3mG|5Y15qF?Vn%ky46MX$bG%u?E{e zeJ{G#7BN+B;?&WLc>CBz^!2QP=jXw5Ue44FimO6MDJ|RN9w#HSIq(AL#3Gxs&_WWN zkWe14;DLen;l9tWpMBQ5wul|y*ofQLufXpQoW>o!?}2pyn_c%CKqnTC=TW5Vn*}l5 zU+_ZTC<|#ZE8!BRqZ)FZgzcYOx8RQ2@XRw@VPUs9#_HfktC(Au%nZv0Zoyfy z5Hsjm&s;wd!CLDJ0B7PP0=@H1GKMQX44t}mOUUKZ*Wj@?FB2pQaT0-HPm9djH|l9K z6S6fWCb3xIbz0cpJ=32B_x3j z&q^m2CMNV1`|;xL*YV~{e}~aCfvmMS``RVE@Z~>ZW$|_(lgOH;#V;fwPOA#gC+M*c zKG&z1hd1t8#db9z@l~_}}3!&2iHLjuOtcP$3 zUbn#6@+qS=`iYtG=*H*YdROP#%^ji_X|=WD9b$;0L@t!bI7Oloc&>+>$b%z`w5FlC zHPv3HM9q$KsXFx5{xe_PCIBFXI#g+tA}=rC5JU1!u?0-kAgN^FNdZ48080 z!4@s!9b$NSfl9p`r%(rG8)T;=URGMEnyLYL0c|l)nPH?cBd!~yF(cDha2)ai)5$cH zNgLbO*;i*FgC_?vhW)`d1vh zCgwo^AXR#QLro*n4Y;9P@B~~;P9P9vb=0%EEx2^Br7-9IIC9~U2@oGDM_1xpC}(ck zHgtV0O3k5&VfPQ79H=e|0RYbHLv>v<4OK%flmOF`@(Kn-x+frW8kf`h7>L}JqME$i%0Zx!d3kYle8Y9_O{Y_G&l zAZCteW{@Pv0H~OugkksI=u!U@1OSfy?b^?^$wtPrF}Q`9zoogN#F!d|vbuci+_hgU z6=O-rB_6aO-gDKK5*YxFPY^!isx2iXu;&sF+W#8@00+;lKWePLJYmK--{oRlkFvG) z(vxQfjP001cn1^@s6z>|W`00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3$s2F$4pbMwI{n2GdDI zK~z}7rI%}rT~!sw|7-7a?z!jOSEn#j$q0bS222k9=q& z!Q8>1&oXn5AQ4H&)yAaKTI)+eqmX#QTKltGZawzuvLN5NiNyBZ+xG+Fo?O0wTrTH% zo(~~1AR;g`Y^tG5h%gLQtu{r>{5`)bxc8$U`I}x6@~7W#yOtq;=eq8@RFIfpqrcwLWk|l&-Q8Wv<$P#01!jYG2a$y1 z77<1YLqmg2^5n*k-}=u%01y|049TD8^TlisWTE15SgXOz^8^wLKDSmwC6n-d4~0U> zF_HP@#oPh_o_uWEXPD(ptFP|#jIIK(EfT_k>vtgIbwS7#$ar0FGaV2zGcVTYD!MvX zdPH)^kzZ~5A^^~{k8chVLu2dKbq84wFuLBd3{JKPtFssztD@O#LhBe(x(I?Iu3D9c zlm?n>fVP+R$SELBfO2^#&N{Z!i5WLY;ZUyVLnWhtoEw}&5)#ViFJSG4o3Z7?pGKj$ z9?kk7`d)tueQzAW+O?g?20jd5dO3qSa>c74rL-~I8yur(YY=#_CI+XbWg{t*!_de$ z-o2?8*T47n+5ZZq_1LuS>sZlwJx;!KKi+w57hoJPr?VLA#PA%C>Y?5$i1@}_(etfU z)3cZnk&9X-1c?$hzUOlbR@61ueGIw622`e+)B7{WZ>>VE==nr^qp*w}e$EBkq;<11 z4x%W*s?}RTM2nX0n(iHlQw?%ti=S-*Kj*?Sb~swwfQZ1DDbbn1%rJ)GIQbZ6d-#fIw&C>9)OI}X-7r~F+Axe~9O z7&I`thnN|MAKvux`fEyCyE+AoskTg;B|)M9DRW2?MjR`6o{MZ&z)}dUYaqjy6+;Q* zla|ZpsxN;SLSQu21njr{x68T~bnW;dTVQ4)yT_khj zSrSAhi^22tNX58+wn0+Cd0Hv0Y83@xv(tU(GO;$`G=foea2f$xFBm6m7E=>35@i}A z>oz_!3)$6sBDEGj8Xjpx((}QB0k+H6Ourkv(2R`X2M+H1t!ceajCp8$G?rm#A!Kmb z60|3g3DAfXs?~&yN*`^xPXJ)|U1x>?JXC(G9!crXoL;*O0YU^g-`|J;Jh12P*Cysc z06-_|zNxB0qoE<4+=4gYViF=iy`G|8O)UcV`)D}`bH<*#Uz=d2L+AU$NXp#Bv)|S% zq?1GWTr;#5_wDLEQC$=Q0NP{^)uyzm)fA+Y0}(GN$H}8sQ)t#xZH#&F@|^P^U)g)C zM#SGO_eGHq0j!;FBa4ZdK;)zUY#3S+_wK&yOk+t10I;9=VHBC9T20}&`76#sdId~X z6{4nzy;Akzh4L*3+0}a@v=#@;eMuxJn7Op(?*$P-*euF@NyJRwy5sZb;uRRsgOiweB>P)e{rQeSA-lq{DL-y z4xB%0BOwA1$?0Vx2~dD?zlp8Ifr~xre}VwO$kBg4o~CAaY&eAwc>oqt7BKp@f==w< z$kEfkSt`epkb}>&Wv2ZX`fUsZAo9WNWBRw)fAD#>|2G5xhQ4}&hmrQNSz0Qkv+@B5eM)21Zilf8Go zy18ASz%m9i?TteaGws9jjJz!U_y_Mluw2i70ck(V0nU5%!2kdN07*qoM6N<$f=$hI A%>V!Z literal 0 HcmV?d00001 diff --git a/markers/marker-shadow.png b/markers/marker-shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..9fd2979532a19a15b824ce763c76e04a8dafadfb GIT binary patch literal 618 zcmV-w0+s!VP)ke9$Lam@{1K@O ze*LXqlKQHiv=gx+V^Cbb2?z@ISBQ*3amF;9UJ3SBg(N|710TLamQmYZ&Qjn2LuO<* zCZlB4n%@pc&7NNnY1}x+NWpHlq`OJEo|`aYN9<`RBUB+79g;>dgb6YlfN#kGL?lO_ z!6~M^7sOnbsUkKk<@Ysie&`G>ruxH&Mgy&8;i=A zB9OO!xR{AyODw>DS-q5YM{0ExFEAzt zm>RdS+ssW(-8|?xr0(?$vBVB*%(xDLtq3Hf0I5yFm<_g=W2`QWAax{1rWVH=I!VrP zs(rTFX@W#t$hXNvbgX`gK&^w_YD;CQ!B@e0QbLIWaKAXQe2-kkloo;{iF#6}z!4=W zi$giRj1{ zt;2w`VSCF#WE&*ev7jpsC=6175@(~nTE2;7M-L((0bH@yG}-TB$R~WXd?tA$s3|%y zA`9$sA(>F%J3ioz<-LJl*^o1|w84l>HBR`>3l9c8$5Xr@xCiIQ7{x$fMCzOk_-M=% z+{a_Q#;42`#KfUte@$NT77uaTz?b-fBe)1s5XE$yA79fm?KqM^VgLXD07*qoM6N<$ Ef<_J(9smFU literal 0 HcmV?d00001 diff --git a/sdeCharts.js b/sdeCharts.js new file mode 100644 index 0000000..7bbc9c4 --- /dev/null +++ b/sdeCharts.js @@ -0,0 +1,971 @@ +function updateChart(){ + if (lastInstanceNo > 0) { + const canvas = []; + for (i = 1; i < lastInstanceNo + 1; i++) { + canvas[i] = document.getElementById('chart' + i); + clearCanvasAndChart(canvas[i], i); + } + } + const yScaleType = document.getElementById('scaleType').checked ? 'logarithmic' : 'linear'; // Check the checkbox state + for (i = 0; i < dataSheetNames.length; i++) { + sheetName = dataSheetNames[i]; + sheetsToDisplay[dataSheetNames[i]] = document.getElementById(dataSheetNamesCheckboxes[i]).checked ? true : false; // Check the checkbox state + } + for (i = 0; i < subChartNames.length; i++) { + subName = subChartNames[i]; + subsToDisplay[subName] = document.getElementById(subName).checked ? true : false; // Check the checkbox state + } + lastInstanceNo = 0; + blankSheets = {}; + setBlanksForCharting(selectedSampleMeasurements); + for (sheetName in sheetsToDisplay) { + if (sheetsToDisplay[sheetName] && chemicalTypeHasData(sheetName)) { + lastInstanceNo = displayCharts(sheetName, lastInstanceNo, yScaleType); + } + } +console.log('lastInstanceNo ',lastInstanceNo); + sampleMap(selectedMeas, yScaleType); + filenameDisplay(); +} + +function displayCharts(sheetName, instanceNo, yScaleType) { +// const { unitTitle, selectedMeas } = dataForCharting(selectedSampleMeasurements, sheetName); + if(sheetName === 'Physical Data') { + retData = dataForPSDCharting(selectedSampleMeasurements, sheetName); + unitTitle = retData['unitTitle']; +//console.log('unitTitle displayCharts ',unitTitle); + sizes = retData['sizes']; + selectedMeas = retData['measChart']; +//console.log(sizes); +//console.log('selectedMeas ', selectedMeas); + instanceNo += 1; + displayPSDChart(sizes, selectedMeas, sheetName, instanceNo, yScaleType, unitTitle); + } else { + retData = dataForCharting(selectedSampleMeasurements, sheetName); + unitTitle = retData['unitTitle']; +//console.log('unitTitle displayCharts ',unitTitle); + selectedMeas = retData['measChart']; + +//console.log('selectedMeas ', selectedMeas); + if (subsToDisplay['samplegroup']) { + instanceNo += 1; + displaySampleChart(selectedMeas, sheetName, instanceNo, yScaleType, unitTitle); + } + if (subsToDisplay['chemicalgroup']) { + instanceNo += 1; + displayChemicalChart(selectedMeas, sheetName, instanceNo, yScaleType, unitTitle); + } + if (sheetName === 'PAH data' && subsToDisplay['gorhamtest']) { + instanceNo += 1; + selectedSums = sumsForGorhamCharting(selectedSampleMeasurements); + displayGorhamTest(selectedSums, sheetName, instanceNo, yScaleType, unitTitle); + } + if (sheetName === 'PAH data' && subsToDisplay['totalHC']) { + instanceNo += 1; + retData = sumsForTotalHCCharting(selectedSampleMeasurements); + unitTitle = retData['unitTitle']; + selectedSums = retData['measChart']; + displayTotalHC(selectedSums, sheetName, instanceNo, yScaleType, unitTitle); + } + if (sheetName === 'PCB data' && subsToDisplay['congenertest']) { + instanceNo += 1; + selectedSums = sumsForCongenerCharting(selectedSampleMeasurements); + displayCongener(selectedSums, sheetName, instanceNo, yScaleType, unitTitle); + } + } + // Display the canvas +//console.log('Display the canvas ',instanceNo); + return instanceNo +} + +function dataForCharting(selected, sheetName) { + const datesSampled = Object.keys(selected); + ct = sheetName; + unitTitle = blankSheets[ct]['Unit of measurement']; + measChart = {}; +// for (const ds in selected) { + datesSampled.sort(); + datesSampled.forEach (ds => { + if (!(selected[ds][ct] == undefined || selected[ds][ct] == null)) { + for (const c in selected[ds][ct].chemicals) { + if (measChart[c] == undefined || measChart[c] == null) { + measChart[c] = {}; + } +// for (const s in selected[ds][ct].chemicals[c].samples) { + for (const s in selectedSampleInfo[ds].position) { + if (selected[ds][ct].chemicals[c].samples[s] == undefined || selected[ds][ct].chemicals[c].samples[s] == null) { + measChart[c][ds + ': ' + s] = 0.0; + } else { + measChart[c][ds + ': ' + s] = selected[ds][ct].chemicals[c].samples[s]; + } + } + } + } else { + // Have to deal with samples without measurements set everything to zero + for (const c in blankSheets[ct].chemicals) { + if (measChart[c] == undefined || measChart[c] == null) { + measChart[c] = {}; + } + for (const s in selectedSampleInfo[ds].position) { + measChart[c][ds + ': ' + s] = 0.0; + } + } + } + }); + unitTitle = blankSheets[ct]['Unit of measurement']; + return {unitTitle, measChart} +} + +function sumsForCongenerCharting(selected) { + const datesSampled = Object.keys(selected); + measChart = {}; +// for (const ds in selected) { + datesSampled.sort(); + datesSampled.forEach (ds => { + if (!(selected[ds]['PCB data'] == undefined || selected[ds]['PCB data'] == null)) { +// for (const s in selected[ds]['PCB data'].congenerTest) { + for (const s in selectedSampleInfo[ds].position) { +console.log(ds,s); + if (selected[ds]['PCB data'].congenerTest[s] == undefined || selected[ds]['PCB data'].congenerTest[s] == null) { + measChart[ds + ': ' + s] = { ICES7 : 0.0, All : 0.0 }; + } else { + measChart[ds + ': ' + s] = selected[ds]['PCB data'].congenerTest[s]; + } + } + } else { + for (const s in selectedSampleInfo[ds].position) { + measChart[ds + ': ' + s] = { All : 0.0, ICES7 : 0.0}; + } + } + }); + return measChart +} + +function sumsForGorhamCharting(selected) { + const datesSampled = Object.keys(selected); + measChart = {}; +// for (const ds in selected) { + datesSampled.sort(); + datesSampled.forEach (ds => { + if (!(selected[ds][ct] == undefined || selected[ds][ct] == null)) { + for (const s in selected[ds]['PAH data'].gorhamTest) { + if (selected[ds]['PAH data'].gorhamTest[s] == undefined || selected[ds]['PAH data'].gorhamTest[s] == null) { + measChart[ds + ': ' + s] = { hmwSum : 0.0, lmwSum : 0.0}; + } else { + measChart[ds + ': ' + s] = selected[ds]['PAH data'].gorhamTest[s]; + } + } + } else { + for (const s in selectedSampleInfo[ds].position) { + measChart[ds + ': ' + s] = { hmwSum : 0.0, lmwSum : 0.0}; + } + } + }); + return measChart +} + +function sumsForTotalHCCharting(selected) { + const datesSampled = Object.keys(selected); + unitTitle = blankSheets[ct]['totalHCUnit']; + measChart = {}; +// for (const ds in selected) { + datesSampled.sort(); + datesSampled.forEach (ds => { + if (!(selected[ds][ct] == undefined || selected[ds][ct] == null)) { + for (const s in selected[ds]['PAH data'].totalHC) { + if (selected[ds]['PAH data'].total[s] == undefined || selected[ds]['PAH data'].totalHC[s] == null) { + measChart[ds + ': ' + s] = { totalHC : 0.0, fractionPAH : 0.0}; + } else { +// measChart[ds + ': ' + s] = {totalHC : selected[ds]['PAH data'].totalHC[s], fractionPAH : (selected[ds]['PAH data'].total[s] / (1000 * selected[ds]['PAH data'].totalHC[s]))}; + measChart[ds + ': ' + s] = {totalHC : selected[ds]['PAH data'].totalHC[s], fractionPAH : selected[ds]['PAH data'].total[s] / 1000}; + } + } + } else { + for (const s in selectedSampleInfo[ds].position) { + measChart[ds + ': ' + s] = { totalHC : 0.0, fractionPAH : 0.0}; + } + } + }); + return {unitTitle, measChart} +} + + + +function setBlanksForCharting(selected) { + const datesSampled = Object.keys(selected); + // Have to deal with samples without measurements set everything to zero + for (const ds in selected) { + for (const ct in selected[ds]) { + if (blankSheets[ct] == null || blankSheets[ct] == undefined) { + if (!(selected[ds][ct] == undefined || selected[ds][ct] == null)) { + blankSheets[ct] = selected[ds][ct]; + } + } + } + } + return +} + +function dataForPSDCharting(selected, sheetName) { + const datesSampled = Object.keys(selected); + ct = sheetName; +// unitTitle = selected[datesSampled[0]][ct]['Unit of measurement']; + unitTitle = blankSheets[ct]['Unit of measurement']; + measChart = {}; + sizes = null; +// for (const ds in selected) { + datesSampled.sort(); + datesSampled.forEach (ds => { + if (!(selected[ds][ct] == undefined || selected[ds][ct] == null)) { + if (!sizes) { + sizes = selected[ds][ct].sizes; + sizes = sizes.map(phiSize => Math.pow(2, -phiSize)); + } + for (const s in selected[ds][ct].samples) { + measChart[ds + ': ' + s] = selected[ds][ct].samples[s].psd; + } + } else { + for (const s in selectedSampleInfo[ds].position) { + measChart[ds + ': ' + s] = new Array(42).fill(0.0); + } + } + }); +//console.log('dataforPSD ', unitTitle,sizes,measChart); + return {unitTitle, sizes, measChart} +} + +function displayPSDChart(sizes, meas, sheetName, instanceNo, yLogLin, unitTitle) { + createCanvas(instanceNo); + const convas = document.getElementById("chart" + instanceNo); + convas.style.display = "block"; + instanceType[instanceNo] = 'PSD'; + instanceSheet[instanceNo] = sheetName; + // Extract sample names from the PSD data structure + const sampleNames = Object.keys(meas); + + // Create datasets for each sample + const datasets = sampleNames.map((sampleName, index) => { + return { + label: sampleName, + data: meas[sampleName], +// borderColor: getRandomColor(), // Function to generate random color + borderWidth: 2, + fill: false, + }; + }); + + // Chart configuration + const chartConfig = { + type: 'line', + data: { + labels: sizes, + datasets: datasets, + }, + options: { + plugins: { + title: { + display: true, + text: sheetName + }, + legend: { + display: false, + position: 'bottom', + labels: { + font: { // Customize legend label font + size: 14, + weight: 'italic', + padding: 10 + } + } + }, + // Add a custom plugin for interactivity + selectSample: { + highlightedSample: null, + }, + }, + scales: { + x: { + type: 'logarithmic', + position: 'bottom', + title: { + display: true, + text: 'mm' + } + }, + y: { + beginAtZero: true, + type: yLogLin, + title: { + display: true, + text: unitTitle + } + } + }, + autocolors: { + mode: 'label' + } + } + }; +// }; + + +const ctx = document.getElementById('chart' + instanceNo).getContext('2d'); +chartInstance[instanceNo] = new Chart(ctx, chartConfig); + +Chart.register({ +id: 'selectSample', +afterDraw: function (chart, args, options) { + const highlightedSample = chart.options.plugins.selectSample.highlightedSample; + + if (highlightedSample) { +//console.log('highlightedSample ', highlightedSample); + const datasetIndex = chart.data.datasets.findIndex(dataset => dataset.label === highlightedSample); + + if (datasetIndex !== -1) { + const dataset = chart.data.datasets[datasetIndex]; + dataset.borderWidth = 4; + dataset.borderColor = 'red'; + } + } +}, +}); +} + +// Function to generate a random color +function getRandomColor() { +const letters = '0123456789ABCDEF'; +let color = '#'; +for (let i = 0; i < 6; i++) { +color += letters[Math.floor(Math.random() * 16)]; +} +return color; +} + +function displayPSDHighlight(meas, yLogLin, instanceNo, clickedMapSample) { + clickedSamples = findSamplesInSameLocation(clickedMapSample); + const allChemicals = Object.keys(meas); + let clickedIndexes = []; + clickedSamples.forEach (clickedSample => { + index = -1; + for (const sample in meas[allChemicals[0]]) { + index += 1; + if (sample.includes(clickedSample)) { + clickedIndexes.push(index); + } + } + }); + clickedIndexes.forEach(item => { +//console.log('displayPSDHighlight',clickedIndexes); +//console.log('item ',item); +chartInstance[instanceNo].options.plugins.selectSample.highlightedSample = item; + }); + // Update the chart + chartInstance[instanceNo].update(); +} + +// Helper function to remove highlighting +function removePSDHighlight() { +chartInstance.options.plugins.selectSample.highlightedSample = null; +chartInstance.update(); +} + +function displaySampleChart(meas, sheetName, instanceNo, yLogLin, unitTitle) { + createCanvas(instanceNo); + const convas = document.getElementById("chart" + instanceNo); + convas.style.display = "block"; + instanceType[instanceNo] = 'chemical'; + instanceSheet[instanceNo] = sheetName; + const allChemicals = Object.keys(meas); + const allSamples = Object.keys(meas[allChemicals[0]]); // Assuming all samples have the same chemicals + const datasets = allChemicals.map((chemical, index) => { + const data = allSamples.map(sample => meas[chemical][sample]); // Using the first concentration value for simplicity + return { + label: chemical, + data: data, + borderWidth: 1, + yAxisID: 'y', + }; + }); + displayAnyChart(meas, allSamples,datasets,instanceNo,sheetName,unitTitle,yLogLin); +} + +function highlightMapLocation(clickedIndex) { + console.log(clickedIndex); + return +} + +function displayAnyChart(meas, all, datasets, instanceNo, title, yTitle, yLogLin) { + //console.log('chartInstance ', instanceNo); + // const ctx = document.getElementById('chart' + instanceNo).getContext('2d'); + const ctx = document.getElementById('chart' + instanceNo); + //console.log(sheetName, instanceNo); + stanGraph = { + type: 'bar', + data: { + labels: all, + datasets: datasets + }, + options: { + interaction: { + mode: 'index', + axis: 'xy' + }, + plugins: { + title: { + display: true, + text: title + }, + legend: { + display: false, + position: 'top', + labels: { + font: { // Customize legend label font + size: 14, + weight: 'italic', + padding: 10 + } + } + }, + zoom: { + pan: { + // pan options and/or events + enabled: true, + mode: 'xy', + modifierKey: 'shift', + }, + limits: { + y: { min: 0 } + // axis limits + }, + zoom: { + // zoom options and/or events + wheel: { + enabled: true, + }, + drag: { + enabled: true, + }, + mode: 'xy' + } + }, + }, + indexAxis: 'x', + scales: { + x: { + beginAtZero: true, + ticks: { + maxRotation: 90, + minRotation: 90, + autoSkip: false, + } + }, + y: { + beginAtZero: true, + type: yLogLin, + title: { + display: true, + text: yTitle, + position: 'left', + } + }, + }, + autocolors: { + mode: 'label' + } + } + }; + if (title.includes('hydrocarbon')) { + stanGraph.options.scales.y1 = { + beginAtZero: true, + type: yLogLin, + position: 'right', + title: { + display: true, + text: 'Total PAHs as Fraction of Total Hydrocarbons', + position: 'right', + } + }; + console.log(stanGraph); + }; + chartInstance[instanceNo] = new Chart(ctx, stanGraph); + //clickableScales(chartInstance[instanceNo], 1); + function clickableScales(chart, canvas, click) { + //console.log(chart); + const height = chart.scales.x.height; + const top = chart.scales.x.top; + const bottom = chart.scales.x.bottom; + const left = chart.scales.x.left; + const right = chart.scales.x.maxWidth / chart.scales.x.ticks.length; + //console.log('click scales - height,top,bottom,left,right', height,top,bottom,left,right); + let resetCoordinates = canvas.getBoundingClientRect(); + //console.log('click - raw x y', click.clientX, click.clientY); + const x = click.clientX - resetCoordinates.left; + const y = click.clientY - resetCoordinates.top; + //console.log('click - corrrected x y', x, y); + //console.log('chart.scales.x.ticks.length',chart.scales.x.ticks.length); + if (y >= top && y <= bottom) { + for (let i = 0; i < chart.scales.x.ticks.length; i++) { + if (x >= left + (right * i) && x <= left + (right * (i + 1))) { + console.log('x label', i); + const regexPattern = /^(\S+): (.+)$/; + const matchResult = all[i].match(regexPattern); + if (matchResult) { + // Extracted parts + const dateSampled = matchResult[1]; + const sample = matchResult[2]; + + // Output the results + console.log("Date Sampled: ", dateSampled); + console.log("Sample:", sample); + createHighlights(meas, yLogLin, dateSampled, sample, null); + } else { + console.log("String format doesn't match the expected pattern."); + }; + } + } + } + + } + ctx.addEventListener('click', (e) => { + clickableScales(chartInstance[instanceNo], ctx, e); + chartInstance[instanceNo].resize(); + //chartInstance[instanceNo].updtae(); + }); + const xLabels = document.querySelectorAll('#chart' + instanceNo + '.chartjs-axis-x .chartjs-axis-label'); + xLabels.forEach((label, index) => { + label.addEventListener('click', () => { + console.log('about to toggle'); + toggleHighlightMapLocation(index); + }); + }); + createResetZoomButton(chartInstance[instanceNo], instanceNo); +} + + +function displayChemicalChart(meas, sheetName, instanceNo, yLogLin, unitTitle) { +createCanvas(instanceNo); +const convas = document.getElementById("chart" + instanceNo); +convas.style.display = "block"; +instanceType[instanceNo] = 'sample'; +instanceSheet[instanceNo] = sheetName; +const allChemicals = Object.keys(meas); +const allSamples = Object.keys(meas[allChemicals[0]]); // Assuming all samples have the same chemicals +const datasets = allSamples.map((sample, index) => { + const data = allChemicals.map(chemical => meas[chemical][sample]); // Using the first concentration value for simplicity + return { + label: sample, + data: data, + borderWidth: 1, + yAxisID: 'y', + }; +}); +displayAnyChart(meas, allChemicals,datasets,instanceNo,sheetName,unitTitle,yLogLin); +chartInstance[instanceNo].options.plugins.annotation.annotations = {}; +let allal = actionLevels[sheetName]; + + +if(allal) { + allChemicals.forEach (chemical => { + let al = allal[chemical] ? allal[chemical].slice() : null; + alMax = 0; + al2 = false; + if(al) { + item = allChemicals.indexOf(chemical); + for (i = 0; i < 2; i++) { + if (al[i] > 0.0) { +// borderColor = actionLevelColors[i]; + // Get the units right between action levels and sample measurements + // Action levels are all in mg/kg but PAHs in ug/kg + if (sheetName === 'PAH data') { + al[i] = al[i] * 1000; + } + if (i === 1) { + al2 = true; + } + chartLine(instanceNo,chemical + i,item-0.5,item+0.5,al[i],al[i],actionLevelColors[i],actionLevelDashes[i]); + } + } + if (al[1] > alMax) { + alMax = al[1]; + } + } + }); + maxConc = findMaxConcentration(meas); +//console.log('maxConc ',maxConc); +//console.log(meas); + if (maxConc > alMax) { + alMax = maxConc; + } + alX = allChemicals.length * 0.03; + chartLabel(instanceNo,alX,0.8*alMax,actionLevelColors[0],'Action Level 1 '); + chartLine(instanceNo,'Legend - Action Level 1',alX*1.4,alX*2.5,0.8*alMax,0.8*alMax,actionLevelColors[0],actionLevelDashes[0]); + if (al2) { + chartLabel(instanceNo,alX,0.9*alMax,actionLevelColors[1],'Action Level 2 '); + chartLine(instanceNo,'Legend - Action Level 2',alX*1.4,alX*2.5,0.9*alMax,0.9*alMax,actionLevelColors[1],actionLevelDashes[1]); + } +} + // Update the chart + chartInstance[instanceNo].update(); +} + +// chartInstance[3].resetZoom(); +// + +// Function to find the maximum concentration +function findMaxConcentration(data) { +let maxConcentration = -Infinity; + +for (const chemical in data) { +for (const sample in data[chemical]) { + const concentration = data[chemical][sample]; + if (concentration > maxConcentration) { + maxConcentration = concentration; + } +} +} + +return maxConcentration; +} + +function chartLine(instanceNo,name,xMin,xMax,yMin,yMax,borderColor,borderDash) { +// chartInstance[instanceNo].options.plugins.annotation.annotations.push({ + chartInstance[instanceNo].options.plugins.annotation.annotations[('line-' + instanceNo + '-' + name)] = { + type: 'line', + yMin: yMin, + yMax: yMax, + xMin: xMin, + xMax: xMax, + borderColor: borderColor, + borderDash: borderDash, + borderWidth: 2, + }; +} + +function chartLabel(instanceNo,xValue,yValue,borderColor,label) { +// chartInstance[instanceNo].options.plugins.annotation.annotations.push({ + chartInstance[instanceNo].options.plugins.annotation.annotations[('label-' + instanceNo + '-'+label)] = { + type: 'label', + enabled: true, + xValue: xValue, + yValue: yValue, + color: borderColor, + backgroundColor: 'rgba(200,200,200)', + content: [label], + font: { + size: 10 + } + }; +} + +function displayGorhamTest(sums, sheetName, instanceNo, yLogLin, unitTitle) { + createCanvas(instanceNo); + const convas = document.getElementById("chart" + instanceNo); + convas.style.display = "block"; + instanceType[instanceNo] = 'gorham'; +instanceSheet[instanceNo] = sheetName; + const lmw = ['Acenaphthene', 'Acenaphthylene', 'Anthracene', 'Fluorene', 'C1-Naphthalenes', 'Naphthalene', 'Phenanthrene']; + const hmw = ['Benz[a]anthracene', 'Benzo[a]pyrene', 'Chrysene', 'Dibenz[a,h]anthracene', 'Fluoranthene', 'Pyrene']; + const LMW = { + ERL: 552, + ERM: 3160 + }; + const HMW = { + ERL: 1700, + ERM: 9600 + }; + + const samples = Object.keys(sums); + const lmwSumData = samples.map(sample => sums[sample].lmwSum); + const hmwSumData = samples.map(sample => sums[sample].hmwSum); + datasets = [ + { + label: 'LMW Sums', + backgroundColor: 'rgba(54, 162, 235, 0.5)', + borderColor: 'rgba(54, 162, 235, 1)', + borderWidth: 1, + data: lmwSumData, + yAxisID: 'y', + }, + { + label: 'HMW Sums', + backgroundColor: 'rgba(255, 99, 132, 0.5)', + borderColor: 'rgba(255, 99, 132, 1)', + borderWidth: 1, + data: hmwSumData, + yAxisID: 'y', + }, + ]; + +displayAnyChart(sums, samples,datasets,instanceNo,sheetName + ': Gorham Test Protocol',unitTitle,yLogLin); + + chartInstance[instanceNo].options.plugins.annotation.annotations = {}; + chartLine(instanceNo,'LMW.ERL',0,samples.length,LMW.ERL,LMW.ERL,'rgba(0, 0, 255, 0.5)',[3,3]); + chartLine(instanceNo,'LMW.ERM',0,samples.length,LMW.ERM,LMW.ERM,'rgba(0, 0, 255, 0.5)',[5,5]); + chartLine(instanceNo,'HMW.ERL',0,samples.length,HMW.ERL,HMW.ERL,'rgba(255, 0, 0, 0.5)',[3,3]); + chartLine(instanceNo,'HMW.ERM',0,samples.length,HMW.ERM,HMW.ERM,'rgba(255, 0, 0, 0.5)',[5,5]); + gorX = samples.length * 0.05; + gorMax = HMW.ERM; + for (const sample in sums) { + if (sums[sample].lmwSum > gorMax) { + gorMax = sums[sample].lmwSum; + } + if (sums[sample].hmwSum > gorMax) { + gorMax = sums[sample].hmwSum; + } + } + chartLabel(instanceNo,gorX,0.75*gorMax,'rgba(0, 0, 255, 0.5)','LMW ERL '); + chartLine(instanceNo,'Legend - LMW.ERL',gorX*1.2,gorX*2.2,0.75*gorMax,0.75*gorMax,'rgba(0, 0, 255, 0.5)',actionLevelDashes[0]); + chartLabel(instanceNo,gorX,0.8*gorMax,'rgba(0, 0, 255, 0.5)','LMW ERM '); + chartLine(instanceNo,'Legend - LMW.ERM',gorX*1.2,gorX*2.2,0.8*gorMax,0.8*gorMax,'rgba(0, 0, 255, 0.5)',actionLevelDashes[1]); + chartLabel(instanceNo,gorX,0.9*gorMax,'rgba(255, 0, 0, 0.5)','HMW ERL '); + chartLine(instanceNo,'Legend - HMW.ERL',gorX*1.2,gorX*2.2,0.9*gorMax,0.9*gorMax,'rgba(255, 0, 0, 0.5)',actionLevelDashes[0]); + chartLabel(instanceNo,gorX,0.95*gorMax,'rgba(255, 0, 0, 0.5)','HMW ERM '); + chartLine(instanceNo,'Legend - HMW.ERM',gorX*1.2,gorX*2.2,0.95*gorMax,0.95*gorMax,'rgba(255, 0, 0, 0.5)',actionLevelDashes[1]); + // Update the chart + chartInstance[instanceNo].update(); +} + +function displayCongener(sums, sheetName, instanceNo, yLogLin, unitTitle) { + createCanvas(instanceNo); + const convas = document.getElementById("chart" + instanceNo); + convas.style.display = "block"; + instanceType[instanceNo] = 'congener'; +instanceSheet[instanceNo] = sheetName; + const samples = Object.keys(sums); + const ICES7SumData = samples.map(sample => sums[sample].ICES7); + const allSumData = samples.map(sample => sums[sample].All); + const datasets = [ + { + label: 'ICES7', + backgroundColor: 'rgba(54, 162, 235, 0.5)', + borderColor: 'rgba(54, 162, 235, 1)', + borderWidth: 1, + data: ICES7SumData, + yAxisID: 'y', + }, + { + label: 'All', + backgroundColor: 'rgba(255, 99, 132, 0.5)', + borderColor: 'rgba(255, 99, 132, 1)', + borderWidth: 1, + data: allSumData, + yAxisID: 'y', + }, + ]; +displayAnyChart(sums, samples,datasets,instanceNo,sheetName + ': Congener Sums',unitTitle,yLogLin); + chartInstance[instanceNo].options.plugins.annotation.annotations = {}; + chartLine(instanceNo,'ICES7 Action Level 1',0,samples.length,0.01,0.01,'rgba(0, 0, 255, 0.5)',[3,3]); + chartLine(instanceNo,'All Action Level 1',0,samples.length,0.02,0.02,'rgba(255, 0, 0, 0.5)',[3,3]); + chartLine(instanceNo,'All Action Level 2',0,samples.length,0.2,0.2,'rgba(255, 0, 0, 0.5)',[5,5]); + gorX = samples.length * 0.1; + gorMax = 0.2; + for (const sample in sums) { + if (sums[sample].ICES7 > gorMax) { + gorMax = sums[sample].ICES7; + } + if (sums[sample].All > gorMax) { + gorMax = sums[sample].All; + } + } + chartLabel(instanceNo,gorX,0.75*gorMax,'rgba(0, 0, 255, 0.5)','ICES7 Action Level 1 '); + chartLine(instanceNo,'Legend - ICES7 AL1',gorX*1.2,gorX*2.2,0.75*gorMax,0.75*gorMax,'rgba(0, 0, 255, 0.5)',actionLevelDashes[0]); + chartLabel(instanceNo,gorX,0.9*gorMax,'rgba(255, 0, 0, 0.5)','All Action Level 1 '); + chartLine(instanceNo,'Legend - All AL1',gorX*1.2,gorX*2.2,0.9*gorMax,0.9*gorMax,'rgba(255, 0, 0, 0.5)',actionLevelDashes[0]); + chartLabel(instanceNo,gorX,0.95*gorMax,'rgba(255, 0, 0, 0.5)','All Action Level 2 '); + chartLine(instanceNo,'Legend - All AL2',gorX*1.2,gorX*2.2,0.95*gorMax,0.95*gorMax,'rgba(255, 0, 0, 0.5)',actionLevelDashes[1]); + // Update the chart + chartInstance[instanceNo].update(); +} + +function displayTotalHC(sums, sheetName, instanceNo, yLogLin, unitTitle) { + createCanvas(instanceNo); + const convas = document.getElementById("chart" + instanceNo); + convas.style.display = "block"; + instanceType[instanceNo] = 'totalHC'; +instanceSheet[instanceNo] = sheetName; + const samples = Object.keys(sums); + const totalHC = samples.map(sample => sums[sample].totalHC); + const fractionPAH = samples.map(sample => sums[sample].fractionPAH); + const datasets = [ + { + label: 'totalHC', + backgroundColor: 'rgba(54, 162, 235, 0.5)', + borderColor: 'rgba(54, 162, 235, 1)', + borderWidth: 1, + data: totalHC, + yAxisID: 'y', + }, + { + label: 'fractionPAH', + backgroundColor: 'rgba(255, 99, 132, 0.5)', + borderColor: 'rgba(255, 99, 132, 1)', + borderWidth: 1, + data: fractionPAH, + yAxisID: 'y1', + }, + ]; +displayAnyChart(sums, samples,datasets,instanceNo,sheetName + ': Total hydrocarbon & Total PAH/THC',unitTitle,yLogLin); +y1Title = 'Fraction PAH of THC'; +/* chartInstance[instanceNo].options.scales.push({ + y1: { beginAtZero: true, + type: yLogLin, + title: { + display: true, + text: y1Title, + position: 'right', + } + } + });*/ + +/* chartInstance[instanceNo].scales[('y1')] = { + y1: { beginAtZero: true, + type: yLogLin, + position: 'right', + title: { + display: true, + text: 'Something', + position: 'right', + } + }, + };*/ +chartInstance[instanceNo].options.plugins.legend.display = true; + + /*chartInstance[instanceNo].options.plugins.annotation.annotations = {}; + chartLine(instanceNo,'ICES7 Action Level 1',0,samples.length,0.01,0.01,'rgba(0, 0, 255, 0.5)',[3,3]); + chartLine(instanceNo,'All Action Level 1',0,samples.length,0.02,0.02,'rgba(255, 0, 0, 0.5)',[3,3]); + chartLine(instanceNo,'All Action Level 2',0,samples.length,0.2,0.2,'rgba(255, 0, 0, 0.5)',[5,5]); + gorX = samples.length * 0.1; + gorMax = 0.2; + for (const sample in sums) { + if (sums[sample].totalHC > gorMax) { + gorMax = sums[sample].ICES7; + } + if (sums[sample].All > gorMax) { + gorMax = sums[sample].All; + } + } + chartLabel(instanceNo,gorX,0.75*gorMax,'rgba(0, 0, 255, 0.5)','ICES7 Action Level 1 '); + chartLine(instanceNo,'Legend - ICES7 AL1',gorX*1.2,gorX*2.2,0.75*gorMax,0.75*gorMax,'rgba(0, 0, 255, 0.5)',actionLevelDashes[0]); + chartLabel(instanceNo,gorX,0.9*gorMax,'rgba(255, 0, 0, 0.5)','All Action Level 1 '); + chartLine(instanceNo,'Legend - All AL1',gorX*1.2,gorX*2.2,0.9*gorMax,0.9*gorMax,'rgba(255, 0, 0, 0.5)',actionLevelDashes[0]); + chartLabel(instanceNo,gorX,0.95*gorMax,'rgba(255, 0, 0, 0.5)','All Action Level 2 '); + chartLine(instanceNo,'Legend - All AL2',gorX*1.2,gorX*2.2,0.95*gorMax,0.95*gorMax,'rgba(255, 0, 0, 0.5)',actionLevelDashes[1]);*/ + // Update the chart + chartInstance[instanceNo].update(); +} + + +function findSamplesInSameLocation(clickedMapSample) { + for (ds in selectedSampleInfo) { + for (s in selectedSampleInfo[ds].position) { + if (clickedMapSample === s) { + lat = selectedSampleInfo[ds].position[s]['Position latitude']; + lon = selectedSampleInfo[ds].position[s]['Position longitude']; + } + } + } + clickedMapSamples = []; + for (ds in selectedSampleInfo) { + for (s in selectedSampleInfo[ds].position) { + const testPos = selectedSampleInfo[ds].position[s]; + if (testPos['Position latitude'] === lat && testPos['Position longitude'] === lon) { + clickedMapSamples.push(ds + ': ' + s); + } + } + } + return clickedMapSamples +} + +function createHighlights(meas, linLog, dateSampled, hoveredSample, isMarked) { + const datesSampled = Object.keys(selectedSampleInfo); + datesSampled.sort(); + samples = []; + datesSampled.forEach(dateSampled => { + // for (const dateSampled in selectedSampleInfo) { + const ok = Object.keys(selectedSampleInfo[dateSampled].position); + // noSamples += Object.keys(selectedSampleInfo[dateSampled].position).length; + noSamples += ok.length; + for (const sample in selectedSampleInfo[dateSampled].position) { + samples.push(dateSampled + ': ' + sample); + } + // } + }); + console.log(hoveredSample); + if (!dateSampled) { + clickedSamples = findSamplesInSameLocation(hoveredSample); + console.log('Not dateSampled'); + } else { + clickedSamples = []; + clickedSamples[0] = dateSampled + ': ' + hoveredSample; + console.log('dateSampled'); + } + console.log(clickedSamples); + const allChemicals = Object.keys(meas); + let clickedIndexes = []; + console.log('samples', samples); + console.log('meas[allChemicals[0]]', Object.keys(meas[allChemicals[0]])); + clickedSamples.forEach(clickedSample => { + index = -1; + samples.forEach(sample => { + index += 1; + if (sample === clickedSample) { + clickedIndexes.push(index); + } + }); + }); + console.log(clickedIndexes); + clickedIndexes.forEach(item => { + if (isMarked === null) { + console.log('doing the null bit'); + if (highlighted[item]) { + highlighted[item] = false; + } else { + highlighted[item] = true; + } + } else { + highlighted[item] = !isMarked; + } + }); + console.log(highlighted); + clickedIndexes.forEach(item => { + console.log(item); + for (let i = 1; i < lastInstanceNo + 1; i++) { + if (instanceType[i] === 'gorham' || instanceType[i] === 'chemical' || instanceType[i] === 'congener' || instanceType[i] === 'totalHC') { + if (highlighted[item]) { + displayChartHighlight(meas, linLog, i, dateSampled, item); + } else { + removeChartHighlight(meas, linLog, i, dateSampled, item); + } + } + } + }); +} + +// Function to display the chart based on the clicked sample +function displayChartHighlight(meas, yLogLin, instanceNo, dateSampled, item) { + // Draw a rectangle around the clicked data +console.log('about to highlight',instanceNo,item); + chartInstance[instanceNo].options.plugins.annotation.annotations[('tempBox-' + instanceNo + '-'+item)] = { + type: 'box', + xScaleID: 'x', + yScaleID: 'y', + xMin: item - 0.5, // Adjust based on your data and preferences + xMax: item + 0.5, + borderWidth: 2, + borderColor: 'red', + backgroundColor: 'rgba(255, 0, 0, 0.1)', + id: `tempBox-$(instanceNo)-$(item)`, + }; + // Update the chart + chartInstance[instanceNo].update(); +} + +function removeChartHighlight(meas, yLogLin, instanceNo, dateSampled, item) { +console.log('about to remove highlight',instanceNo,item); + delete chartInstance[instanceNo].options.plugins.annotation.annotations['tempBox-' + instanceNo + '-'+item]; + // Update the chart + chartInstance[instanceNo].update(); +} + + + diff --git a/sdeMaps.js b/sdeMaps.js new file mode 100644 index 0000000..840652a --- /dev/null +++ b/sdeMaps.js @@ -0,0 +1,226 @@ +function sampleMap(meas, linLog) { + // Check if there's an existing map and remove it + if (map) { + map.remove(); + } + // SampleInfo data structure + // Initialize the map + map = L.map('map').setView([54.596, -1.177], 13); // Set the initial center and zoom level + + // Add OpenStreetMap tile layer + L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { + attribution: '© OpenStreetMap contributors' + }).addTo(map); + + latSum = 0; + lonSum = 0; + noLocations = 0; + minLat = null; + maxLat = null; + minLon = null; + maxLon = null; + let hoveredSample = null; + + var greenIcon = L.icon({ + iconUrl: 'blue-marker-icon.png', // Replace with the path to your marker icon + shadowUrl: 'marker-shadow.png', + + iconSize: [38, 95], // size of the icon + shadowSize: [50, 64], // size of the shadow + iconAnchor: [22, 94], // point of the icon which will correspond to marker's location + shadowAnchor: [4, 62], // the same for the shadow + popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor + }); + + // Define a custom marker icon with a specific color + var CustomIcon = L.Icon.extend({ + options: { + shadowUrl: 'marker-shadow.png', + iconSize: [25, 41], // Replace with the size of your marker icon + iconAnchor: [12, 41], // Replace with the anchor point of your marker icon + popupAnchor: [1, -34], // Replace with the popup anchor point of your marker icon + } + }); + // Add markers for each sample + iconNo = 0; + + const datesSampled = Object.keys(selectedSampleInfo); + datesSampled.sort(); + datesSampled.forEach(dateSampled => { + currentIcon = new CustomIcon({ iconUrl: markerPngs[iconNo] }); + iconNo = (iconNo + 1) % 9; + noSamples = 0; + for (const dateSampled in selectedSampleInfo) { + noSamples += Object.keys(selectedSampleInfo[dateSampled].position).length; + } + console.log('noSamples', noSamples); + highlighted = Array(noSamples).fill(false); + for (const sample in selectedSampleInfo[dateSampled].position) { + if (selectedSampleInfo[dateSampled].position[sample]['Position latitude']) { + lat = selectedSampleInfo[dateSampled].position[sample]['Position latitude']; + lon = selectedSampleInfo[dateSampled].position[sample]['Position longitude']; + // Create a marker for each sample + if (lat !== undefined && lon !== undefined) { + lat = parseFloat(lat); + lon = parseFloat(lon); + if (maxLat === null) { + minLat = lat; + maxLat = lat; + minLon = lon; + maxLon = lon; + } else { + if (lat > maxLat) { + maxLat = lat; + } else if (lat < minLat) { + minLat = lat; + } + if (lon > maxLon) { + maxLon = lon; + } else if (lon < minLon) { + minLon = lon; + } + } + // Create a marker for each sample + // const marker = L.marker([lat, lon]).addTo(map).bindPopup(`${sample}
Latitude: ${lat}
Longitude: ${lon}`); + const marker = L.marker([lat, lon], { icon: currentIcon }).addTo(map).bindPopup(`${sample}
Latitude: ${lat}
Longitude: ${lon}`); + /* const marker = L.circleMarker([lat, lon], + {radius: 4, color: 'white', fillColor: 'red', fillOpacity: 1} + ).addTo(map).bindPopup(`${sample}
Latitude: ${lat}
Longitude: ${lon}`); + marker.bindTooltip(sample, { permanent: false, direction: 'top' });*/ + marker.isMarked = false; + + // Add a click event listener to the marker + marker.on('click', function () { + hoveredSample = sample; + createHighlights(meas, linLog, null, hoveredSample, marker.isMarked); + if (!marker.isMarked) { + marker.isMarked = true; + } else { + marker.isMarked = false; + } + // Update the chart - in routintes + //console.log('update ',sample,i); + // chartInstance[i].update(); + }); + + noLocations += 1; + latSum += parseFloat(lat); + lonSum += parseFloat(lon); + }; + } + + } + /* iconNo += 1; + if (iconNo > 8) { + iconNo = 0; + }*/ + console.log(iconNo, dateSampled); + }); + + if (noLocations > 0) { + const centreLat = latSum / noLocations; + const centreLon = lonSum / noLocations; + var bounds = L.latLngBounds([minLat, minLon], [maxLat, maxLon]); + map.fitBounds(bounds); + //console.log('lat,lon ',minLat,minLon, maxLat,maxLon); + /* if (centreLat !== undefined && centreLon !== undefined) { + map.setView(new L.LatLng(centreLat, centreLon), 13); + }*/ + // } + } + +} + +function randomColor() { + return '#' + Math.floor(Math.random() * 16777215).toString(16); +} + +function exportChart() { + const now = new Date(); + const formattedDate = now + .toISOString() + .slice(2, 16) + .replace(/[-T:]/g, ''); // Format: yymmddhhmm + + for (i = 1; i 360) { +// Use proj4js library to convert British National Grid to latitude and longitude +proj4.defs("EPSG:27700", "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +towgs84=446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894 +units=m +no_defs"); +const point = proj4("EPSG:27700", "EPSG:4326", [parseInt(latitude, 10), parseInt(longitude, 10)]); + +return { latitude: point[1], longitude: point[0] }; +} else { +return { latitude: parseCoordinate(latitude), longitude: parseCoordinate(longitude) }; +} + +// If the input doesn't match any recognized format, return null or handle accordingly +return null; +} + diff --git a/sdeSelections.js b/sdeSelections.js new file mode 100644 index 0000000..642f1cd --- /dev/null +++ b/sdeSelections.js @@ -0,0 +1,442 @@ +function openChemicalSelection(sampleMeasurements) { + const chemicalModal = document.getElementById('chemicalModal'); + chemicalModal.style.display = 'block'; + + const sampleCheckboxes = document.getElementById('chemicalCheckboxes'); + chemicalCheckboxes.innerHTML = ''; + + const datesSampled = Object.keys(selectedSampleMeasurements); + + for (chemicalType in selectedSampleMeasurements[datesSampled[0]]) { + if (chemicalType !== 'Physical Data') { + const chemicals = Object.keys(selectedSampleMeasurements[datesSampled[0]][chemicalType].chemicals); + + const checkboxContainer = document.createElement('div'); + checkboxContainer.className = 'checkbox-container'; + + chemicals.forEach(chemical => { + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.id = `chemical`; + checkbox.name = 'chemical'; + checkbox.value = chemical; + checkbox.checked = true; // Initially all chemicals are checked + + const label = document.createElement('label'); + label.htmlFor = `chemical_${chemical}`; + label.appendChild(document.createTextNode(chemical)); + + checkboxContainer.appendChild(checkbox); + checkboxContainer.appendChild(label); + checkboxContainer.appendChild(document.createElement('br')); + }); + + chemicalCheckboxes.appendChild(checkboxContainer); + } + } + } + + function flipChemicalSelections(selection) { + const checkboxes = document.querySelectorAll('#chemicalCheckboxes input[type="checkbox"]'); + checkboxes.forEach(checkbox => { + if (selection) { + checkbox.checked = true; + } else { + checkbox.checked = false; + }; + }); + } + + function applyChemicalFilter() { + const containsText = document.getElementById('containsTextChemical').value.toLowerCase(); + const checkboxes = document.querySelectorAll('#chemicalCheckboxes input[type="checkbox"]'); + checkboxes.forEach(checkbox => { + if (containsText.length > 0) { + if (checkbox.nextSibling.textContent.toLowerCase().includes(containsText)) { + checkbox.checked = true; + } else { + checkbox.checked = false; + } + } + }); + } + + function closeChemicalSelection() { + selectChemicals(); + const chemicalModal = document.getElementById('chemicalModal'); + chemicalModal.style.display = 'none'; + } + + function selectChemicals() { + const checkboxes = document.querySelectorAll('input[name="chemical"]:checked'); + const selectedChemicals = Array.from(checkboxes) + .filter(checkbox => checkbox.checked) + .map(checkbox => checkbox.value); + selectedSampleMeasurements = getSelectedChemicalSampleMeasurements(selectedChemicals); + selectedSampleInfo = getSelectedChemicalSampleInfo(selectedChemicals); + updateChart(); + } + + function getSelectedChemicalSampleMeasurements(selectedChemicals) { + selectedMeas = {}; + for (dateSampled in sampleMeasurements) { + for (const chemicalType in selectedSampleMeasurements[dateSampled]) { + for (const chemical in selectedSampleMeasurements[dateSampled][chemicalType].chemicals) { + if (selectedChemicals.includes(chemical)) { + // Put here as if no chemicals selected then don't need chemical type + if (!selectedMeas[dateSampled]) { + selectedMeas[dateSampled] = {}; + } + if (!selectedMeas[dateSampled][chemicalType]) { + selectedMeas[dateSampled][chemicalType] = {}; + selectedMeas[dateSampled][chemicalType].chemicals = {}; + if (chemicalType == 'PAH data') { + // Just copy all common data even if only 1 PAH is selected + selectedMeas[dateSampled][chemicalType].gorhamTest = selectedSampleMeasurements[dateSampled][chemicalType].gorhamTest; + selectedMeas[dateSampled][chemicalType].total = selectedSampleMeasurements[dateSampled][chemicalType].total; + selectedMeas[dateSampled][chemicalType].totalHC = selectedSampleMeasurements[dateSampled][chemicalType].totalHC; + selectedMeas[dateSampled][chemicalType].totalHCUnit = selectedSampleMeasurements[dateSampled][chemicalType].totalHCUnit; + } + } + selectedMeas[dateSampled][chemicalType].chemicals[chemical] = selectedSampleMeasurements[dateSampled][chemicalType].chemicals[chemical]; + } + } + } + } + return selectedMeas; + } + + function getSelectedChemicalSampleInfo(selectedChemicals) { + selectedSamps = {}; + for (const dateSampled in selectedSampleMeasurements) { + for (const chemicalType in selectedSampleMeasurements[dateSampled]) { + selectedSamps[dateSampled] = {}; + selectedSamps[dateSampled]['Date sampled'] = selectedSampleInfo[dateSampled]['Date sampled']; + selectedSamps[dateSampled].fileURL = selectedSampleInfo[dateSampled].fileURL; + selectedSamps[dateSampled].Applicant = selectedSampleInfo[dateSampled].Applicant; + selectedSamps[dateSampled]['Application number'] = selectedSampleInfo[dateSampled]['Application number']; + selectedSamps[dateSampled]['Application title'] = selectedSampleInfo[dateSampled]['Application title']; + selectedSamps[dateSampled].position = {}; + for (const chemical in selectedSampleMeasurements[dateSampled][chemicalType].chemicals) { + for (const sample in selectedSampleMeasurements[dateSampled][chemicalType].chemicals[chemical].samples){ + selectedSamps[dateSampled].position[sample] = selectedSampleInfo[dateSampled].position[sample]; + } + } + } + } + return selectedSamps; + } + + function openSampleSelection(sampleMeasurements) { + const sampleModal = document.getElementById('sampleModal'); + sampleModal.style.display = 'block'; + + const sampleCheckboxes = document.getElementById('sampleCheckboxes'); + sampleCheckboxes.innerHTML = ''; + + const datesSampled = Object.keys(sampleInfo); + + + datesSampled.sort(); + datesSampled.forEach (dateSampled => { + + // for (dateSampled in sampleInfo) { + const samples = Object.keys(sampleInfo[dateSampled].position); + const checkboxContainer = document.createElement('div'); + checkboxContainer.className = 'checkbox-container'; + + samples.forEach(sample => { + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.id = `sample_${dateSampled + ': ' + sample}`; + checkbox.name = 'sample'; + checkbox.value = dateSampled + ': ' + sample; + checkbox.checked = true; // Initially all samples are checked + + const label = document.createElement('label'); + label.htmlFor = `sample_${sample}`; + label.appendChild(document.createTextNode(dateSampled + ': ' + sample)); + + checkboxContainer.appendChild(checkbox); + checkboxContainer.appendChild(label); + checkboxContainer.appendChild(document.createElement('br')); + }); + + sampleCheckboxes.appendChild(checkboxContainer); + }); + } + + function flipSampleSelections(selection) { + const checkboxes = document.querySelectorAll('#sampleCheckboxes input[type="checkbox"]'); + checkboxes.forEach(checkbox => { + if (selection) { + checkbox.checked = true; + } else { + checkbox.checked = false; + }; + }); + } + + function applySampleFilter() { + const containsText = document.getElementById('containsText').value.toLowerCase(); + const minDepth = parseFloat(document.getElementById('minDepth').value); + const maxDepth = parseFloat(document.getElementById('maxDepth').value); + centreLat = parseFloat(document.getElementById('centreLat').value); + centreLon = parseFloat(document.getElementById('centreLon').value); + const centreDist = parseFloat(document.getElementById('centreDist').value); + const checkboxes = document.querySelectorAll('#sampleCheckboxes input[type="checkbox"]'); + const checkboxesIn = document.querySelectorAll('input[name="sample"]:checked'); + checkboxes.forEach(checkbox => { + if (containsText.length > 0) { + if (checkbox.nextSibling.textContent.toLowerCase().includes(containsText)) { + checkbox.checked = true; + } else { + checkbox.checked = false; + } + } + }); + if (!(isNaN(minDepth) || isNaN(maxDepth)) && (minDepth <= maxDepth)) { + checkboxes.forEach(checkbox => { + checkbox.checked = false; + }); + for (const dateSelected in sampleInfo) { + for (const sample in sampleInfo[dateSelected].position) { + const minSample = sampleInfo[dateSelected].position[sample]['Sampling depth (m)'].minDepth; + if (minDepth <= minSample) { + const maxSample = sampleInfo[dateSelected].position[sample]['Sampling depth (m)'].maxDepth; + if (maxDepth >= maxSample) { + const checkName = `sample_${dateSelected + ': ' + sample}`; + const checkbox = document.getElementById(checkName); + checkbox.checked = true; + } + } + } + } + } + // going to find samples close to a set of coordinates + if (!isNaN(centreDist)) { + // latitude and longitude not supplied + if ((isNaN(centreLat) || isNaN(centreLon))) { + // so assuming only one checkbox is ticked then find all samples near to that position + const selectedSamples = Array.from(checkboxesIn) + .filter(checkbox => checkbox.checked) + .map(checkbox => checkbox.value); + if (selectedSamples.length === 1) { + for (const dateSampled in sampleInfo) { + for (const sample in sampleInfo[dateSampled].position) { + if (selectedSamples.includes(dateSampled + ': ' + sample)) { + centreLat = sampleInfo[dateSampled].position[sample]['Position latitude']; + centreLon = sampleInfo[dateSampled].position[sample]['Position longitude']; + } + } + } + } else { + return + } + } + checkboxes.forEach(checkbox => { + checkbox.checked = false; + }); + for (const dateSelected in sampleInfo) { + for (const sample in sampleInfo[dateSelected].position) { + const sampleLat = sampleInfo[dateSelected].position[sample]['Position latitude']; + const sampleLon = sampleInfo[dateSelected].position[sample]['Position longitude']; + distance = 1000 * haversineDistance(sampleLat, sampleLon, centreLat, centreLon); + if (distance <= centreDist) { + const checkName = `sample_${dateSelected + ': ' + sample}`; + const checkbox = document.getElementById(checkName); + checkbox.checked = true; + } + } + } + } + } + + function haversineDistance(lat1, lon1, lat2, lon2) { + const R = 6371; // Radius of the Earth in kilometers + const dLat = toRadians(lat2 - lat1); + const dLon = toRadians(lon2 - lon1); + const a = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + const distance = R * c; // Distance in kilometers + return distance; + } + + function toRadians(degrees) { + return degrees * (Math.PI / 180); + } + + + function closeSampleSelection() { + selectSamples(); + const sampleModal = document.getElementById('sampleModal'); + sampleModal.style.display = 'none'; + } + + function selectSamples() { + const checkboxes = document.querySelectorAll('input[name="sample"]:checked'); + //console.log(checkboxes); + const selectedSamples = Array.from(checkboxes) + .filter(checkbox => checkbox.checked) + .map(checkbox => checkbox.value); + //console.log(selectedSamples); + selectedSampleMeasurements = getselectedSampleMeasurements(selectedSamples); + selectedSampleInfo = getSelectedSamples(selectedSamples); + updateChart(); + } + + + function getselectedSampleMeasurements(selectedSamples) { + selectedMeas = {}; + //console.log(selectedSamples); + for (dateSampled in sampleMeasurements) { + //console.log(dateSampled); + const chemicalTypes = Object.keys(sampleMeasurements[dateSampled]); + const chemicals = Object.keys(sampleMeasurements[dateSampled][chemicalTypes[0]].chemicals); + for (const chemicalType in sampleMeasurements[dateSampled]) { + if (chemicalType === 'Physical Data') { + for (const sample in sampleMeasurements[dateSampled][chemicalType].samples) { + if (selectedSamples.includes(dateSampled + ': ' + sample)) { + if (!selectedMeas[dateSampled]) { + selectedMeas[dateSampled] = {}; + selectedMeas[dateSampled][chemicalType] = {}; + selectedMeas[dateSampled][chemicalType].samples = {}; + selectedMeas[dateSampled][chemicalType]['Unit of measurement'] = sampleMeasurements[dateSampled][chemicalType]['Unit of measurement']; + selectedMeas[dateSampled][chemicalType].sizes = sampleMeasurements[dateSampled][chemicalType].sizes; + //console.log('1 psd selectedMeas ',dateSampled,chemicalType,selectedMeas); + } else { + if (!selectedMeas[dateSampled][chemicalType]) { + selectedMeas[dateSampled][chemicalType] = {}; + selectedMeas[dateSampled][chemicalType].samples = {}; + selectedMeas[dateSampled][chemicalType]['Unit of measurement'] = sampleMeasurements[dateSampled][chemicalType]['Unit of measurement']; + selectedMeas[dateSampled][chemicalType].sizes = sampleMeasurements[dateSampled][chemicalType].sizes; + //console.log('2 psd selectedMeas ',dateSampled,chemicalType,selectedMeas); + } + //console.log('3 psd selectedMeas ',dateSampled,chemicalType,sample,selectedMeas); + selectedMeas[dateSampled][chemicalType].samples[sample] = {}; + selectedMeas[dateSampled][chemicalType].samples[sample].psd = sampleMeasurements[dateSampled][chemicalType].samples[sample].psd; + } + } + } + + //console.log('Create ', dateSampled, chemicalType); + //console.log('should do Gorham Test here'); + + } else { + for (const chemical in sampleMeasurements[dateSampled][chemicalType].chemicals) { + for (const sample in sampleMeasurements[dateSampled][chemicalType].chemicals[chemical].samples) { + //console.log(sample); + if (selectedSamples.includes(dateSampled + ': ' + sample)) { + //console.log('Found one'); + if (!selectedMeas[dateSampled]) { + //console.log('Create ', dateSampled); + selectedMeas[dateSampled] = {}; + // for (const chemicalType in sampleMeasurements[dateSampled]) { + selectedMeas[dateSampled][chemicalType] = {}; + selectedMeas[dateSampled][chemicalType]['Unit of measurement'] = sampleMeasurements[dateSampled][chemicalType]['Unit of measurement']; + selectedMeas[dateSampled][chemicalType].chemicals = {}; + //console.log('Create ', dateSampled, chemicalType); + //console.log('should do Gorham Test here'); + if (chemicalType == 'PAH data') { + //console.log('Create ', dateSampled, chemicalType,'Gorham Test'); + selectedMeas[dateSampled][chemicalType].gorhamTest = {}; + selectedMeas[dateSampled][chemicalType].gorhamTest[sample] = sampleMeasurements[dateSampled][chemicalType].gorhamTest[sample]; + selectedMeas[dateSampled][chemicalType].total = {}; + selectedMeas[dateSampled][chemicalType].total[sample] = selectedSampleMeasurements[dateSampled][chemicalType].total[sample]; + selectedMeas[dateSampled][chemicalType].totalHC = {}; + selectedMeas[dateSampled][chemicalType].totalHCUnit = selectedSampleMeasurements[dateSampled][chemicalType].totalHCUnit; + selectedMeas[dateSampled][chemicalType].totalHC[sample] = selectedSampleMeasurements[dateSampled][chemicalType].totalHC[sample]; + } + if (chemicalType == 'PCB data') { + //console.log('Create ', dateSampled, chemicalType,'Gorham Test'); + selectedMeas[dateSampled][chemicalType].congenerTest = {}; + selectedMeas[dateSampled][chemicalType].congenerTest[sample] = sampleMeasurements[dateSampled][chemicalType].congenerTest[sample]; + } + for (const chemical in sampleMeasurements[dateSampled][chemicalType].chemicals) { + //console.log('Create ', dateSampled, chemicalType,chemical); + selectedMeas[dateSampled][chemicalType].chemicals[chemical] = {}; + selectedMeas[dateSampled][chemicalType].chemicals[chemical].samples = {}; + selectedMeas[dateSampled][chemicalType].chemicals[chemical].samples[sample] = sampleMeasurements[dateSampled][chemicalType].chemicals[chemical].samples[sample]; + } + // } + } else { + // for (const chemicalType in sampleMeasurements[dateSampled]) { + //console.log('ch ', dateSampled,sample,chemicalType); + if (!selectedMeas[dateSampled][chemicalType]) { + selectedMeas[dateSampled][chemicalType] = {}; + selectedMeas[dateSampled][chemicalType]['Unit of measurement'] = sampleMeasurements[dateSampled][chemicalType]['Unit of measurement']; + selectedMeas[dateSampled][chemicalType].chemicals = {}; + if (chemicalType === 'PAH data') { + //console.log('Create ', dateSampled, chemicalType,'Gorham Test'); + selectedMeas[dateSampled][chemicalType].gorhamTest = {}; + selectedMeas[dateSampled][chemicalType].gorhamTest[sample] = sampleMeasurements[dateSampled][chemicalType].gorhamTest[sample]; + } + if (chemicalType == 'PCB data') { + //console.log('Create ', dateSampled, chemicalType,'Gorham Test'); + selectedMeas[dateSampled][chemicalType].congenerTest = {}; + selectedMeas[dateSampled][chemicalType].congenerTest[sample] = sampleMeasurements[dateSampled][chemicalType].congenerTest[sample]; + } + for (const chemical in sampleMeasurements[dateSampled][chemicalType].chemicals) { + //console.log('Create ', dateSampled, chemicalType,chemical); + selectedMeas[dateSampled][chemicalType].chemicals[chemical] = {}; + selectedMeas[dateSampled][chemicalType].chemicals[chemical].samples = {}; + selectedMeas[dateSampled][chemicalType].chemicals[chemical].samples[sample] = sampleMeasurements[dateSampled][chemicalType].chemicals[chemical].samples[sample]; + } + } else { + if (chemicalType === 'PAH data') { + //console.log('Create ', dateSampled, chemicalType,'Gorham Test'); + selectedMeas[dateSampled][chemicalType].gorhamTest[sample] = sampleMeasurements[dateSampled][chemicalType].gorhamTest[sample]; + selectedMeas[dateSampled][chemicalType].total[sample] = selectedSampleMeasurements[dateSampled][chemicalType].total[sample]; + selectedMeas[dateSampled][chemicalType].totalHC[sample] = selectedSampleMeasurements[dateSampled][chemicalType].totalHC[sample]; + } + if (chemicalType == 'PCB data') { + //console.log('Create ', dateSampled, chemicalType,'Gorham Test'); + selectedMeas[dateSampled][chemicalType].congenerTest[sample] = sampleMeasurements[dateSampled][chemicalType].congenerTest[sample]; + } + for (const chemical in sampleMeasurements[dateSampled][chemicalType].chemicals) { + selectedMeas[dateSampled][chemicalType].chemicals[chemical].samples[sample] = sampleMeasurements[dateSampled][chemicalType].chemicals[chemical].samples[sample]; + } + } + } + } + } + } + } + } + } + // console.log(selectedMeas); // Output each cell value to console + return selectedMeas; + } + + function getSelectedSamples(selectedSamples) { + selectedSamps = {}; + for (const dateSampled in sampleInfo) { + for (const sample in sampleInfo[dateSampled].position) { + if (selectedSamples.includes(dateSampled + ': ' + sample)) { + // console.log('a point ' + dateSampled + ': ' + sample); + if (!selectedSamps[dateSampled]) { + selectedSamps[dateSampled] = {}; + selectedSamps[dateSampled]['Date sampled'] = sampleInfo[dateSampled]['Date sampled']; + selectedSamps[dateSampled].fileURL = sampleInfo[dateSampled].fileURL; + selectedSamps[dateSampled].Applicant = sampleInfo[dateSampled].Applicant; + selectedSamps[dateSampled]['Application number'] = sampleInfo[dateSampled]['Application number']; + selectedSamps[dateSampled]['Application title'] = sampleInfo[dateSampled]['Application title']; + } + if (!selectedSamps[dateSampled].position) { + selectedSamps[dateSampled].position = {}; + } + selectedSamps[dateSampled].position[sample] = sampleInfo[dateSampled].position[sample]; + } + } + } + // console.log(selectedSamps); // Output each cell value to console + return selectedSamps; + } + + function clearSelections() { + selectedSampleMeasurements = sampleMeasurements; + selectedSampleInfo = sampleInfo; + } +