diff --git a/src/js/operations/BitwiseOp.js b/src/js/operations/BitwiseOp.js index 4cdf6b34..82894e0a 100755 --- a/src/js/operations/BitwiseOp.js +++ b/src/js/operations/BitwiseOp.js @@ -1,7 +1,6 @@ import Utils from '../core/Utils'; - /** * Bitwise operations. * diff --git a/src/js/operations/ByteRepr.js b/src/js/operations/ByteRepr.js index e14a6bcd..851df149 100755 --- a/src/js/operations/ByteRepr.js +++ b/src/js/operations/ByteRepr.js @@ -1,7 +1,6 @@ import Utils from '../core/Utils'; - /** * Byte representation operations. * diff --git a/src/js/operations/Compress.js b/src/js/operations/Compress.js index 87e2f160..2d4b3940 100755 --- a/src/js/operations/Compress.js +++ b/src/js/operations/Compress.js @@ -16,7 +16,7 @@ const Zlib = { Gunzip: zlibAndGzip.Zlib.Gunzip, Zip: zip.Zlib.Zip, Unzip: zip.Zlib.Unzip, -} +}; /** diff --git a/src/js/operations/HTML.js b/src/js/operations/HTML.js index 2a543161..d5c1ed38 100755 --- a/src/js/operations/HTML.js +++ b/src/js/operations/HTML.js @@ -160,7 +160,7 @@ const HTML = { * @returns {html} */ run_parse_colour_code(input, args) { - var m = null, + let m = null, r = 0, g = 0, b = 0, @@ -201,7 +201,7 @@ const HTML = { b = Math.round(255 * (1 - y_) * (1 - k_)); } - var hsl_ = HTML._rgb_to_hsl(r, g, b), + let hsl_ = HTML._rgb_to_hsl(r, g, b), h = Math.round(hsl_[0] * 360), s = Math.round(hsl_[1] * 100), l = Math.round(hsl_[2] * 100), @@ -226,7 +226,7 @@ const HTML = { cmyk = `cmyk(${c}, ${m}, ${y}, ${k})`; // Generate output - return `${"
" + + return `${`
` + 'Hex: '}${hex}\n` + `RGB: ${rgb}\n` + `RGBA: ${rgba}\n` + diff --git a/src/js/operations/Hexdump.js b/src/js/operations/Hexdump.js index ba73b288..0e231999 100755 --- a/src/js/operations/Hexdump.js +++ b/src/js/operations/Hexdump.js @@ -1,7 +1,6 @@ import Utils from '../core/Utils'; - /** * Hexdump operations. * diff --git a/src/js/operations/IP.js b/src/js/operations/IP.js index c58794f5..039cd802 100755 --- a/src/js/operations/IP.js +++ b/src/js/operations/IP.js @@ -126,13 +126,13 @@ const IP = { // Teredo tunneling output += '\nTeredo tunneling IPv6 address detected\n'; let server_ipv4 = (ipv6[2] << 16) + ipv6[3], - udp_port = (~ipv6[5]) & 0xffff, - client_ipv4 = ~((ipv6[6] << 16) + ipv6[7]), - flag_cone = (ipv6[4] >>> 15) & 1, - flag_r = (ipv6[4] >>> 14) & 1, - flag_random1 = (ipv6[4] >>> 10) & 15, - flag_ug = (ipv6[4] >>> 8) & 3, - flag_random2 = ipv6[4] & 255; + udp_port = (~ipv6[5]) & 0xffff, + client_ipv4 = ~((ipv6[6] << 16) + ipv6[7]), + flag_cone = (ipv6[4] >>> 15) & 1, + flag_r = (ipv6[4] >>> 14) & 1, + flag_random1 = (ipv6[4] >>> 10) & 15, + flag_ug = (ipv6[4] >>> 8) & 3, + flag_random2 = ipv6[4] & 255; output += `\nServer IPv4 address: ${IP._ipv4_to_str(server_ipv4) }\nClient IPv4 address: ${IP._ipv4_to_str(client_ipv4) @@ -141,76 +141,76 @@ const IP = { `\n\tCone: ${flag_cone}`; if (flag_cone) { - output += ' (Client is behind a cone NAT)'; - } else { - output += ' (Client is not behind a cone NAT)'; - } + output += ' (Client is behind a cone NAT)'; + } else { + output += ' (Client is not behind a cone NAT)'; + } output += `\n\tR: ${flag_r}`; if (flag_r) { - output += ' Error: This flag should be set to 0. See RFC 5991 and RFC 4380.'; - } + output += ' Error: This flag should be set to 0. See RFC 5991 and RFC 4380.'; + } output += `\n\tRandom1: ${Utils.bin(flag_random1, 4) }\n\tUG: ${Utils.bin(flag_ug, 2)}`; if (flag_ug) { - output += ' Error: This flag should be set to 00. See RFC 4380.'; - } + output += ' Error: This flag should be set to 00. See RFC 4380.'; + } output += `\n\tRandom2: ${Utils.bin(flag_random2, 8)}`; if (!flag_r && !flag_ug && flag_random1 && flag_random2) { - output += '\n\nThis is a valid Teredo address which complies with RFC 4380 and RFC 5991.'; - } else if (!flag_r && !flag_ug) { - output += '\n\nThis is a valid Teredo address which complies with RFC 4380, however it does not comply with RFC 5991 (Teredo Security Updates) as there are no randomised bits in the flag field.'; - } else { - output += '\n\nThis is an invalid Teredo address.'; - } + output += '\n\nThis is a valid Teredo address which complies with RFC 4380 and RFC 5991.'; + } else if (!flag_r && !flag_ug) { + output += '\n\nThis is a valid Teredo address which complies with RFC 4380, however it does not comply with RFC 5991 (Teredo Security Updates) as there are no randomised bits in the flag field.'; + } else { + output += '\n\nThis is an invalid Teredo address.'; + } output += '\n\nTeredo prefix range: 2001::/32'; } else if (ipv6[0] === 0x2001 && ipv6[1] === 0x2 && ipv6[2] === 0) { // Benchmarking - output += '\nAssigned to the Benchmarking Methodology Working Group (BMWG) for benchmarking IPv6. Corresponds to 198.18.0.0/15 for benchmarking IPv4. See RFC 5180 for more details.'; - output += '\nBMWG range: 2001:2::/48'; - } else if (ipv6[0] == 0x2001 && ipv6[1] >= 0x10 && ipv6[1] <= 0x1f) { + output += '\nAssigned to the Benchmarking Methodology Working Group (BMWG) for benchmarking IPv6. Corresponds to 198.18.0.0/15 for benchmarking IPv4. See RFC 5180 for more details.'; + output += '\nBMWG range: 2001:2::/48'; + } else if (ipv6[0] == 0x2001 && ipv6[1] >= 0x10 && ipv6[1] <= 0x1f) { // ORCHIDv1 - output += '\nDeprecated, previously ORCHIDv1 (Overlay Routable Cryptographic Hash Identifiers).\nORCHIDv1 range: 2001:10::/28\nORCHIDv2 now uses 2001:20::/28.'; - } else if (ipv6[0] == 0x2001 && ipv6[1] >= 0x20 && ipv6[1] <= 0x2f) { + output += '\nDeprecated, previously ORCHIDv1 (Overlay Routable Cryptographic Hash Identifiers).\nORCHIDv1 range: 2001:10::/28\nORCHIDv2 now uses 2001:20::/28.'; + } else if (ipv6[0] == 0x2001 && ipv6[1] >= 0x20 && ipv6[1] <= 0x2f) { // ORCHIDv2 - output += '\nORCHIDv2 (Overlay Routable Cryptographic Hash Identifiers).\nThese are non-routed IPv6 addresses used for Cryptographic Hash Identifiers.'; - output += '\nORCHIDv2 range: 2001:20::/28'; - } else if (ipv6[0] == 0x2001 && ipv6[1] == 0xdb8) { + output += '\nORCHIDv2 (Overlay Routable Cryptographic Hash Identifiers).\nThese are non-routed IPv6 addresses used for Cryptographic Hash Identifiers.'; + output += '\nORCHIDv2 range: 2001:20::/28'; + } else if (ipv6[0] == 0x2001 && ipv6[1] == 0xdb8) { // Documentation - output += '\nThis is a documentation IPv6 address. This range should be used whenever an example IPv6 address is given or to model networking scenarios. Corresponds to 192.0.2.0/24, 198.51.100.0/24, and 203.0.113.0/24 in IPv4.'; - output += '\nDocumentation range: 2001:db8::/32'; - } else if (ipv6[0] == 0x2002) { + output += '\nThis is a documentation IPv6 address. This range should be used whenever an example IPv6 address is given or to model networking scenarios. Corresponds to 192.0.2.0/24, 198.51.100.0/24, and 203.0.113.0/24 in IPv4.'; + output += '\nDocumentation range: 2001:db8::/32'; + } else if (ipv6[0] == 0x2002) { // 6to4 - output += '\n6to4 transition IPv6 address detected. See RFC 3056 for more details.' + + output += '\n6to4 transition IPv6 address detected. See RFC 3056 for more details.' + '\n6to4 prefix range: 2002::/16'; - let v4_addr = IP._ipv4_to_str((ipv6[1] << 16) + ipv6[2]), - sla_id = ipv6[3], - interface_id_str = ipv6[4].toString(16) + ipv6[5].toString(16) + ipv6[6].toString(16) + ipv6[7].toString(16), - interface_id = new BigInteger(interface_id_str, 16); + let v4_addr = IP._ipv4_to_str((ipv6[1] << 16) + ipv6[2]), + sla_id = ipv6[3], + interface_id_str = ipv6[4].toString(16) + ipv6[5].toString(16) + ipv6[6].toString(16) + ipv6[7].toString(16), + interface_id = new BigInteger(interface_id_str, 16); - output += `\n\nEncapsulated IPv4 address: ${v4_addr + output += `\n\nEncapsulated IPv4 address: ${v4_addr }\nSLA ID: ${sla_id }\nInterface ID (base 16): ${interface_id_str }\nInterface ID (base 10): ${interface_id.toString()}`; - } else if (ipv6[0] >= 0xfc00 && ipv6[0] <= 0xfdff) { + } else if (ipv6[0] >= 0xfc00 && ipv6[0] <= 0xfdff) { // Unique local address - output += '\nThis is a unique local address comparable to the IPv4 private addresses 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. See RFC 4193 for more details.'; - output += '\nUnique local addresses range: fc00::/7'; - } else if (ipv6[0] >= 0xfe80 && ipv6[0] <= 0xfebf) { + output += '\nThis is a unique local address comparable to the IPv4 private addresses 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. See RFC 4193 for more details.'; + output += '\nUnique local addresses range: fc00::/7'; + } else if (ipv6[0] >= 0xfe80 && ipv6[0] <= 0xfebf) { // Link-local address - output += '\nThis is a link-local address comparable to the auto-configuration addresses 169.254.0.0/16 in IPv4.'; - output += '\nLink-local addresses range: fe80::/10'; - } else if (ipv6[0] >= 0xff00) { + output += '\nThis is a link-local address comparable to the auto-configuration addresses 169.254.0.0/16 in IPv4.'; + output += '\nLink-local addresses range: fe80::/10'; + } else if (ipv6[0] >= 0xff00) { // Multicast - output += '\nThis is a reserved multicast address.'; - output += '\nMulticast addresses range: ff00::/8'; - } + output += '\nThis is a reserved multicast address.'; + output += '\nMulticast addresses range: ff00::/8'; + } } else { return 'Invalid IPv6 address'; } diff --git a/src/js/operations/StrUtils.js b/src/js/operations/StrUtils.js index 4185bc5e..40723882 100755 --- a/src/js/operations/StrUtils.js +++ b/src/js/operations/StrUtils.js @@ -2,7 +2,6 @@ import Utils from '../core/Utils'; import JsDiff from '../lib/diff'; - /** * String utility operations. * diff --git a/src/js/views/html/OperationsWaiter.js b/src/js/views/html/OperationsWaiter.js index ad1c8cba..c8cd8264 100755 --- a/src/js/views/html/OperationsWaiter.js +++ b/src/js/views/html/OperationsWaiter.js @@ -3,7 +3,6 @@ import HTMLOperation from './HTMLOperation'; import Sortable from '../../lib/Sortable'; - /** * Waiter to handle events related to the operations. * diff --git a/src/js/views/html/OutputWaiter.js b/src/js/views/html/OutputWaiter.js index a96a12ac..918fb7f5 100755 --- a/src/js/views/html/OutputWaiter.js +++ b/src/js/views/html/OutputWaiter.js @@ -5,15 +5,15 @@ import CanvasComponents from './utils/CanvasComponents'; const inlineFuncs = { colorpicker({ rgba }) { $('#colorpicker').colorpicker({ - format: 'rgba', - color: rgba, - container: true, - inline: true, - }).on('changeColor', function(e) { - const { r, g, b, a} = e.color.toRGB(); - const css = `rgba(${r}, ${g}, ${b}, ${a})`; - document.getElementById('input-text').value = css; - window.app.auto_bake(); + format: 'rgba', + color: rgba, + container: true, + inline: true, + }).on('changeColor', (e) => { + const { r, g, b, a } = e.color.toRGB(); + const css = `rgba(${r}, ${g}, ${b}, ${a})`; + document.getElementById('input-text').value = css; + window.app.auto_bake(); }); }, entropy({ entropy }) { @@ -23,15 +23,15 @@ const inlineFuncs = { canvas.width = parent_rect.width * 0.95; canvas.height = height > 150 ? 150 : height; CanvasComponents.draw_scale_bar(canvas, entropy, 8, [ - { - label: 'English text', - min: 3.5, - max: 5 - },{ - label: 'Encrypted/compressed', - min: 7.5, - max: 8 - } + { + label: 'English text', + min: 3.5, + max: 5, + }, { + label: 'Encrypted/compressed', + min: 7.5, + max: 8, + }, ]); }, freq({ percentages }) { @@ -41,8 +41,8 @@ const inlineFuncs = { canvas.width = parent_rect.width * 0.95; canvas.height = parent_rect.height * 0.9; CanvasComponents.draw_bar_chart(canvas, scores, 'Byte', 'Frequency %', 16, 6); - } -} + }, +}; /** * Waiter to handle events related to the output. diff --git a/src/js/views/html/utils/CanvasComponents.js b/src/js/views/html/utils/CanvasComponents.js index 009cf2a2..5c1fa97f 100644 --- a/src/js/views/html/utils/CanvasComponents.js +++ b/src/js/views/html/utils/CanvasComponents.js @@ -10,175 +10,178 @@ */ const CanvasComponents = { - draw_line: function(ctx, start_x, start_y, end_x, end_y) { - ctx.beginPath(); - ctx.moveTo(start_x, start_y); - ctx.lineTo(end_x, end_y); - ctx.closePath(); - ctx.stroke(); - }, + draw_line(ctx, start_x, start_y, end_x, end_y) { + ctx.beginPath(); + ctx.moveTo(start_x, start_y); + ctx.lineTo(end_x, end_y); + ctx.closePath(); + ctx.stroke(); + }, + + draw_bar_chart(canvas, scores, x_axis_label, y_axis_label, num_x_labels, num_y_labels, font_size) { + font_size = font_size || 15; + if (!num_x_labels || num_x_labels > Math.round(canvas.width / 50)) { + num_x_labels = Math.round(canvas.width / 50); + } + if (!num_y_labels || num_y_labels > Math.round(canvas.width / 50)) { + num_y_labels = Math.round(canvas.height / 50); + } + + // Graph properties + let ctx = canvas.getContext('2d'), + left_padding = canvas.width * 0.08, + right_padding = canvas.width * 0.03, + top_padding = canvas.height * 0.08, + bottom_padding = canvas.height * 0.15, + graph_height = canvas.height - top_padding - bottom_padding, + graph_width = canvas.width - left_padding - right_padding, + base = top_padding + graph_height, + ceil = top_padding; + + ctx.font = `${font_size}px Arial`; + + // Draw axis + ctx.lineWidth = '1.0'; + ctx.strokeStyle = '#444'; + CanvasComponents.draw_line(ctx, left_padding, base, graph_width + left_padding, base); // x + CanvasComponents.draw_line(ctx, left_padding, base, left_padding, ceil); // y + + // Bar properties + let bar_padding = graph_width * 0.003, + bar_width = (graph_width - (bar_padding * scores.length)) / scores.length, + curr_x = left_padding + bar_padding, + max = Math.max(...scores); + + // Draw bars + ctx.fillStyle = 'green'; + for (var i = 0; i < scores.length; i++) { + const h = scores[i] / max * graph_height; + ctx.fillRect(curr_x, base - h, bar_width, h); + curr_x += bar_width + bar_padding; + } + + // Mark x axis + ctx.fillStyle = 'black'; + ctx.textAlign = 'center'; + curr_x = left_padding + bar_padding; + if (num_x_labels >= scores.length) { + // Mark every score + for (let j = 0; j <= scores.length; j++) { + ctx.fillText(j, curr_x, base + (bottom_padding * 0.3)); + curr_x += bar_width + bar_padding; + } + } else { + // Mark some scores + for (let k = 0; k <= num_x_labels; k++) { + const val = Math.ceil((scores.length / num_x_labels) * k); + curr_x = (graph_width / num_x_labels) * k + left_padding; + ctx.fillText(val, curr_x, base + (bottom_padding * 0.3)); + } + } + + // Mark y axis + ctx.textAlign = 'right'; + let curr_y; + if (num_y_labels >= max) { + // Mark every increment + for (let l = 0; l <= max; l++) { + curr_y = base - (l / max * graph_height) + font_size / 3; + ctx.fillText(i, left_padding * 0.8, curr_y); + } + } else { + // Mark some increments + for (let m = 0; m <= num_y_labels; m++) { + const val2 = Math.ceil((max / num_y_labels) * m); + curr_y = base - (val2 / max * graph_height) + font_size / 3; + ctx.fillText(val2, left_padding * 0.8, curr_y); + } + } + + // Label x axis + if (x_axis_label) { + ctx.textAlign = 'center'; + ctx.fillText(x_axis_label, graph_width / 2 + left_padding, base + bottom_padding * 0.8); + } + + // Label y axis + if (y_axis_label) { + ctx.save(); + let x = left_padding * 0.3, + y = graph_height / 2 + top_padding; + ctx.translate(x, y); + ctx.rotate(-Math.PI / 2); + ctx.textAlign = 'center'; + ctx.fillText(y_axis_label, 0, 0); + ctx.restore(); + } + }, + + draw_scale_bar(canvas, score, max, markings) { + // Bar properties + let ctx = canvas.getContext('2d'), + left_padding = canvas.width * 0.01, + right_padding = canvas.width * 0.01, + top_padding = canvas.height * 0.1, + bottom_padding = canvas.height * 0.3, + bar_height = canvas.height - top_padding - bottom_padding, + bar_width = canvas.width - left_padding - right_padding; + + // Scale properties + const proportion = score / max; + + // Draw bar outline + ctx.strokeRect(left_padding, top_padding, bar_width, bar_height); + + // Shade in up to proportion + const grad = ctx.createLinearGradient(left_padding, 0, bar_width + left_padding, 0); + grad.addColorStop(0, 'green'); + grad.addColorStop(0.5, 'gold'); + grad.addColorStop(1, 'red'); + ctx.fillStyle = grad; + ctx.fillRect(left_padding, top_padding, bar_width * proportion, bar_height); + + // Add markings + let x0, + y0, + x1, + y1; + ctx.fillStyle = 'black'; + ctx.textAlign = 'center'; + ctx.font = '13px Arial'; + for (let i = 0; i < markings.length; i++) { + // Draw min line down + x0 = bar_width / max * markings[i].min + left_padding; + y0 = top_padding + bar_height + (bottom_padding * 0.1); + x1 = x0; + y1 = top_padding + bar_height + (bottom_padding * 0.3); + CanvasComponents.draw_line(ctx, x0, y0, x1, y1); + + // Draw max line down + x0 = bar_width / max * markings[i].max + left_padding; + x1 = x0; + CanvasComponents.draw_line(ctx, x0, y0, x1, y1); + + // Join min and max lines + x0 = bar_width / max * markings[i].min + left_padding; + y0 = top_padding + bar_height + (bottom_padding * 0.3); + x1 = bar_width / max * markings[i].max + left_padding; + y1 = y0; + CanvasComponents.draw_line(ctx, x0, y0, x1, y1); + + // Add label + if (markings[i].max >= max * 0.9) { + ctx.textAlign = 'right'; + x0 = x1; + } else if (markings[i].max <= max * 0.1) { + ctx.textAlign = 'left'; + } else { + x0 += (x1 - x0) / 2; + } + y0 = top_padding + bar_height + (bottom_padding * 0.8); + ctx.fillText(markings[i].label, x0, y0); + } + }, - draw_bar_chart: function(canvas, scores, x_axis_label, y_axis_label, num_x_labels, num_y_labels, font_size) { - font_size = font_size || 15; - if (!num_x_labels || num_x_labels > Math.round(canvas.width / 50)) { - num_x_labels = Math.round(canvas.width / 50); - } - if (!num_y_labels || num_y_labels > Math.round(canvas.width / 50)) { - num_y_labels = Math.round(canvas.height / 50); - } - - // Graph properties - var ctx = canvas.getContext("2d"), - left_padding = canvas.width * 0.08, - right_padding = canvas.width * 0.03, - top_padding = canvas.height * 0.08, - bottom_padding = canvas.height * 0.15, - graph_height = canvas.height - top_padding - bottom_padding, - graph_width = canvas.width - left_padding - right_padding, - base = top_padding + graph_height, - ceil = top_padding; - - ctx.font = font_size + "px Arial"; - - // Draw axis - ctx.lineWidth = "1.0"; - ctx.strokeStyle = "#444"; - CanvasComponents.draw_line(ctx, left_padding, base, graph_width + left_padding, base); // x - CanvasComponents.draw_line(ctx, left_padding, base, left_padding, ceil); // y - - // Bar properties - var bar_padding = graph_width * 0.003, - bar_width = (graph_width - (bar_padding * scores.length)) / scores.length, - curr_x = left_padding + bar_padding, - max = Math.max.apply(Math, scores); - - // Draw bars - ctx.fillStyle = "green"; - for (var i = 0; i < scores.length; i++) { - var h = scores[i] / max * graph_height; - ctx.fillRect(curr_x, base - h, bar_width, h); - curr_x += bar_width + bar_padding; - } - - // Mark x axis - ctx.fillStyle = "black"; - ctx.textAlign = "center"; - curr_x = left_padding + bar_padding; - if (num_x_labels >= scores.length) { - // Mark every score - for (var j = 0; j <= scores.length; j++) { - ctx.fillText(j, curr_x, base + (bottom_padding * 0.3)); - curr_x += bar_width + bar_padding; - } - } else { - // Mark some scores - for (var k = 0; k <= num_x_labels; k++) { - var val = Math.ceil((scores.length / num_x_labels) * k); - curr_x = (graph_width / num_x_labels) * k + left_padding; - ctx.fillText(val, curr_x, base + (bottom_padding * 0.3)); - } - } - - // Mark y axis - ctx.textAlign = "right"; - var curr_y; - if (num_y_labels >= max) { - // Mark every increment - for (var l = 0; l <= max; l++) { - curr_y = base - (l / max * graph_height) + font_size / 3; - ctx.fillText(i, left_padding * 0.8, curr_y); - } - } else { - // Mark some increments - for (var m = 0; m <= num_y_labels; m++) { - var val2 = Math.ceil((max / num_y_labels) * m); - curr_y = base - (val2 / max * graph_height) + font_size / 3; - ctx.fillText(val2, left_padding * 0.8, curr_y); - } - } - - // Label x axis - if (x_axis_label) { - ctx.textAlign = "center"; - ctx.fillText(x_axis_label, graph_width / 2 + left_padding, base + bottom_padding * 0.8); - } - - // Label y axis - if (y_axis_label) { - ctx.save(); - var x = left_padding * 0.3, - y = graph_height / 2 + top_padding; - ctx.translate(x, y); - ctx.rotate(-Math.PI / 2); - ctx.textAlign = "center"; - ctx.fillText(y_axis_label, 0, 0); - ctx.restore(); - } - }, - - draw_scale_bar: function(canvas, score, max, markings) { - // Bar properties - var ctx = canvas.getContext("2d"), - left_padding = canvas.width * 0.01, - right_padding = canvas.width * 0.01, - top_padding = canvas.height * 0.1, - bottom_padding = canvas.height * 0.3, - bar_height = canvas.height - top_padding - bottom_padding, - bar_width = canvas.width - left_padding - right_padding; - - // Scale properties - var proportion = score / max; - - // Draw bar outline - ctx.strokeRect(left_padding, top_padding, bar_width, bar_height); - - // Shade in up to proportion - var grad = ctx.createLinearGradient(left_padding, 0, bar_width + left_padding, 0); - grad.addColorStop(0, "green"); - grad.addColorStop(0.5, "gold"); - grad.addColorStop(1, "red"); - ctx.fillStyle = grad; - ctx.fillRect(left_padding, top_padding, bar_width * proportion, bar_height); - - // Add markings - var x0, y0, x1, y1; - ctx.fillStyle = "black"; - ctx.textAlign = "center"; - ctx.font = "13px Arial"; - for (var i = 0; i < markings.length; i++) { - // Draw min line down - x0 = bar_width / max * markings[i].min + left_padding; - y0 = top_padding + bar_height + (bottom_padding * 0.1); - x1 = x0; - y1 = top_padding + bar_height + (bottom_padding * 0.3); - CanvasComponents.draw_line(ctx, x0, y0, x1, y1); - - // Draw max line down - x0 = bar_width / max * markings[i].max + left_padding; - x1 = x0; - CanvasComponents.draw_line(ctx, x0, y0, x1, y1); - - // Join min and max lines - x0 = bar_width / max * markings[i].min + left_padding; - y0 = top_padding + bar_height + (bottom_padding * 0.3); - x1 = bar_width / max * markings[i].max + left_padding; - y1 = y0; - CanvasComponents.draw_line(ctx, x0, y0, x1, y1); - - // Add label - if (markings[i].max >= max * 0.9) { - ctx.textAlign = "right"; - x0 = x1; - } else if (markings[i].max <= max * 0.1) { - ctx.textAlign = "left"; - } else { - x0 = x0 + (x1 - x0) / 2; - } - y0 = top_padding + bar_height + (bottom_padding * 0.8); - ctx.fillText(markings[i].label, x0, y0); - } - }, - }; export default CanvasComponents;