Created
March 11, 2019 23:15
-
-
Save lelandbatey/2599ac2314da478afc2a0885e200be95 to your computer and use it in GitHub Desktop.
A demonstration of the importance of correct RGB color interpolation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script> | |
| <body style="margin: 0;"> | |
| <div> | |
| <canvas id='canvas1' width='800' height='200'></canvas> | |
| </div> | |
| <div> | |
| <canvas id='canvas2' width='800' height='200'></canvas> | |
| </div> | |
| <div> | |
| <canvas id='canvas3' width='800' height='200'></canvas> | |
| </div> | |
| </body> | |
| <script> | |
| // To run, download this file and serve it via some http server; I prefer | |
| // `python -m SimpleHTTPServer` in this directory. Then you'd access | |
| // `http://localhost:8000/` in your web browser. | |
| /// Assumes an input string of "#ABCDEF" | |
| function hex_to_rgb(hex) { | |
| return [Number.parseInt(hex.slice(1, 3), 16), Number.parseInt(hex.slice(3, 5), 16), Number.parseInt(hex.slice(5, 7), 16)]; | |
| } | |
| /// [255, 255, 255] -> "#FFFFFF" | |
| function rgb_to_hex(rgb) { | |
| var hex = "#"; | |
| for (var i = 0; i < rgb.length; i++) { | |
| hex = hex + rgb[i].toString(16).padStart(2, '0'); | |
| } | |
| return hex; | |
| } | |
| function _blend_colors(c1, c2, t, blendChannel) { | |
| if (typeof c1 === 'string') { | |
| c1 = hex_to_rgb(c1); | |
| c2 = hex_to_rgb(c2); | |
| } | |
| let nc = [0, 0, 0]; | |
| for (var i = 0; i<3; i++) { | |
| nc[i] = blendChannel(c1[i], c2[i], t); | |
| } | |
| return nc; | |
| } | |
| function blend_multi_colors(colors, t, blendChannel) { | |
| let n = 1/(colors.length-1); | |
| let tween_color_span = t/n % 1; | |
| let c_strt_idx = Math.floor(t/n); | |
| let c1 = colors[c_strt_idx]; | |
| let c2 = colors[c_strt_idx+1]; | |
| return _blend_colors(c1, c2, tween_color_span, blendChannel); | |
| } | |
| function blend_colors(colors, t) { | |
| let blendChannel = (a, b, x) => { | |
| return Math.sqrt((1-x) * Math.pow(a, 2) + x * Math.pow(b, 2)); | |
| } | |
| return blend_multi_colors(colors, t, blendChannel); | |
| } | |
| function bad_blend(colors, t) { | |
| let bc = (a, b, x) => { | |
| return a + x * (b - a); | |
| } | |
| return blend_multi_colors(colors, t, bc); | |
| } | |
| function draw_gradient(canv, colorFunc, colors) { | |
| var context = canv.getContext('2d'); | |
| context.fillStyle = 'grey'; | |
| context.fillRect(0, 0, canv.width, canv.height); | |
| for (var x = 0; x < canv.width; x++) { | |
| let colColor = colorFunc(colors, x/canv.width); | |
| for (var y = 0; y < canv.height; y++) { | |
| context.fillStyle = `rgba(${colColor[0]}, ${colColor[1]}, ${colColor[2]}, 1)`; | |
| context.fillRect(x, y, 1, 1); | |
| } | |
| } | |
| } | |
| $(document).ready(() => { | |
| var canv = document.getElementById('canvas1'); | |
| //let colors = ["#FF0000", "#00FF00", "#0000FF"]; | |
| // let colors = ["#49C209", "#312077", "#CD252B"]; | |
| let colors = ["#49C209", "#312077"]; | |
| draw_gradient(document.getElementById('canvas1'), blend_colors, colors); | |
| draw_gradient(document.getElementById('canvas2'), bad_blend, colors); | |
| }); | |
| </script> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment