Built with blockbuilder.org
forked from zeffii's block: mediseen0.2
forked from zeffii's block: mediseen0.2 18march2016
Built with blockbuilder.org
forked from zeffii's block: mediseen0.2
forked from zeffii's block: mediseen0.2 18march2016
| <!DOCTYPE html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
| <style> | |
| body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
| svg { width:100%; height: 100% } | |
| </style> | |
| </head> | |
| <body> | |
| <svg></svg> | |
| <script> | |
| /* | |
| CURRENT MEDICATION SPECIMEN. | |
| MIT license. Dealga McArdle. 2009-2015 | |
| Rewrite in Progress. | |
| Specifically written for people who have a difficult time | |
| figuring out their meds. It's easy for family or a healthcare | |
| professional to update and print when changes are made. | |
| It parses a medicine descriptor string used to describe most | |
| forms of medication. (Universal Medicine Descriptor Language). | |
| only caviat is some meds have weird shapes. A solution is to | |
| allow the medication descriptor to include a link to a bitmap. | |
| Milestones | |
| [x] parse csv | |
| [x] draw time, number, medication name, dose | |
| [x] parse UMDL as vector | |
| [ ] parse IMGUR 5 or 7 digit code when no UMDL is present | |
| [ ] write up formalized UMDL | |
| */ | |
| d3.select("body").style("background-color", d3.rgb(255,255,255)) | |
| var svg = d3.select("svg"); | |
| var defs = svg.append("defs"); | |
| var group1 = svg.append("g").classed("group1", true); | |
| var group2 = svg.append("g").classed("group2", true); | |
| var group3 = svg.append("g").classed("group2", true); | |
| var global_transform = "translate(" + [40, 63] + ")"; | |
| group1.attr("transform", global_transform) | |
| group2.attr("transform", global_transform) | |
| group3.attr("transform", global_transform) | |
| d3.csv("medilist.csv", generateList); | |
| var data = []; | |
| function generateList(data){ | |
| data = data; | |
| var line_height = 23, | |
| padding_y = 13, | |
| padding_x = 130, | |
| type_height = 19, | |
| time_height = 29, | |
| divider_height = 6, | |
| divider_width = 291, | |
| ty = 30, | |
| my = ty, | |
| vert_lines_x_offset = 259, | |
| outline_width = {"stroke-width": 0.7 + "px"}, | |
| div_style = {"fill": "#424242", "stroke": "none"}, | |
| med_style = {"fill": "#837979", "stroke": "none", "font-family": "sans-serif"}, | |
| dose_style = {"fill": "#77A2CA", "stroke": "none", "font-family": "sans-serif"}, | |
| text_styles = [med_style, dose_style]; | |
| function assemble_med_list(data, med_list, time_list){ | |
| data.forEach(function(d){ | |
| if (d.time in med_list) med_list[d.time].push(d) | |
| else { | |
| med_list[d.time] = [d] | |
| time_list.push(d.time) | |
| } | |
| }) | |
| return [med_list, time_list] | |
| } | |
| var med_and_time_list = assemble_med_list(data, {}, []); | |
| var med_list = med_and_time_list[0]; | |
| var time_list = med_and_time_list[1]; | |
| function draw_text(text, size, pos, style){ | |
| group1.append('text') | |
| .text(text) | |
| .attr(pos) | |
| .style(style) | |
| .style({"font-size": size}) | |
| } | |
| function draw_text2(text, size, pos){ | |
| group1.append('text') | |
| .text(text.med) | |
| .attr(pos) | |
| .style(med_style) | |
| .style({"font-size": size}) | |
| .append('tspan') | |
| .text(" " + text.dose) | |
| .style(dose_style) | |
| } | |
| function draw_divider(pos){ | |
| group1.append("rect") | |
| .attr(pos) | |
| .attr({height: divider_height, width: divider_width}) | |
| .style(div_style) | |
| } | |
| function _adjust(ty){ return ty-35 } | |
| function buffer_space(n){ return (2 * padding_y) + (n * line_height) } | |
| function parse_umdl(d){ | |
| var descr_array, | |
| descr_object, | |
| descr = d.descriptor, | |
| descr_length = descr.length; | |
| // maybe enforcing this leads to unnecessary complexity | |
| // but i like the way it helps keep the description together | |
| // optically at least in the csv | |
| if ((descr[0] != "(") || (descr[descr_length-1] != ")")){ | |
| console.error(descr) | |
| console.error("descriptor must be enclosed in parentheses") | |
| return | |
| } | |
| // strip parentheses | |
| descr = descr.slice(1, descr_length-1) | |
| // split into color(s)|shape|[groovetype|]inscription object | |
| descr_array = descr.split("|") | |
| if (descr_array.length === 3){ | |
| descr_object = { | |
| color: descr_array[0].split("/"), | |
| shape: descr_array[1], | |
| inscription: descr_array[2], | |
| numparams: 3 | |
| } | |
| } | |
| else if (descr_array.length === 4){ | |
| descr_object = { | |
| color: descr_array[0].split("/"), | |
| shape: descr_array[1], | |
| groovetype: descr_array[2], | |
| inscription: descr_array[3], | |
| numparams: 4 | |
| } | |
| } | |
| else { | |
| var error_message = "descriptor must take form: \n"; | |
| error_message += "color(s)|shape|groovetype|inscription\n" | |
| error_message += "or\n" | |
| error_message += "color|shape|inscription" | |
| console.error(error_message) | |
| return | |
| } | |
| return descr_object | |
| } | |
| function console_debug(d, medicine_object){ | |
| console.log("______") | |
| console.log(d.descriptor) | |
| console.log("color(s):", medicine_object.color) | |
| console.log("shape:", medicine_object.shape) | |
| if (medicine_object.numparams === 4) | |
| console.log("groove type:", medicine_object.groovetype) | |
| if (medicine_object.inscription != "_") | |
| console.log("inscription:", medicine_object.inscription) | |
| } | |
| function draw_from_umdl(d, pos){ | |
| var medicine_object = parse_umdl(d); | |
| // check if this parsed a valid umdl | |
| if (!medicine_object){ | |
| console.error(d, "didn't parse correctly") | |
| // draw questionmark? | |
| return | |
| } | |
| var show_debug = [false, true][0]; | |
| if (show_debug) console_debug(d, medicine_object) | |
| draw_medicine(medicine_object, pos) | |
| } | |
| c_list = { | |
| "D-pink": "#F171E7", | |
| "D-khaki": "#f0f06f" | |
| // add custom colors | |
| }; | |
| function color_list_check(c_in){ | |
| if (c_in in c_list) return c_list[c_in] | |
| else { | |
| console.error(c_in, "not in color list (c_list), add it!") | |
| return "#fff" | |
| } | |
| } | |
| function draw_liteline(pos){ | |
| // function draw_text(text, size, pos, style){ | |
| var y_tweak = 4; | |
| var line_start_x = 239; | |
| var line_width_x = 630; | |
| var line_height_y = type_height+4; | |
| group1.append("line") | |
| .attr(pos) | |
| .attr({x1: line_start_x, y1:0+y_tweak, x2: line_start_x + line_width_x, y2: 0+y_tweak}) | |
| .style({"stroke-width": "1px", "stroke": "#eee"}) | |
| group1.append("line") | |
| .attr(pos) | |
| .attr({x1: line_start_x, y1: -line_height_y + y_tweak, x2: line_start_x + line_width_x, y2: -line_height_y + y_tweak}) | |
| .style({"stroke-width": "1px", "stroke": "#eee"}) | |
| } | |
| function draw_vertline(x, total_height){ | |
| var line_start_y = -4; | |
| group1.append("line") | |
| .attr({"transform": "translate(" + [x, 0] + ")"}) | |
| .attr({x1: x, y1:line_start_y, x2: x, y2: line_start_y + total_height}) | |
| .style({"stroke-width": "1px", "stroke": "#aaa"}) | |
| } | |
| function draw_medicine(mo, pos){ | |
| var med = group2.append("g") | |
| var med_r = type_height/2; | |
| var shape = mo.shape.toLowerCase(); | |
| var size = shape.indexOf("small") >= 0 ? "small" : "normal"; | |
| if (size==="small") med_r *= 0.8 | |
| // round & round-small | |
| if (shape.indexOf("round") >= 0){ | |
| med.append("circle") | |
| .attr({"cx": pos.x, "cy": pos.y-med_r/2, "r": med_r}) | |
| .style({stroke: "#121212", "fill": mo.color[0]}) | |
| .style(outline_width) | |
| } | |
| // oval | |
| if (shape.indexOf("oval") >= 0){ | |
| var oval_color = color_list_check(mo.color[0]); | |
| med.append("ellipse") | |
| .attr({"cx": pos.x, "cy": pos.y-med_r/2, | |
| "rx": med_r*1.5, "ry": med_r}) | |
| .style({stroke: "#121212", "fill": oval_color}) | |
| .style(outline_width) | |
| } | |
| if (mo.groovetype){ | |
| var groove = mo.groovetype.toLowerCase(); | |
| var g_width = 1; | |
| if (groove === "brkthin") g_width = 1 | |
| if (groove === "brkwide") g_width = 4 | |
| var groove_style = { | |
| "stroke": "#000", | |
| "stroke-width": g_width +"px", | |
| "stroke-opacity": 0.6 | |
| }; | |
| med.append('line') | |
| .attr({x1: pos.x, y1: pos.y, x2: pos.x, y2: pos.y-(med_r*2)}) | |
| .style(groove_style) | |
| .attr("transform", "translate("+ [0, med_r/2] + ")") | |
| if (groove === "brkx"){ | |
| med.append('line') | |
| .attr({x1: pos.x-med_r, y1: pos.y-(med_r), x2: pos.x+med_r, y2: pos.y-(med_r)}) | |
| .style(groove_style) | |
| .attr("transform", "translate("+ [0, med_r/2] + ")") | |
| } | |
| } | |
| function side_(dir, med_r){ | |
| var th = med_r, | |
| two_th = med_r*2, | |
| straight_1 = "M" + [0,0,-th*dir,0].join(" "), | |
| curve = "C" + [-two_th*dir, 0, -two_th*dir, -two_th, -th*dir, -two_th].join(" "), | |
| straight_2 = "L" + [0,-two_th].join(" "); | |
| return straight_1 + curve + straight_2; | |
| } | |
| // capsule | |
| if (shape==="capsule"){ | |
| var cap = {x: pos.x, y: pos.y+(med_r/2)}; | |
| med.append("path") | |
| .attr("d", side_(1, med_r)) | |
| .style({stroke: "#121212", "fill": mo.color[0]}) | |
| .style(outline_width) | |
| med.append("path") | |
| .attr("d", side_(-1, med_r)) | |
| .style({stroke: "#121212", "fill": mo.color[1]}) | |
| .style(outline_width) | |
| med.attr("transform", "translate(" + [cap.x, cap.y] + ")") | |
| } | |
| // inscriptions | |
| if (mo.inscription != "_"){ | |
| group3.append('text') | |
| .attr({x: pos.x + 30, y: pos.y}) | |
| .text(mo.inscription) | |
| .style(med_style) | |
| } | |
| } | |
| var end_height = 0; | |
| time_list.forEach(function(d){ | |
| my = ty; | |
| draw_divider({x: padding_x, y: _adjust(ty)}) | |
| var num_items = med_list[d].length; | |
| var extra_space = buffer_space(num_items); | |
| var text_y = ty + (extra_space / 2) - (padding_y * 1.4); | |
| // draw time | |
| draw_text(d, time_height, {x: 37, y: text_y-5}, med_style) | |
| ty += extra_space | |
| // draw details for each | |
| med_list[d].forEach(function(m){ | |
| draw_text(m.num, type_height, {x: 152, y: my}, med_style) | |
| draw_text2(m, type_height, {x: 172, y: my}) | |
| draw_liteline({"transform": "translate(" + [172, my] + ")"}) | |
| draw_from_umdl(m, {x: 389, y: my}) | |
| my += line_height | |
| }) | |
| end_height = my; | |
| }) | |
| draw_divider({x: padding_x, y: _adjust(ty)}) | |
| // draw vertical markings | |
| 'Za Zo Ma Di Wo Do Vr'.split(' ').forEach(function(d, i){ | |
| // draw_vertline(x, total_height) | |
| var twinky = 35; | |
| var line_x = vert_lines_x_offset + 36*i; | |
| draw_vertline(line_x, end_height); | |
| draw_text(d, 14, {x: line_x+287+(twinky*i), y: 0}) | |
| console.log(d) | |
| }) | |
| console.log("______\nscript finished") | |
| /* EOF */ | |
| } | |
| </script> | |
| </body> |
| time | med | num | dose | descriptor | |
|---|---|---|---|---|---|
| 07:00 | Thyrax | 1 | 0.025mg | (#45D0FC|round|brkwide|ZK 5) | |
| 07:00 | Thyrax | 1 | 0.10mg | (white|round|brkwide|ZK 2) | |
| 08:00 | Furosemide | 1 | 20mg | (white|round|FUR.20) | |
| 08:00 | BREAKFAST | - | -- | (--) | |
| 08:00 | Lactulose Stroop | 1 | 15ml | (--) | |
| 08:00 | Pantoprazol | 1 | 40mg | (D-khaki|oval|ps4) | |
| 08:00 | Hydrocortison | 1 | 10mg | (white|round-small|brkthin|fullname) | |
| 08:00 | Hydrocortison | 1 | 5mg | (white|round|brkx|fullname) | |
| 08:00 | Spironolacton | 1 | 100mg | (white|round|AF) | |
| 08:00 | Ursofalk | 2 | 250mg | (white/white|capsule|_) | |
| 10:00 | Desmopressine | 1 | 0.1mg | (white|round|brkthin|0.1) | |
| 13:00 | Hydrocortison | 1 | 5mg | (white|round|brkx|fullname) | |
| 13:00 | Lactulose Stroop | 1 | 15ml | (--) | |
| 18:00 | Furosemide | 1 | 20mg | (white|round|FUR.20) | |
| 18:00 | DINNER | - | -- | (--) | |
| 18:00 | Ursofalk | 2 | 250mg | (white/white|capsule|_) | |
| 18:00 | Pantoprazol | 1 | 40mg | (D-khaki|oval|ps4) | |
| 18:00 | Lyrica | 1 | 150mg | (white/white|capsule|PGN 150) | |
| 18:00 | Lactulose Stroop | 1 | 15ml | (--) | |
| 22:00 | Desmopressine | 1 | 0.1mg | (white|round|brkthin|0.1) | |
| 22:00 | SLEEP | - | -- | (--) |
| Universal Medicine Descriptor Language | Revision B, Draft | |
| Consider describing any medication using a set of rules: | |
| color(s)|shape|groovetype|inscription | |
| color|shape|inscription |