{% extends "admin/base_site_gridpivot.html" %} {% load i18n %} {% block tools %}{% if args.0 %}{% tabs "input.buffer" %}{% endif %}{{block.super}}{% endblock %} {% block before_table %}{% if args.0 %}
{% endif %}{% endblock %} {% block crosses %} {% if args.0 %}$(function(){ // Resize top graph var h = $(window).height(); $("#graph").width($(window).width()-60).height(h>800 || h<480 ? 400 : h-420); });{% endif %} {% if args.0 or mode == "graph" %} function drawGraphs(jsondata) { {% if args.0 %}var margin = {top: 0, right: 100, bottom: 30, left: 70}; {% else %}var margin = {top: 0, right: 0, bottom: 0, left: 70}; {% endif %}var width = $({% if args.0 %}"#graph"{% else %}"#grid_graph"{% endif %}).width() - margin.left - margin.right; var height = {% if args.0 %}$("#graph").height(){% else %}80{% endif %} - margin.top - margin.bottom; // Lookup table of displayed columns var fields = {}; for (var i in cross_idx) fields[cross_idx[i]] = 0; // Define X-axis var domain_x = []; var bucketnamelength = 0; for (var i in timebuckets) { domain_x.push(timebuckets[i]['name']); bucketnamelength = Math.max(timebuckets[i]['name'].length, bucketnamelength); } var x = d3.scale.ordinal() .domain(domain_x) .rangeRoundBands([0, width], .1); var x_width = x.rangeBand(); {% if mode == "graph" and not args.0 %}graph.header(margin.left, x);{% endif %} // Define Y-axis var y = d3.scale.linear().rangeRound([height, 0]); // Draw all graphs $("#grid"){% if not args.0 %}.find(".graph"){% endif %}.each(function(index) { // Create a new SVG element $({% if args.0 %}$("#graph").get(0){% else %}this{% endif %}).html(""); var svg = d3.select({% if args.0 %}$("#graph").get(0){% else %}this{% endif %}) .append("svg") .attr("class","graphcell") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // Build the data for d3 var max_y = 0; var min_y = 0; var data = []; for (var bckt in timebuckets) { var tmp = jsondata['rows'][index][timebuckets[bckt]['name']]; data.push({ 'buffer': jsondata['rows'][index]['buffer'], 'bucket': bckt, 'startinv': tmp[0], 'startohdoc': tmp[1], 'safetystock': tmp[2], 'consumed': tmp[3], 'consumedMO': tmp[4], 'consumedDO': tmp[5], 'consumedSO': tmp[6], 'produced': tmp[7], 'producedMO': tmp[8], 'producedDO': tmp[9], 'producedPO': tmp[10], 'endinv': tmp[11], 'total_in_progress': tmp[12], 'work_in_progress_mo': tmp[13], 'on_order_po': tmp[14], 'in_transit_do': tmp[15] }); for (var i in cross_idx) { if (cross_idx[i] == 0 || cross_idx[i] == 2 || cross_idx[i] == 3 || cross_idx[i] == 7 || cross_idx[i] == 11) { if (tmp[cross_idx[i]] < min_y) min_y = tmp[cross_idx[i]]; if (tmp[cross_idx[i]] > max_y) max_y = tmp[cross_idx[i]]; } } } // Update the scale of the Y-axis by looking for the max value y.domain([min_y,max_y]); var y_zero = y(0); // Create D3 bars var my_y; svg.selectAll("g") .data(data) .enter() .append("g") .attr("transform", function(d) { return "translate(" + x(timebuckets[d['bucket']]['name']) + ",0)"; }) .each(function(d) { var bucket = d3.select(this); if (d['produced'] > 0 && 1 in fields) { my_y = y(d['produced']); bucket.append("rect") .attr("width", x_width/2) .attr("height", y_zero - my_y) .attr("x", x_width/2) .attr("y", my_y) .style("fill","#2B95EC"); } if (d['consumed'] > 0 && 2 in fields) { my_y = y(d['consumed']); bucket.append("rect") .attr("width", x_width/2) .attr("height", y_zero - my_y) .attr("y", my_y) .style("fill","#F6BD0F"); } // Invisible rectangle for the tooltip bucket.append("rect") .attr("height", height) .attr("width", x_width) .attr("fill-opacity", 0) .on("click", function(d) { if (d3.event.defaultPrevented || (d['produced'] == 0 && d['consumed'] == 0)) return; d3.select("#tooltip").style('display', 'none'); window.location = url_prefix + "/flowplan/" + admin_escape(d['buffer']) + "/?noautofilter&flowdate__gte=" + timebuckets[d['bucket']]['startdate'] + "&flowdate__lt=" + timebuckets[d['bucket']]['enddate']; d3.event.stopPropagation(); }) .on("mouseenter", function(d) { tiptext = '
' + timebuckets[d['bucket']]['name'] + '
' + '
{{_('start inventory days of cover')|capfirst}}' + d['startohdoc'] + " {{_('days')}}" + '
{{_('start inventory')|capfirst}}' + grid.formatNumber(d['startinv']); if (d['producedPO']) tiptext += '
{{_('produced by PO')|capfirst}}+ ' + grid.formatNumber(d['producedPO']); if (d['producedMO']) tiptext += '
{{_('produced by MO')|capfirst}}+ ' + grid.formatNumber(d['producedMO']); if (d['producedDO']) tiptext += '
{{_('produced by DO')|capfirst}}+ ' + grid.formatNumber(d['producedDO']); if (d['consumedMO']) tiptext += '
{{_('consumed by MO')|capfirst}}- ' + grid.formatNumber(d['consumedMO']); if (d['consumedSO']) tiptext += '
{{_('consumed by SO')|capfirst}}- ' + grid.formatNumber(d['consumedSO']); if (d['consumedDO']) tiptext += '
{{_('consumed by DO')|capfirst}}- ' + grid.formatNumber(d['consumedDO']); tiptext += '
{{_('end inventory')|capfirst}}= ' + grid.formatNumber(d['startinv']+d['produced']-d['consumed']); if (d['safetystock']) tiptext += '
{{_('safety stock')|capfirst}}' + grid.formatNumber(d['safetystock']); if (d['total_in_progress']) tiptext += '
{{_('total in progress')|capfirst}}' + grid.formatNumber(d['total_in_progress']); if (d['work_in_progress_mo']) tiptext += '
{{_('work in progress MO')|capfirst}}' + grid.formatNumber(d['work_in_progress_mo']); if (d['on_order_po']) tiptext += '
{{_('on order PO')|capfirst}}' + grid.formatNumber(d['on_order_po']); if (d['in_transit_do']) tiptext += '
{{_('in transit DO')|capfirst}}' + grid.formatNumber(d['in_transit_do']); tiptext += '
' graph.showTooltip(tiptext); }) .on("mouseleave", graph.hideTooltip) .on("mousemove", graph.moveTooltip); }); // Create D3 line if (0 in fields) { var line = d3.svg.line() .x(function(d) { return x(timebuckets[d['bucket']]['name']) + x_width / 2; }) .y(function(d) { return y(d['startinv']); }); svg.append("svg:path") .attr('class', 'graphline') .attr("stroke","#8BBA00") .attr("d", line(data)); } else if (3 in fields) { var line = d3.svg.line() .x(function(d) { return x(timebuckets[d['bucket']]['name']) + x_width / 2; }) .y(function(d) { return y(d['endinv']); }); svg.append("svg:path") .attr('class', 'graphline') .attr("stroke","#7B5E08") .attr("d", line(data)); } if (2 in fields) { var line = d3.svg.line() .x(function(d) { return x(timebuckets[d['bucket']]['name']) + x_width / 2; }) .y(function(d) { return y(d['safetystock']); }); svg.append("svg:path") .attr('class', 'graphline') .attr("stroke","#FF0000") .attr("d", line(data)); } // Display Y-Axis var yAxis = d3.svg.axis() .scale(y) .orient("left"); {% if not args.0 %} svg.append("g") .attr("class", "miniaxis") .call(graph.miniAxis.bind(yAxis)); {% else %} svg.append("g") .attr("class", "y axis") .call(yAxis); // Display 0 line if (min_y < 0 && max_y > 0) svg.append("line") .attr("x1", 0) .attr("x2", width) .attr("y1", y(0)) .attr("y2", y(0)) .attr("stroke-width", 1) .attr("stroke", "black") .attr("shape-rendering", "crispEdges"); // Display X-axis for a single buffer var nth = Math.ceil(timebuckets.length / width * bucketnamelength * 10); var myticks = []; for (var i in timebuckets) if (i % nth == 0) myticks.push(timebuckets[i]['name']); var xAxis = d3.svg.axis() .scale(x) .tickValues(myticks) .orient("bottom"); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); // Display legend var legend = svg.append("g"); var codes = [ ["{{_('start inventory')|capfirst}}", "#8BBA00"], [], ["{{_('safety stock')|capfirst}}", "#FF0000"], ["{{_('consumed')|capfirst}}", "#F6BD0F"], [], [], [], ["{{_('produced')|capfirst}}", "#2B95EC"], [], [], [], ["{{_('end inventory')|capfirst}}", "#7B5E08"] ]; var cnt = 0; for (var i in cross_idx) { if (cross_idx[i] == 0 || cross_idx[i] == 2|| cross_idx[i] == 3 || cross_idx[i] == 7 || cross_idx[i] == 11) { legend.append("rect") .attr("x", width + 82) .attr("width", 18) .attr("height", 18) .style("fill", codes[cross_idx[i]][1]) .attr("transform", "translate(0," + (cnt*20+10) + ")"); legend.append("text") .attr("x", width + 76) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(codes[cross_idx[i]][0]) .attr("transform", "translate(0," + (cnt*20+10) + ")"); ++cnt; } }{% endif %} }); } {% endif %} {% if args.0 or mode == "table" %} function crosses (cellvalue, options, rowdata) { var result = ''; for (var i in cross_idx) switch(cross_idx[i]) { case 1: result += cellvalue[cross_idx[i]] + '
'; break; case 3: if (cellvalue[3] != 0.0) result += grid.formatNumber(cellvalue[3]) + " 
"; else result += '0
'; break; case 4: if (cellvalue[4] != 0.0) result += grid.formatNumber(cellvalue[4]) + " 
"; else result += '0
'; break; case 5: if (cellvalue[5] != 0.0) result += grid.formatNumber(cellvalue[5]) + " 
"; else result += '0
'; break; case 6: if (cellvalue[6] != 0.0) result += grid.formatNumber(cellvalue[6]) + " 
"; else result += '0
'; break; case 7: if (cellvalue[7] != 0.0) result += grid.formatNumber(cellvalue[7]) + " 
"; else result += '0
'; break; case 8: if (cellvalue[8] != 0.0) result += grid.formatNumber(cellvalue[8]) + " 
"; else result += '0
'; break; case 9: if (cellvalue[9] != 0.0) result += grid.formatNumber(cellvalue[9]) + " 
"; else result += '0
'; break; case 10: if (cellvalue[10] != 0.0) result += grid.formatNumber(cellvalue[10]) + " 
"; else result += '0
'; break; case 13: if (cellvalue[13] != 0.0) result += grid.formatNumber(cellvalue[13]) + " 
"; else result += '0
'; break; case 14: if (cellvalue[14] != 0.0) result += grid.formatNumber(cellvalue[14]) + " 
"; else result += '0
'; break; case 15: if (cellvalue[15] != 0.0) result += grid.formatNumber(cellvalue[15]) + " 
"; else result += '0
'; break; default: result += grid.formatNumber(cellvalue[cross_idx[i]]) + '
'; } return result; }; {% endif %}{% endblock %} {% block extra_grid %}{% if args.0 or mode == "graph" %}loadComplete: drawGraphs, {% endif %}{% endblock %}