<window id="lossplots">
    <reporttitle>Production:->Weight Loss By Item and Operator</reporttitle>
    <layout type="vertical">
        <webview id="report" />
    </layout>
    <menu name="File">
        <item id="print" shortcut="Ctrl+P">Print...</item>
    </menu>
    <program>
        <![CDATA[
this.windowTitle = TTR("lossplots", "Typica - Weight Loss By Item and Operator");
var report = findChildObject(this, 'report');
var printMenu = findChildObject(this, 'print');
printMenu.triggered.connect(function() {
    report.print();
});
var query = new QSqlQuery;
query.exec("WITH a AS (SELECT roasted_id, max(time) AS last_batch FROM roasting_log WHERE roasted_id IN (SELECT item FROM current_items) GROUP BY roasted_id), b AS (SELECT roasted_id, last_batch, (SELECT unroasted_id FROM roasting_log WHERE roasted_id = a.roasted_id AND time = last_batch) FROM a), c AS (SELECT roasting_log.roasted_id, ((unroasted_total_quantity - roasted_quantity)/unroasted_total_quantity) AS loss FROM roasting_log, b WHERE roasting_log.roasted_id = b.roasted_id AND roasting_log.unroasted_id = b.unroasted_id AND unroasted_total_quantity > 0 AND approval = true) SELECT roasted_id, (SELECT name FROM items WHERE id = roasted_id) AS name, count(1), min(loss), percentile_cont(0.25) WITHIN GROUP (ORDER BY loss) AS lower_quart, percentile_cont(0.5) WITHIN GROUP (ORDER BY loss) AS median, percentile_cont(0.75) WITHIN GROUP (ORDER BY loss) AS upper_quart, max(loss), avg(loss) FROM c GROUP BY roasted_id ORDER BY name ASC");
var items = new Array;
while(query.next()) {
    var item = new Object;
    item.roasted_id = query.value(0);
    item.name = query.value(1);
    item.mean = query.value(8);
    item.min = query.value(3);
    item.max = query.value(7);
    item.plots = new Array;
    var plot = new Object;
    plot.count = query.value(2);
    plot.min = item.min;
    plot.max = item.max;
    plot.lower_quart = query.value(4);
    plot.median = query.value(5);
    plot.upper_quart = query.value(6);
    plot.name = "All";
    item.plots.push(plot);
    items.push(item);
}
query.exec("WITH a AS (SELECT roasted_id, max(time) AS last_batch FROM roasting_log WHERE roasted_id IN (SELECT item FROM current_items) GROUP BY roasted_id), b AS (SELECT roasted_id, last_batch, (SELECT unroasted_id FROM roasting_log WHERE roasted_id = a.roasted_id AND time = last_batch) FROM a), c AS (SELECT roasting_log.roasted_id, ((unroasted_total_quantity - roasted_quantity)/unroasted_total_quantity) AS loss, person FROM roasting_log, b WHERE roasting_log.roasted_id = b.roasted_id AND roasting_log.unroasted_id = b.unroasted_id AND unroasted_total_quantity > 0 AND approval = true) SELECT roasted_id, person, count(1), min(loss), percentile_cont(0.25) WITHIN GROUP (ORDER BY loss) AS lower_quart, percentile_cont(0.5) WITHIN GROUP (ORDER BY loss) AS median, percentile_cont(0.75) WITHIN GROUP (ORDER BY loss) AS upper_quart, max(loss) FROM c GROUP BY roasted_id, person");
while(query.next()) {
    var plot = new Object;
    plot.count = query.value(2);
    plot.min = query.value(3);
    plot.max = query.value(7);
    plot.lower_quart = query.value(4);
    plot.median = query.value(5);
    plot.upper_quart = query.value(6);
    plot.name = query.value(1);
    for(var i = 0; i < items.length; i++) {
        if(items[i].roasted_id == query.value(0)) {
            items[i].plots.push(plot);
            break;
        }
    }
}
query = query.invalidate();
var buffer = new QBuffer;
buffer.open(3);
var output = new XmlWriter(buffer);
output.writeStartDocument("1.0");
output.writeDTD('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg.dtd">');
output.writeStartElement("html");
output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
output.writeStartElement("head");
output.writeTextElement("style", ".box {font: 10px sans-serif;} .whisker {font: 10px sans-serif;} .axis {font: 12px sans-serif;} .axis path {fill: none; stroke: #000; shape-rendering: crispEdges;} .axis line {fill: none; stroke: #000; shape-rendering: crispEdges;} .x.axis path {fill: none; stroke: #000; shape-rendering: crispEdges;}");
output.writeEndElement(); //head
output.writeStartElement("body");
var cdt = new Date(Date.now());
output.writeTextElement("p", cdt.toLocaleDateString(TTR("reports", "en-US")) + " " + cdt.toLocaleTimeString(TTR("reports", "en-US")));
function position(value, min, max) {
    return 300 - (((Number(value)-Number(min))/(Number(max)-Number(min)))*300);
}
for(var i = 0; i < items.length; i++) {
    output.writeStartElement("svg");
    output.writeAttribute("xmlns", "http://www.w3.org/2000/svg");
    output.writeAttribute("height", "420");
    output.writeAttribute("width", 84 + (items[i].plots.length * 179));
    output.writeStartElement("g"); //plots
    output.writeAttribute("transform", "translate(50,30)");
    var plotMin = items[i].min;
    var plotMax = items[i].max;
    for(var j = 0; j < items[i].plots.length; j++) {
        output.writeStartElement("g"); //plot
        output.writeAttribute("transform", "translate(" + (55 + (179 * j)).toString() + ",30)");
        output.writeStartElement("line"); //center line
        output.writeAttribute("class", "center");
        output.writeAttribute("style", "fill: #000; stroke: #000; stroke-width: 1px;");
        output.writeAttribute("x1", "27");
        output.writeAttribute("x2", "27");
        output.writeAttribute("y1", position(items[i].plots[j].min, plotMin, plotMax));
        output.writeAttribute("y2", position(items[i].plots[j].max, plotMin, plotMax));
        output.writeEndElement(); //line
        output.writeStartElement("rect"); //upper and lower quartiles box
        output.writeAttribute("class", "box");
        output.writeAttribute("style", "fill: #12DD11; stroke: #000; stroke-width: 1px;");
        output.writeAttribute("x", "0");
        output.writeAttribute("width", "54");
        output.writeAttribute("y", position(items[i].plots[j].upper_quart, plotMin, plotMax));
        output.writeAttribute("height", position(items[i].plots[j].lower_quart, plotMin, plotMax) - position(items[i].plots[j].upper_quart, plotMin, plotMax));
        output.writeEndElement(); //rect
        output.writeStartElement("line"); //median line
        output.writeAttribute("class", "median");
        output.writeAttribute("style", "fill: #12DD11; stroke: #000; stroke-width: 1px;");
        output.writeAttribute("x1", "0");
        output.writeAttribute("x2", "54");
        output.writeAttribute("y1", position(items[i].plots[j].median, plotMin, plotMax));
        output.writeAttribute("y2", position(items[i].plots[j].median, plotMin, plotMax));
        output.writeEndElement(); //line
        output.writeStartElement("line"); //minimum whisker
        output.writeAttribute("class", "whisker");
        output.writeAttribute("style", "fill: #12DD11; stroke: #000; stroke-width: 1px;");
        output.writeAttribute("x1", "0");
        output.writeAttribute("x2", "54");
        output.writeAttribute("y1", position(items[i].plots[j].min, plotMin, plotMax));
        output.writeAttribute("y2", position(items[i].plots[j].min, plotMin, plotMax));
        output.writeEndElement(); //line
        output.writeStartElement("line"); //maximum whisker
        output.writeAttribute("class", "whisker");
        output.writeAttribute("style", "fill: #12DD11; stroke: #000; stroke-width: 1px;");
        output.writeAttribute("x1", "0");
        output.writeAttribute("x2", "54");
        output.writeAttribute("y1", position(items[i].plots[j].max, plotMin, plotMax));
        output.writeAttribute("y2", position(items[i].plots[j].max, plotMin, plotMax));
        output.writeEndElement(); //line
        output.writeStartElement("text"); //upper quartile label
        output.writeAttribute("class", "box");
        output.writeAttribute("dy", ".3em");
        output.writeAttribute("dx", "-6");
        output.writeAttribute("x", "0");
        output.writeAttribute("y", position(items[i].plots[j].upper_quart, plotMin, plotMax));
        output.writeAttribute("text-anchor", "end");
        output.writeCharacters(Number(items[i].plots[j].upper_quart * 100).toFixed(2) + "%");
        output.writeEndElement(); //text
        output.writeStartElement("text"); //lower quartile label
        output.writeAttribute("class", "box");
        output.writeAttribute("dy", ".3em");
        output.writeAttribute("dx", "-6");
        output.writeAttribute("x", "0");
        output.writeAttribute("y", position(items[i].plots[j].lower_quart, plotMin, plotMax));
        output.writeAttribute("text-anchor", "end");
        output.writeCharacters(Number(items[i].plots[j].lower_quart * 100).toFixed(2) + "%");
        output.writeEndElement(); //text
        output.writeStartElement("text"); //median label
        output.writeAttribute("class", "box");
        output.writeAttribute("dy", ".3em");
        output.writeAttribute("dx", "6");
        output.writeAttribute("x", "54");
        output.writeAttribute("y", position(items[i].plots[j].median, plotMin, plotMax));
        output.writeAttribute("text-anchor", "start");
        output.writeCharacters(Number(items[i].plots[j].median * 100).toFixed(2) + "%");
        output.writeEndElement(); //text
        output.writeStartElement("text"); //minimum label
        output.writeAttribute("class", "whisker");
        output.writeAttribute("dy", ".3em");
        output.writeAttribute("dx", "6");
        output.writeAttribute("x", "54");
        output.writeAttribute("y", position(items[i].plots[j].min, plotMin, plotMax));
        output.writeAttribute("text-anchor", "start");
        output.writeCharacters(Number(items[i].plots[j].min * 100).toFixed(2) + "%");
        output.writeEndElement(); //text
        output.writeStartElement("text"); //maximum label
        output.writeAttribute("class", "whisker");
        output.writeAttribute("dy", ".3em");
        output.writeAttribute("dx", "6");
        output.writeAttribute("x", "54");
        output.writeAttribute("y", position(items[i].plots[j].max, plotMin, plotMax));
        output.writeAttribute("text-anchor", "start");
        output.writeCharacters(Number(items[i].plots[j].max * 100).toFixed(2) + "%");
        output.writeEndElement(); //text
        output.writeEndElement(); //g
    }
    output.writeStartElement("g"); //mean line and label
    output.writeAttribute("transform", "translate(0, 30)");
    output.writeStartElement("line");
    output.writeAttribute("class", "center");
    output.writeAttribute("style", "stroke: #000; stroke-width: 1px;");
    output.writeAttribute("x1", "0");
    output.writeAttribute("x2", (items[i].plots.length * 179) - 16);
    output.writeAttribute("y1", position(items[i].mean, plotMin, plotMax));
    output.writeAttribute("y2", position(items[i].mean, plotMin, plotMax));
    output.writeEndElement(); //line
    output.writeStartElement("text");
    output.writeAttribute("class", "box");
    output.writeAttribute("dy", ".3em");
    output.writeAttribute("dx", "-6");
    output.writeAttribute("x", "0");
    output.writeAttribute("y", position(items[i].mean, plotMin, plotMax));
    output.writeAttribute("text-anchor", "end");
    output.writeCharacters(Number(items[i].mean * 100).toFixed(2) + "%");
    output.writeEndElement(); //text
    output.writeEndElement(); //g
    output.writeStartElement("g") //x axis
    output.writeAttribute("class", "x axis");
    output.writeAttribute("transform", "translate(0,340)");
    for(var j = 0; j < items[i].plots.length; j++) {
        output.writeStartElement("g"); //name and population size
        output.writeAttribute("class", "tick");
        output.writeAttribute("transform", "translate(" + (82 + (j * 179)) + ",0)");
        output.writeStartElement("line"); //tick
        output.writeAttribute("y2", "6");
        output.writeAttribute("x2", "0");
        output.writeEndElement(); //line
        output.writeStartElement("text"); //label
        output.writeAttribute("style", "text-anchor: middle");
        output.writeAttribute("y", "9");
        output.writeAttribute("x", "0");
        output.writeStartElement("tspan");
        output.writeAttribute("x", "0");
        output.writeAttribute("dy", ".71em");
        output.writeCharacters(items[i].plots[j].name);
        output.writeEndElement(); //tspan
        output.writeStartElement("tspan");
        output.writeAttribute("x", "0");
        output.writeAttribute("dy", "1.42em");
        output.writeCharacters("(n=" + items[i].plots[j].count + ")");
        output.writeEndElement(); //tspan
        output.writeEndElement(); //text
        output.writeEndElement(); //g
    }
    output.writeStartElement("path");
    output.writeAttribute("class", "domain");
    output.writeAttribute("d", "M0,6V0H" + ((items[i].plots.length * 179) - 16) + "V6");
    output.writeEndElement(); //path
    output.writeEndElement(); //g
    output.writeStartElement("text") //chart title
    output.writeAttribute("x", (84 + (items[i].plots.length * 179))/2);
    output.writeAttribute("y", "15");
    output.writeAttribute("text-anchor", "middle");
    output.writeAttribute("style", "font-size: 18px;");
    output.writeCharacters(items[i].name);
    output.writeEndElement(); //text
    output.writeEndElement(); //g
    output.writeEndElement(); //svg
}
output.writeEndElement(); //body
output.writeEndElement(); //html
output.writeEndDocument();
report.setContent(buffer);
buffer.close();
        ]]>
    </program>
</window>