block by zeffii 1554f5cc59f7b4b3403d

mediseen0.2 18march2016

Full Screen

Built with blockbuilder.org

forked from zeffii‘s block: mediseen0.2

index.html

<!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>

/*

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"

     // 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>

medilist.csv

time,med,num,dose,descriptor
08:00,Nexium,1,40mg,(D-pink|oval|AEl 40mg)
08:00,Thyrax,1,0.025mg,(#45D0FC|round|brkwide|ZK 5)
08:00,Thyrax,1,0.10mg,(white|round|brkwide|ZK 2)
08:00,Hydrocortison,1,10mg,(white|round-small|brkthin|fullname)
08:00,Hydrocortison,1,5mg,(white|round|brkx|fullname)
08:00,Furosemide,1,20mg,(white|round|FUR.20)
08:00,BREAKFAST,-,--,(--)
08:00,Spironolacton,1,100mg,(white|round|AF)
08:00,Metformine,1,500mg,(white|round|_)
08:00,Ursofalk,2,250mg,(white/white|capsule|_)
08:00,Lyrica,1,150mg,(white/white|capsule|PGN 150)
10:00,Desmopressin,1,0.1mg,(white|round|brkthin|0.1)
18:00,Furosemide,1,20mg,(white|round|FUR.20)
18:00,DINNER,-,--,(--)
18:00,Metformine,1,500mg,(white|round|_)
18:00,Ursofalk,2,250mg,(white/white|capsule|_)
22:00,Hydrocortison,1,5mg,(white|round|brkx|fullname)
22:00,Desmopressin,1,0.1mg,(white|round|brkthin|0.1)
22:00,SLEEP,-,--,(--)

rules.txt

Universal Medicine Descriptor Language | Revision B, Draft

Consider describing any medication using a set of rules:

color(s)|shape|groovetype|inscription
color|shape|inscription