From 260ff761eb796fe21b4da55557a39690e78b84b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Szumi=C5=84ski?= Date: Wed, 21 Dec 2022 09:23:05 +0100 Subject: [PATCH 1/7] Created color converter & form. --- .../highcharts/15-heatmap-hsv/index.html | 21 ++++++ .../highcharts/15-heatmap-hsv/main.js | 66 +++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/highcharts-api/highcharts/15-heatmap-hsv/index.html b/highcharts-api/highcharts/15-heatmap-hsv/index.html index 6c800fd..4589993 100644 --- a/highcharts-api/highcharts/15-heatmap-hsv/index.html +++ b/highcharts-api/highcharts/15-heatmap-hsv/index.html @@ -7,11 +7,32 @@ +
+ +
+ + + + 50 + +
+ + +
+ +
+ + +
+ +
\ No newline at end of file diff --git a/highcharts-api/highcharts/15-heatmap-hsv/main.js b/highcharts-api/highcharts/15-heatmap-hsv/main.js index e69de29..27387fe 100644 --- a/highcharts-api/highcharts/15-heatmap-hsv/main.js +++ b/highcharts-api/highcharts/15-heatmap-hsv/main.js @@ -0,0 +1,66 @@ +function hsvToRgb(hue, saturation, value) { + const M = 255 * value, + m = M * (1 - saturation), + z = (M - m) * (1 - Math.abs((hue / 60) % 2 - 1)); + + let R, G, B; + + if(hue < 60) { R = M; G = z + m; B = m; } + else if (hue < 120) { R = z + m; G = M; B = m; } + else if (hue < 180) { R = m; G = M; B = z + m; } + else if (hue < 240) { R = m; G = z + m; B = M; } + else if (hue < 300) { R = z + m; G = m; B = M; } + else if (hue < 360) { R = M; G = m; B = z + m; } + + R = Math.round(R); + G = Math.round(G); + B = Math.round(B); + + return `rgba(${R}, ${G}, ${B})`; +} + +let arr = []; + +for(let x = 0; x < 360; x += 10) { + for(let y = 0; y < 1; y += 0.025) { + arr.push([x, y, hsvToRgb(x, y, 1)]); + } +} + +console.log(arr); + + +Highcharts.chart('container', { + chart: { + type: 'heatmap' + }, + + title: { + text: 'Heatmap of colors in HSV' + }, + + //step y: 0.05 + //step x: 36 (to 360) + + series: [{ + name: 'Colors', + data: arr + }] +}); + +const form = document.getElementById('form'), + slider = document.getElementById('slider'); + +form.addEventListener('change', () => { + console.log('form changed'); + + const choice = document.querySelector('input[name="property_choice"]:checked')?.value; + if(!choice) return; + + console.log(choice); +}) + +//Data generation +//x from 0 to 360 (step by 10 degrees) +//y from 0 to 1 (step by 0.025) + From 8f2be6a249cd8fb156b06d1ee26ac3f833d092de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Szumi=C5=84ski?= Date: Wed, 21 Dec 2022 11:13:47 +0100 Subject: [PATCH 2/7] a --- .../highcharts/15-heatmap-hsv/main.js | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/highcharts-api/highcharts/15-heatmap-hsv/main.js b/highcharts-api/highcharts/15-heatmap-hsv/main.js index 27387fe..b240383 100644 --- a/highcharts-api/highcharts/15-heatmap-hsv/main.js +++ b/highcharts-api/highcharts/15-heatmap-hsv/main.js @@ -19,15 +19,37 @@ function hsvToRgb(hue, saturation, value) { return `rgba(${R}, ${G}, ${B})`; } +function hslToHex(h, s, l) { + const a = s * Math.min(l, 1 - l); + const f = n => { + const k = (n + h / 30) % 12; + const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); + return Math.round(255 * color).toString(16).padStart(2, '0'); // convert to Hex and prefix "0" if needed + }; + + const result = `#${f(0)}${f(8)}${f(4)}`; + console.log('Conversion result: ', result); + + return `#${f(0)}${f(8)}${f(4)}`; +} + let arr = []; +/* for(let x = 0; x < 360; x += 10) { for(let y = 0; y < 1; y += 0.025) { - arr.push([x, y, hsvToRgb(x, y, 1)]); + arr.push([x, y, x * y]); + //arr.push([x, y, hsvToRgb(x, y, 1)]); + } +}*/ + +for(let x = 0; x < 360; x += 1) { + for(let y = 0; y < 1; y += 0.1) { + arr.push([x, y, x * y]); } } -console.log(arr); +//console.log(arr); Highcharts.chart('container', { @@ -39,6 +61,30 @@ Highcharts.chart('container', { text: 'Heatmap of colors in HSV' }, + plotOptions: { + series: { + turboThreshold: 10000 + } + }, + + colorAxis: { + min: 0, + max: 10, + + }, + + yAxis: { + min: 0, + max: 1, + tickInterval: 0.1, + }, + + xAxis: { + min: 0, + max: 360, + tickInterval: 60, + }, + //step y: 0.05 //step x: 36 (to 360) From b5b5439773d2a4edecd8407370bd820768e4a8d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Szumi=C5=84ski?= Date: Wed, 21 Dec 2022 15:02:33 +0100 Subject: [PATCH 3/7] Created first version of the chart. --- .../highcharts/15-heatmap-hsv/index.html | 1 + .../highcharts/15-heatmap-hsv/main.js | 120 ++++++++---------- 2 files changed, 54 insertions(+), 67 deletions(-) diff --git a/highcharts-api/highcharts/15-heatmap-hsv/index.html b/highcharts-api/highcharts/15-heatmap-hsv/index.html index 4589993..4c7dca6 100644 --- a/highcharts-api/highcharts/15-heatmap-hsv/index.html +++ b/highcharts-api/highcharts/15-heatmap-hsv/index.html @@ -8,6 +8,7 @@ + diff --git a/highcharts-api/highcharts/15-heatmap-hsv/main.js b/highcharts-api/highcharts/15-heatmap-hsv/main.js index b240383..d307923 100644 --- a/highcharts-api/highcharts/15-heatmap-hsv/main.js +++ b/highcharts-api/highcharts/15-heatmap-hsv/main.js @@ -1,96 +1,82 @@ -function hsvToRgb(hue, saturation, value) { - const M = 255 * value, - m = M * (1 - saturation), - z = (M - m) * (1 - Math.abs((hue / 60) % 2 - 1)); - - let R, G, B; - - if(hue < 60) { R = M; G = z + m; B = m; } - else if (hue < 120) { R = z + m; G = M; B = m; } - else if (hue < 180) { R = m; G = M; B = z + m; } - else if (hue < 240) { R = m; G = z + m; B = M; } - else if (hue < 300) { R = z + m; G = m; B = M; } - else if (hue < 360) { R = M; G = m; B = z + m; } - - R = Math.round(R); - G = Math.round(G); - B = Math.round(B); - - return `rgba(${R}, ${G}, ${B})`; -} - function hslToHex(h, s, l) { const a = s * Math.min(l, 1 - l); + const f = n => { - const k = (n + h / 30) % 12; - const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); + const k = (n + h / 30) % 12, + color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); return Math.round(255 * color).toString(16).padStart(2, '0'); // convert to Hex and prefix "0" if needed }; - const result = `#${f(0)}${f(8)}${f(4)}`; - console.log('Conversion result: ', result); - return `#${f(0)}${f(8)}${f(4)}`; } -let arr = []; +function createHeatmapData(parameter, value) { + const arr = []; + const val = value ? (value / 100) : 0.5; -/* -for(let x = 0; x < 360; x += 10) { - for(let y = 0; y < 1; y += 0.025) { - arr.push([x, y, x * y]); - //arr.push([x, y, hsvToRgb(x, y, 1)]); + for(let x = 0; x <= 360; x += 10) { + for(let y = 0; y <= 1; y += 0.025) { + arr.push({ + x, y, + color: parameter === 'Saturation' ? hslToHex(x, val, 0.5) : hslToHex(x, y, val) + }); + } } -}*/ -for(let x = 0; x < 360; x += 1) { - for(let y = 0; y < 1; y += 0.1) { - arr.push([x, y, x * y]); - } + return arr; } -//console.log(arr); - - -Highcharts.chart('container', { +const chart = Highcharts.chart('container', { chart: { - type: 'heatmap' + type: 'heatmap', + events: { + load() { + this.update({ + chart: { + height: this.plotWidth + } + }); + }, + } + }, + + boost: { + useGPUTranslations: true, }, title: { text: 'Heatmap of colors in HSV' }, - plotOptions: { - series: { - turboThreshold: 10000 + yAxis: { + tickInterval: 0.05, + title: { + text: 'S' } }, - colorAxis: { - min: 0, - max: 10, - - }, - - yAxis: { - min: 0, - max: 1, - tickInterval: 0.1, - }, - xAxis: { min: 0, max: 360, - tickInterval: 60, + tickInterval: 36, + endOnTick: true, + title: { + text: 'H' + } + }, + + plotOptions: { + heatmap: { + colsize: 10, + rowsize: 0.025, + turboThreshold: 160000 + } }, - //step y: 0.05 - //step x: 36 (to 360) - series: [{ + boostTreshold: 1500, name: 'Colors', - data: arr + data: createHeatmapData() }] }); @@ -103,10 +89,10 @@ form.addEventListener('change', () => { const choice = document.querySelector('input[name="property_choice"]:checked')?.value; if(!choice) return; - console.log(choice); -}) + console.log(`${choice} : ${slider.value}`); -//Data generation -//x from 0 to 360 (step by 10 degrees) -//y from 0 to 1 (step by 0.025) + chart.series[0].update({ + data: createHeatmapData(choice, slider.value) + }); +}) From 507016d0f3e40a2f06b43f5654a321d5b8eaf239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Szumi=C5=84ski?= Date: Thu, 22 Dec 2022 15:44:33 +0100 Subject: [PATCH 4/7] Created first version of the solution. --- .../highcharts/15-heatmap-hsv/main.js | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/highcharts-api/highcharts/15-heatmap-hsv/main.js b/highcharts-api/highcharts/15-heatmap-hsv/main.js index d307923..e7a5aa6 100644 --- a/highcharts-api/highcharts/15-heatmap-hsv/main.js +++ b/highcharts-api/highcharts/15-heatmap-hsv/main.js @@ -10,16 +10,35 @@ function hslToHex(h, s, l) { return `#${f(0)}${f(8)}${f(4)}`; } -function createHeatmapData(parameter, value) { +function createHeatmapData(choice) { const arr = []; - const val = value ? (value / 100) : 0.5; - - for(let x = 0; x <= 360; x += 10) { - for(let y = 0; y <= 1; y += 0.025) { - arr.push({ - x, y, - color: parameter === 'Saturation' ? hslToHex(x, val, 0.5) : hslToHex(x, y, val) - }); + + if(choice === 'Saturation') { + for(let x = 0; x <= 360; x += 10) { + for(let y = 0; y <= 1; y += 0.025) { + arr.push({ + x, y, + color: hslToHex(x, saturation, y) + }); + } + } + } else if (choice === 'Value') { + for(let x = 0; x <= 360; x += 10) { + for(let y = 0; y <= 1; y += 0.025) { + arr.push({ + x, y, + color: hslToHex(x, y, value) + }); + } + } + } else { + for(let x = 0; x <= 360; x += 10) { + for(let y = 0; y <= 1; y += 0.025) { + arr.push({ + x, y, + color: hslToHex(x, y, 0.5) + }); + } } } @@ -84,15 +103,23 @@ const form = document.getElementById('form'), slider = document.getElementById('slider'); form.addEventListener('change', () => { - console.log('form changed'); - const choice = document.querySelector('input[name="property_choice"]:checked')?.value; if(!choice) return; - console.log(`${choice} : ${slider.value}`); + if(choice === 'Saturation') { + saturation = slider.value / 100; + } else if (choice === 'Value') { + value = slider.value / 100; + } + + chart.yAxis[0].update({ + title: { + text: choice === 'Value' ? 'S' : 'V' + } + }); chart.series[0].update({ - data: createHeatmapData(choice, slider.value) + data: createHeatmapData(choice) }); }) From 793640c9aa7987af360a69fd71dbd35eb9587cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Szumi=C5=84ski?= Date: Fri, 23 Dec 2022 08:26:33 +0100 Subject: [PATCH 5/7] Refactored code & prepared it for code review. --- .../highcharts/15-heatmap-hsv/index.html | 5 +- .../highcharts/15-heatmap-hsv/main.js | 70 +++++-------------- 2 files changed, 18 insertions(+), 57 deletions(-) diff --git a/highcharts-api/highcharts/15-heatmap-hsv/index.html b/highcharts-api/highcharts/15-heatmap-hsv/index.html index 4c7dca6..8d70ab1 100644 --- a/highcharts-api/highcharts/15-heatmap-hsv/index.html +++ b/highcharts-api/highcharts/15-heatmap-hsv/index.html @@ -8,7 +8,6 @@ - @@ -24,12 +23,12 @@ 50
- +
- +
diff --git a/highcharts-api/highcharts/15-heatmap-hsv/main.js b/highcharts-api/highcharts/15-heatmap-hsv/main.js index e7a5aa6..60aec20 100644 --- a/highcharts-api/highcharts/15-heatmap-hsv/main.js +++ b/highcharts-api/highcharts/15-heatmap-hsv/main.js @@ -1,44 +1,25 @@ function hslToHex(h, s, l) { const a = s * Math.min(l, 1 - l); - const f = n => { const k = (n + h / 30) % 12, color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); return Math.round(255 * color).toString(16).padStart(2, '0'); // convert to Hex and prefix "0" if needed }; - return `#${f(0)}${f(8)}${f(4)}`; } -function createHeatmapData(choice) { +function createHeatmapData(choice = 'none', sliderValue) { const arr = []; - if(choice === 'Saturation') { - for(let x = 0; x <= 360; x += 10) { - for(let y = 0; y <= 1; y += 0.025) { - arr.push({ - x, y, - color: hslToHex(x, saturation, y) - }); - } - } - } else if (choice === 'Value') { - for(let x = 0; x <= 360; x += 10) { - for(let y = 0; y <= 1; y += 0.025) { - arr.push({ - x, y, - color: hslToHex(x, y, value) - }); - } - } - } else { - for(let x = 0; x <= 360; x += 10) { - for(let y = 0; y <= 1; y += 0.025) { - arr.push({ - x, y, - color: hslToHex(x, y, 0.5) - }); - } + const createColor = { + 'none': (x, y) => hslToHex(x, y, 0.5), + 'saturation': (x, y) => hslToHex(x, sliderValue, y), + 'value': (x, y) => hslToHex(x, y, sliderValue) + } + + for(let x = 0; x <= 360; x += 15) { + for(let y = 0; y <= 1; y += 0.0375) { + arr.push({ x, y, color: createColor[choice](x, y) }) } } @@ -48,19 +29,7 @@ function createHeatmapData(choice) { const chart = Highcharts.chart('container', { chart: { type: 'heatmap', - events: { - load() { - this.update({ - chart: { - height: this.plotWidth - } - }); - }, - } - }, - - boost: { - useGPUTranslations: true, + height: 400, }, title: { @@ -86,14 +55,13 @@ const chart = Highcharts.chart('container', { plotOptions: { heatmap: { - colsize: 10, - rowsize: 0.025, + colsize: 15, + rowsize: 0.0375, turboThreshold: 160000 } }, series: [{ - boostTreshold: 1500, name: 'Colors', data: createHeatmapData() }] @@ -106,20 +74,14 @@ form.addEventListener('change', () => { const choice = document.querySelector('input[name="property_choice"]:checked')?.value; if(!choice) return; - if(choice === 'Saturation') { - saturation = slider.value / 100; - } else if (choice === 'Value') { - value = slider.value / 100; - } - chart.yAxis[0].update({ title: { - text: choice === 'Value' ? 'S' : 'V' + text: choice === 'value' ? 'S' : 'V' } }); chart.series[0].update({ - data: createHeatmapData(choice) + data: createHeatmapData(choice, slider.value / 100) }); -}) +}); From 6cdedf32481267bab769e81bfa973f83f2578388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Szumi=C5=84ski?= Date: Fri, 23 Dec 2022 09:54:41 +0100 Subject: [PATCH 6/7] Resolved issues after first code review. --- highcharts-api/highcharts/15-heatmap-hsv/main.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/highcharts-api/highcharts/15-heatmap-hsv/main.js b/highcharts-api/highcharts/15-heatmap-hsv/main.js index 60aec20..7fd23b1 100644 --- a/highcharts-api/highcharts/15-heatmap-hsv/main.js +++ b/highcharts-api/highcharts/15-heatmap-hsv/main.js @@ -8,11 +8,10 @@ function hslToHex(h, s, l) { return `#${f(0)}${f(8)}${f(4)}`; } -function createHeatmapData(choice = 'none', sliderValue) { +function createHeatmapData(choice = 'value', sliderValue = 0.5) { const arr = []; const createColor = { - 'none': (x, y) => hslToHex(x, y, 0.5), 'saturation': (x, y) => hslToHex(x, sliderValue, y), 'value': (x, y) => hslToHex(x, y, sliderValue) } @@ -78,7 +77,7 @@ form.addEventListener('change', () => { title: { text: choice === 'value' ? 'S' : 'V' } - }); + }, false); chart.series[0].update({ data: createHeatmapData(choice, slider.value / 100) From 044ce8ad35bdaae3c3bbd9fab3d4340bd6bf905c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Szumi=C5=84ski?= Date: Fri, 23 Dec 2022 12:55:42 +0100 Subject: [PATCH 7/7] Added notes about external function that converts colors. --- .../highcharts/15-heatmap-hsv/main.js | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/highcharts-api/highcharts/15-heatmap-hsv/main.js b/highcharts-api/highcharts/15-heatmap-hsv/main.js index 7fd23b1..8276379 100644 --- a/highcharts-api/highcharts/15-heatmap-hsv/main.js +++ b/highcharts-api/highcharts/15-heatmap-hsv/main.js @@ -1,9 +1,24 @@ -function hslToHex(h, s, l) { - const a = s * Math.min(l, 1 - l); +/* +This function takes three parameters (of an HSL color): +- hue (0 to 360 degrees), +- saturation (0 to 1), +- value (0 to 1) +and returns a corresponding HEX color. + +The function was taken from this source: +https://stackoverflow.com/questions/36721830/convert-hsl-to-rgb-and-hex + +The calculations are based on this repo: +https://gist.github.com/mjackson/5311256 +*/ + +function convertHSLtoHEX(hue, saturation, value) { + const a = saturation * Math.min(value, 1 - value); const f = n => { - const k = (n + h / 30) % 12, - color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); - return Math.round(255 * color).toString(16).padStart(2, '0'); // convert to Hex and prefix "0" if needed + const k = (n + hue / 30) % 12, + color = value - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); + //convert to HEX and prefix "0" if needed + return Math.round(255 * color).toString(16).padStart(2, '0'); }; return `#${f(0)}${f(8)}${f(4)}`; } @@ -12,8 +27,8 @@ function createHeatmapData(choice = 'value', sliderValue = 0.5) { const arr = []; const createColor = { - 'saturation': (x, y) => hslToHex(x, sliderValue, y), - 'value': (x, y) => hslToHex(x, y, sliderValue) + 'saturation': (x, y) => convertHSLtoHEX(x, sliderValue, y), + 'value': (x, y) => convertHSLtoHEX(x, y, sliderValue) } for(let x = 0; x <= 360; x += 15) {