Commit 541b6a6a authored by Jérome Perrin's avatar Jérome Perrin

make a function for each widget

parent f48e95fa
...@@ -21,357 +21,195 @@ ...@@ -21,357 +21,195 @@
(function (scope, $, jsPlumb, console) { (function (scope, $, jsPlumb, console) {
"use strict"; "use strict";
scope.Dream = function (configuration) {
var that = jsonPlumb(),
priv = {};
that.initGeneralProperties = function () { function station_utilisation_graph_widget(input_data, output_data) {
var general_properties = {}; var blockage_data = [],
$.each(configuration["Dream-Configuration"].property_list, function ( waiting_data = [],
idx, element) { failure_data = [],
general_properties[element.id] = element._default; working_data = [],
}); ticks = [],
that.setGeneralProperties(general_properties); counter = 1;
};
priv.displayTool = function () { // XXX output is still elementList ???
var render_element = $("#tools-container"); $.each(output_data.elementList.sort(
$.each(configuration, function(key, val) { function(a,b) {return a.id < b.id ? -1 : 1}),
var name = val["name"] || key.split('-')[1]; function (idx, obj) {
if (key !== 'Dream-Configuration') { // add each object that has a working ratio
render_element.append('<div id="' + key + '" class="tool ' + key + '">' + if (obj.results !== undefined && obj.results.working_ratio !== undefined) {
name + "<ul/></div>"); /* when there is only one replication, the ratio is given as a float,
otherwise we have a mapping avg, ub lb */
var blockage_ratio = 0.0;
if (obj.results.blockage_ratio !== undefined) {
if (obj.results.blockage_ratio.avg !== undefined) {
blockage_ratio = obj.results.blockage_ratio.avg;
} else {
blockage_ratio = obj.results.blockage_ratio;
} }
}); }
}; blockage_data.push([counter, blockage_ratio]);
priv.initDialog = function () {
$("#dialog-form").dialog({
autoOpen: false
});
};
that.prepareDialogForGeneralProperties = function () { // XXX merge setup & loading ratio in working ratio for now
var fieldset = $("#general-fieldset"), var working_ratio = 0.0;
previous_data = that.getData()['general'], if (obj.results.setup_ratio !== undefined) {
previous_value = "", if (obj.results.setup_ratio.avg !== undefined) {
prefix = "General-"; working_ratio += obj.results.setup_ratio.avg;
fieldset.children().remove(); } else {
$.each(configuration['Dream-Configuration']['property_list'], working_ratio += obj.results.setup_ratio;
function (idx, property) {
if (property._class === "Dream.Property") {
previous_value = previous_data[property.id] || "";
if (previous_value.length > 0 || typeof previous_value == "number") {
previous_value = ' value="' + previous_value + '"';
} }
fieldset.append("<label>" + (property.name || property.id) + "</label>" +
'<input title="' + (property.description || '') + '" type="text" name="' + prefix + property.id + '"' +
previous_value + ' id="' + prefix + property.id + '"' +
' class="text ui-widget-content ui-corner-all"/>');
} }
}); if (obj.results.loading_ratio !== undefined) {
}; if (obj.results.loading_ratio.avg !== undefined) {
working_ratio += obj.results.loading_ratio.avg;
priv.prepareDialogForElement = function (title, element_id) { } else {
// code to allow changing values on connections. For now we assume working_ratio += obj.results.loading_ratio;
// that it is throughput. But we will need more generic code
//var throughput = $( "#throughput" ),
// allFields = $( [] ).add( throughput );
$(function () {
$("input[type=submit]")
.button()
.click(function (event) {
event.preventDefault();
});
});
// Render fields for that particular element
var fieldset = $("#dialog-fieldset");
var node_dict = that.getData()["nodes"];
var node_id = that.getNodeId(element_id);
$("#dialog-fieldset").children().remove();
var element_type = node_dict[node_id]._class.replace('.', '-');
var property_list = configuration[element_type].property_list || [];
fieldset.append(
'<label>ID</label><input type="text" name="id" id="id" value="' +
node_id + '" class="text ui-widget-content ui-corner-all"/>');
var element_name = node_dict[node_id]['name'] || node_id;
fieldset.append(
'<label>Name</label><input type="text" name="name" id="name" value="' +
element_name + '" class="text ui-widget-content ui-corner-all"/>');
var previous_data = node_dict[node_id] || {};
var previous_value;
var renderField = function (property_list, previous_data, prefix) {
if (prefix === undefined) {
prefix = "";
} }
$.each(property_list, function (key, property) {
if (property._class === "Dream.Property") {
if (!property.non_editable){
fieldset.append($("<label>").text(property.name || property.id));
var input = $("<input type='text'>")
if (property.choice) {
input = $("<select/>");
input.append("<option/>");
$.each(property.choice, function(idx, option) {
input.append($("<option/>").val(option[1]).text(option[0]));
});
} }
input.attr({ if (obj.results.working_ratio !== undefined) {
'name': prefix + property.id, if (obj.results.working_ratio.avg !== undefined) {
'title': (property.description || ''), working_ratio += obj.results.working_ratio.avg;
'id': prefix + property.id, } else {
'class': 'text ui-widget-content ui-corner-all', working_ratio += obj.results.working_ratio;
})
previous_value = previous_data[property.id];
input.val(previous_value);
fieldset.append(input);
} }
} else if (property._class === "Dream.PropertyList") {
var next_prefix = prefix + property.id + "-";
var next_previous_data = previous_data[property.id] || {};
renderField(property.property_list, next_previous_data,
next_prefix);
} }
}); working_data.push([counter, working_ratio]);
};
renderField(property_list, previous_data);
$("#dialog-form").dialog({ var waiting_ratio = 0.0;
autoOpen: false, if (obj.results.waiting_ratio !== undefined) {
width: 350, if (obj.results.waiting_ratio.avg !== undefined) {
modal: true, waiting_ratio = obj.results.waiting_ratio.avg;
title: node_dict[node_id]._class + " " + title || "", } else {
buttons: { waiting_ratio = obj.results.waiting_ratio;
Cancel: function () {
$(this).dialog("close");
},
Delete: function () {
if (confirm("Are you sure you want to delete " + node_id +
" ?")) {
that.removeElement(node_id);
}
$(this).dialog("close");
},
Validate: function () {
var new_id = $("#id").val();
if (new_id !== node_id && new_id in node_dict) {
alert('This ID is already used.');
return;
} }
var data = {}, prefixed_property_id, property_element;
var updateDataPropertyList = function (property_list, data,
prefix) {
if (prefix === undefined) {
prefix = "";
} }
waiting_data.push([counter, waiting_ratio]);
$.each(property_list, function (key, property) { var failure_ratio = 0.0;
if (property._class === "Dream.Property") { if (obj.results.failure_ratio !== undefined) {
prefixed_property_id = prefix + property.id; if (obj.results.failure_ratio.avg !== undefined) {
property_element = $("#" + prefixed_property_id); failure_ratio = obj.results.failure_ratio.avg;
data[property.id] = property_element.val(); } else {
if (property.type === "number" && data[property.id] !== "") { failure_ratio = obj.results.failure_ratio;
data[property.id] = parseFloat(data[property.id])
} }
} else if (property._class === "Dream.PropertyList") {
var next_prefix = prefix + property.id + "-";
data[property.id] = {};
updateDataPropertyList(property.property_list, data[
property.id], next_prefix);
} }
}); failure_data.push([counter, failure_ratio]);
};
updateDataPropertyList(property_list, data); ticks.push([counter, obj.id]);
that.updateElementData(node_id, { counter++;
data: data, }
name: $("#name").val() || node_id,
id: $("#id").val() || node_id
}); });
$(this).dialog("close"); var series = [{
} label: "Working",
data: working_data
}, {
label: "Waiting",
data: waiting_data
}, {
label: "Failures",
data: failure_data
}, {
label: "Blockage",
data: blockage_data
}];
var options = {
xaxis: {
minTickSize: 1,
ticks: ticks
}, },
close: function () { yaxis: {
//allFields.val( "" ).removeClass( "ui-state-error" ); max: 100
},
series: {
bars: {
show: true,
barWidth: 0.8,
align: "center"
},
stack: true
} }
}); };
$.plot("#graph", series, options);
}; };
priv.super_newElement = that.newElement; function queue_stat_widget(input_data, output_data) {
that.newElement = function (element) { /* FIXME: does not support more than one replic.
var element_type = element._class.replace('.', '-'); * + see george email to integrate without the need of an EG
element.element_id = that.generateElementId(); */
if (!element.id) { var queue_stat = $("#queue_stat");
element.id = that.generateNodeId(element_type, configuration[element_type]); var series = [];
$.each(output_data.elementList, function(idx, el){
if (el._class == 'Dream.Queue'){
series.push({label: el.name || el.id,
data: el.wip_stat_list})
} }
priv.super_newElement(element, configuration[element_type]); })
$("#" + element.element_id).on('dblclick', function () { $.plot("#queue_stat_graph", series);
$("#dialog-form").dialog("destroy");
priv.prepareDialogForElement(element.id, element.element_id);
$("#dialog-form").dialog("open");
});
// Store default values
var data = {}, property_list = configuration[element_type][
"property_list"
] || [];
var updateDefaultData = function (data, property_list) {
$.each(property_list, function (idx, value) {
if (value) {
if (element[value.id]) {
data[value.id] = element[value.id];
} else if (value._class === "Dream.Property") {
data[value.id] = value._default;
} else if (value._class === "Dream.PropertyList") {
data[value.id] = {};
var next_data = data[value.id];
var next_property_list = value.property_list || [];
updateDefaultData(next_data, next_property_list);
}
}
});
};
updateDefaultData(data, property_list);
var update_dict = {data: data}
if (element.name) {
update_dict["name"] = element.name;
}
that.updateElementData(element.id, update_dict);
};
priv.super_start = that.start;
that.start = function () {
priv.super_start();
priv.displayTool();
priv.initDialog();
that.initGeneralProperties();
that.prepareDialogForGeneralProperties();
};
that.readGeneralPropertiesDialog = function () {
// handle Dream.General properties
var prefix = "General-",
properties = {}, prefixed_property_id;
$.each(configuration['Dream-Configuration']['property_list'],
function (idx, property) {
if (property._class === "Dream.Property") {
prefixed_property_id = prefix + property.id;
properties[property.id] = $("#" + prefixed_property_id).val();
if (property.type === "number" && properties[property.id] !== "") {
properties[property.id] = parseFloat(properties[property.id])
}
}
});
that.setGeneralProperties(properties);
}
/** Runs the simulation, and call the callback with results once the
* simulation is finished.
*/
that.runSimulation = function (callback) {
that.readGeneralPropertiesDialog()
$.ajax(
'../runSimulation', {
data: JSON.stringify({
json: that.getData()
}),
contentType: 'application/json',
type: 'POST',
success: function (data, textStatus, jqXHR) {
callback(data);
}
});
};
/** Runs the knowledge extraction, and call the callback with results once the
* KE is finished.
*/
that.runKnowledgeExtraction = function (callback) {
that.readGeneralPropertiesDialog()
$.ajax(
'../runKnowledgeExtraction', {
data: JSON.stringify({
json: that.getData()
}),
contentType: 'application/json',
type: 'POST',
success: function (data, textStatus, jqXHR) {
callback(data);
} }
});
};
that.displayResult = function (idx) {
var active_tab = $("#reports").data("ui-tabs") ?
$("#reports").tabs("option", "active") : 0;
var result = JSON.parse($("#json_result").val())[idx]['result'];
$('li.result').removeClass('active'); function exit_stat_widget(input_data, output_data) {
$($('li.result')[idx]).addClass('active'); var exit_stat = $("#exit_stat").find('div').empty();
if ($("#reports").data("ui-tabs")) { $.each(output_data.elementList, function(idx, el){
$("#reports").tabs("destroy"); if (el._class == 'Dream.Exit'){
var text = exit_stat.html() + "<table><tr><th colspan='2'>" + (
el.name || el.id) + "</th></tr>";
$.each(el.results, function(metric, value){
if (metric == 'intervalThroughputList') {
var attainment_list = [],
general = that.getData().general,
throughputTarget = parseFloat(general.throughputTarget);
text += "<tr><td>Daily Attainment</td><td>"
$.each(value, function(i, intervalValue) {
var icon = "fa-frown-o";
attainment_list.push((intervalValue/throughputTarget));
if (intervalValue > throughputTarget) {
icon = "fa-smile-o"
} }
text += intervalValue + ' <i class="fa ' + icon + '"/><br/>';
})
text += "</td></tr>";
function showReport(report_id) { text += "<tr><td>Average Daily Line Attainment</td><td>" + (
$("li > a[href='#" + report_id + "']").parent().show(); (attainment_list.reduce(function(a, b){return a+b}) / attainment_list.length ) * 100).toFixed(2) + "%</td></tr>";
} else {
if (typeof value == "object") {
if (value.ub == value.lb) {
value = value.ub;
} else {
var ci_text = "<table width='100%'><tbody>"
ci_text += "<tr><td>Average</td><td>" + value.avg.toFixed(2) + "</td></tr>"
ci_text += "<tr><td>Lower Bound</td><td>" + value.lb.toFixed(2) + "</td></tr>"
ci_text += "<tr><td>Upper Bound</td><td>" + value.ub.toFixed(2) + "</td></tr>"
ci_text += "</tbody></table>"
value = ci_text;
} }
function hideReport(report_id) {
$("li > a[href='#" + report_id + "']").parent().hide();
} }
if (typeof value == "number") {
// XXX : use same name and make it a loop value = value.toFixed(2)
if (configuration['Dream-Configuration'].gui.debug_json){
showReport("debug_json")
} else {
hideReport("debug_json")
} }
if (configuration['Dream-Configuration'].gui.station_utilisation_graph){ // Rename some metric to something more meaningful
showReport("station_utilisation_graph") if (metric == "lifespan" ){
} else { metric = "Cycle Time"
hideReport("station_utilisation_graph")
} }
if (configuration['Dream-Configuration'].gui.job_schedule_spreadsheet){ if (metric == "takt_time" ){
showReport("job_schedule_spreadsheet") metric = "Average Departure Rate"
} else {
hideReport("job_schedule_spreadsheet")
} }
if (configuration['Dream-Configuration'].gui.job_gantt){ text += "<tr><td>" + metric + "</td><td>" + value + "</td></tr>";
showReport("job_gantt")
} else {
hideReport("job_gantt")
} }
if (configuration['Dream-Configuration'].gui.exit_stat){ })
showReport("exit_stat") exit_stat.html(text + "</table>");
} else {
hideReport("exit_stat")
} }
if (configuration['Dream-Configuration'].gui.queue_stat){ })
showReport("queue_stat")
} else {
hideReport("queue_stat")
} }
// temporary hack function job_schedule_spreadsheet_widget(input_data, output_data) {
// TODO: use the date specified in general input
var now = new Date(); var now = new Date();
// XXX why ?
now.setHours(0); now.setHours(0);
now.setMinutes(0); now.setMinutes(0);
now.setSeconds(0); now.setSeconds(0);
var blockage_data = [], var spreadsheet_data = [],
waiting_data = [],
failure_data = [],
working_data = [],
ticks = [],
counter = 1,
spreadsheet_data = [],
spreadsheet_header = [ spreadsheet_header = [
[ [
"Jobs", "Jobs",
...@@ -385,7 +223,98 @@ ...@@ -385,7 +223,98 @@
"Step No." "Step No."
] ]
], ],
start_date, simulation_start_date = new Date(input_data.general.currentDate || now.getTime());
// TODO: time unit for later
// or an utility function to map sim time to real time & vice
// versa.
$.each(output_data.elementList, function(idx, obj) {
if (obj._class === 'Dream.Job') {
var input_job, input_order, job_index = parseInt(obj["id"]);
// TODO: do not read spreadsheet, use input JSON to get data
// ... afterall why ?
input_job = input_data.wip_part_spreadsheet[job_index];
// If this line is an order component, find the order.
var i = job_index;
while (input_data.wip_part_spreadsheet[i][0] === null ||
input_data.wip_part_spreadsheet[i][0] === "") {
i = i-1;
}
input_order = input_data.wip_part_spreadsheet[i];
$.each(obj['results']['schedule'], function (i, schedule) {
var entrance_date = new Date(simulation_start_date.getTime() +
// TODO: time unit
schedule['entranceTime'] * 1000 * 3600);
spreadsheet_data.push([
input_order[0] + "-" + input_job[4],
obj['id'],
input_order[3], // operator
input_order[1], // dueDate
input_order[2], // priority
moment(entrance_date).format("MMM/DD HH:mm"),
input_job[7].split('-')[i] || 0, // processing time
schedule['stationId'],
i
]);
});
}
});
if (spreadsheet_data.length > 1) {
var job_schedule_spreadsheet = $('#job_schedule_spreadsheet');
// Sort the spreadsheet data to an order convenient for end users
// TODO: search for a default cmp in javascript
spreadsheet_data.sort( function(a, b) {
var result = 0,
order_id_a, order_id_b, entrance_a, entrance_b;
order_id_a = a[0].split('-')[0];
order_id_b = b[0].split('-')[0];
if (order_id_a !== order_id_b) {
if (order_id_a > order_id_b) {
result = 1;
} else {
result = -1;
}
} else {
entrance_a = a[4];
entrance_b = b[4];
if (entrance_a > entrance_b) {
result = 1;
} else if (entrance_a < entrance_b) {
result = -1;
} else {
result = 0;
}
}
return result;
});
job_schedule_spreadsheet.show();
job_schedule_spreadsheet.handsontable({
data: spreadsheet_header.concat(spreadsheet_data),
width: function () {
return $(window).width() -
job_schedule_spreadsheet.offset().left +
$(window).scrollLeft();
},
readOnly: true
});
job_schedule_spreadsheet.find('.htCore').width(job_schedule_spreadsheet.width());
}
}
function job_gantt_widget(input_data, output_data) {
// temporary hack
var now = new Date();
now.setHours(0);
now.setMinutes(0);
now.setSeconds(0);
var start_date,
gantt_data = { gantt_data = {
data: [ data: [
{ {
...@@ -408,94 +337,33 @@ ...@@ -408,94 +337,33 @@
link: [] link: []
}; };
start_date = that.getData().general.currentDate; start_date = input_data.general.currentDate;
if (start_date !== undefined && start_date !== "") { if (start_date !== undefined && start_date !== "") {
start_date = new Date(start_date); start_date = new Date(start_date);
} else { } else {
start_date = new Date(now.getTime()) start_date = new Date(now.getTime())
} }
$.each(result.elementList.sort(function(a,b) {return a.id < b.id ? -1 : 1}), $.each(output_data.elementList.sort(function(a,b) {return a.id < b.id ? -1 : 1}),
function (idx, obj) { function (idx, obj) {
if (obj.results !== undefined && obj.results.working_ratio !== undefined) {
/* when there is only one replication, the ratio is given as a float,
otherwise we have a mapping avg, ub lb */
var blockage_ratio = 0.0;
if (obj.results.blockage_ratio !== undefined) {
if (obj.results.blockage_ratio.avg !== undefined) {
blockage_ratio = obj.results.blockage_ratio.avg;
} else {
blockage_ratio = obj.results.blockage_ratio;
}
}
blockage_data.push([counter, blockage_ratio]);
// XXX merge setup & loading ratio in working ratio for now
var working_ratio = 0.0;
if (obj.results.setup_ratio !== undefined) {
if (obj.results.setup_ratio.avg !== undefined) {
working_ratio += obj.results.setup_ratio.avg;
} else {
working_ratio += obj.results.setup_ratio;
}
}
if (obj.results.loading_ratio !== undefined) {
if (obj.results.loading_ratio.avg !== undefined) {
working_ratio += obj.results.loading_ratio.avg;
} else {
working_ratio += obj.results.loading_ratio;
}
}
if (obj.results.working_ratio !== undefined) {
if (obj.results.working_ratio.avg !== undefined) {
working_ratio += obj.results.working_ratio.avg;
} else {
working_ratio += obj.results.working_ratio;
}
}
working_data.push([counter, working_ratio]);
var waiting_ratio = 0.0;
if (obj.results.waiting_ratio !== undefined) {
if (obj.results.waiting_ratio.avg !== undefined) {
waiting_ratio = obj.results.waiting_ratio.avg;
} else {
waiting_ratio = obj.results.waiting_ratio;
}
}
waiting_data.push([counter, waiting_ratio]);
var failure_ratio = 0.0;
if (obj.results.failure_ratio !== undefined) {
if (obj.results.failure_ratio.avg !== undefined) {
failure_ratio = obj.results.failure_ratio.avg;
} else {
failure_ratio = obj.results.failure_ratio;
}
}
failure_data.push([counter, failure_ratio]);
ticks.push([counter, obj.id]);
counter++;
}
var isVisibleStation = function (station) { var isVisibleStation = function (station) {
// we should be able to define in the backend which station is visible // we should be able to define in the backend which station is visible
return that.getData().nodes[station]._class != "Dream.QueueManagedJob"; return input_data.nodes[station]._class != "Dream.QueueManagedJob";
}; };
if (obj._class === 'Dream.Job') { if (obj._class === 'Dream.Job') {
// find the corresponding input // find the corresponding input
var data = that.getData(), var input_job, input_order;
input_job, input_order;
var job_index = parseInt(obj["id"]); var job_index = parseInt(obj["id"]);
// TODO: do not read spreadsheet, use input JSON to get data // TODO: do not read spreadsheet, use input JSON to get data
input_job = data.wip_part_spreadsheet[job_index]; input_job = input_data.wip_part_spreadsheet[job_index];
var i = job_index; var i = job_index;
while (data.wip_part_spreadsheet[i][0] === null || data.wip_part_spreadsheet[i][0] === "") { while (input_data.wip_part_spreadsheet[i][0] === null ||
input_data.wip_part_spreadsheet[i][0] === "") {
i = i-1; i = i-1;
} }
input_order = data.wip_part_spreadsheet[i]; input_order = input_data.wip_part_spreadsheet[i];
var duration = 0; var duration = 0;
if (input_job == input_order) { // if we are on the order definition if (input_job == input_order) { // if we are on the order definition
...@@ -514,17 +382,6 @@ ...@@ -514,17 +382,6 @@
if (isVisibleStation(schedule['stationId'])) { if (isVisibleStation(schedule['stationId'])) {
var entrance_date = new Date(start_date.getTime()); var entrance_date = new Date(start_date.getTime());
entrance_date.setTime(entrance_date.getTime() + schedule['entranceTime']*1000*3600); entrance_date.setTime(entrance_date.getTime() + schedule['entranceTime']*1000*3600);
spreadsheet_data.push([
input_order[0] + "-" + input_job[4],
obj['id'],
input_order[3], // operator
input_order[1], // dueDate
input_order[2], // priority
moment(entrance_date).format("MMM/DD HH:mm"),
input_job[7].split('-')[i] || 0, // processing time
schedule['stationId'],
i
]);
if (obj['results']['schedule'][i + 1]) { if (obj['results']['schedule'][i + 1]) {
duration = obj['results']['schedule'][i + 1]['entranceTime'] - schedule['entranceTime']; duration = obj['results']['schedule'][i + 1]['entranceTime'] - schedule['entranceTime'];
} else { } else {
...@@ -562,214 +419,408 @@ ...@@ -562,214 +419,408 @@
} }
} }
}); });
} else { } else {
if (isVisibleStation(obj['id'])) { if (isVisibleStation(obj['id'])) {
gantt_data.data.push({ gantt_data.data.push({
id: obj['id'], id: obj['id'],
text: obj['id'], text: obj['id'],
project: 1, project: 1,
open: false, open: false,
parent: "by_station" parent: "by_station"
}); });
};
}
});
gantt.templates.task_class = function (start, end, obj) {
return obj.parent ? "sub_task" : "";
};
try {
gantt.clearAll();
} catch (e) {}
var gantt_output_height = 35 * (gantt_data.data.length + 1) + 1;
gantt_data.data.sort(function (a, b) {
// sort gantt data in a chronological order
var result;
if (a.start_date === undefined && b.start_date !== undefined) {
result = 1;
} else if (a.start_date !== undefined && b.start_date === undefined) {
result = - 1;
} else if (a.start_date === undefined && b.start_date === undefined) {
result = 0;
} else if (a.start_date > b.start_date) {
result = 1;
} else if (a.start_date < b.start_date) {
result = -1;
} else {
result = 0;
}
return result;
});
$('#job_gantt').show().dhx_gantt({
data: gantt_data,
readonly: true,
/* for days has simulation time unit
scale_unit: 'day',
step: 7
*/
// for hours has simulation time unit
scale_unit: 'day',
duration_unit: 60*60*1000,
//date_grid: "%H:%i",
date_scale: "%M/%d",
step: 1,
subscales: [{unit:"hour", step:4, date:"%H:%i" }]
});
}
scope.Dream = function (configuration) {
var that = jsonPlumb(),
priv = {};
that.initGeneralProperties = function () {
var general_properties = {};
$.each(configuration["Dream-Configuration"].property_list, function (
idx, element) {
general_properties[element.id] = element._default;
});
that.setGeneralProperties(general_properties);
};
priv.displayTool = function () {
var render_element = $("#tools-container");
$.each(configuration, function(key, val) {
var name = val["name"] || key.split('-')[1];
if (key !== 'Dream-Configuration') {
render_element.append('<div id="' + key + '" class="tool ' + key + '">' +
name + "<ul/></div>");
}
});
};
priv.initDialog = function () {
$("#dialog-form").dialog({
autoOpen: false
});
};
that.prepareDialogForGeneralProperties = function () {
var fieldset = $("#general-fieldset"),
previous_data = that.getData()['general'],
previous_value = "",
prefix = "General-";
fieldset.children().remove();
$.each(configuration['Dream-Configuration']['property_list'],
function (idx, property) {
if (property._class === "Dream.Property") {
previous_value = previous_data[property.id] || "";
if (previous_value.length > 0 || typeof previous_value == "number") {
previous_value = ' value="' + previous_value + '"';
}
fieldset.append("<label>" + (property.name || property.id) + "</label>" +
'<input title="' + (property.description || '') + '" type="text" name="' + prefix + property.id + '"' +
previous_value + ' id="' + prefix + property.id + '"' +
' class="text ui-widget-content ui-corner-all"/>');
}
});
};
priv.prepareDialogForElement = function (title, element_id) {
// code to allow changing values on connections. For now we assume
// that it is throughput. But we will need more generic code
//var throughput = $( "#throughput" ),
// allFields = $( [] ).add( throughput );
$(function () {
$("input[type=submit]")
.button()
.click(function (event) {
event.preventDefault();
});
});
// Render fields for that particular element
var fieldset = $("#dialog-fieldset");
var node_dict = that.getData()["nodes"];
var node_id = that.getNodeId(element_id);
$("#dialog-fieldset").children().remove();
var element_type = node_dict[node_id]._class.replace('.', '-');
var property_list = configuration[element_type].property_list || [];
fieldset.append(
'<label>ID</label><input type="text" name="id" id="id" value="' +
node_id + '" class="text ui-widget-content ui-corner-all"/>');
var element_name = node_dict[node_id]['name'] || node_id;
fieldset.append(
'<label>Name</label><input type="text" name="name" id="name" value="' +
element_name + '" class="text ui-widget-content ui-corner-all"/>');
var previous_data = node_dict[node_id] || {};
var previous_value;
var renderField = function (property_list, previous_data, prefix) {
if (prefix === undefined) {
prefix = "";
}
$.each(property_list, function (key, property) {
if (property._class === "Dream.Property") {
if (!property.non_editable){
fieldset.append($("<label>").text(property.name || property.id));
var input = $("<input type='text'>")
if (property.choice) {
input = $("<select/>");
input.append("<option/>");
$.each(property.choice, function(idx, option) {
input.append($("<option/>").val(option[1]).text(option[0]));
});
}
input.attr({
'name': prefix + property.id,
'title': (property.description || ''),
'id': prefix + property.id,
'class': 'text ui-widget-content ui-corner-all',
})
previous_value = previous_data[property.id];
input.val(previous_value);
fieldset.append(input);
}
} else if (property._class === "Dream.PropertyList") {
var next_prefix = prefix + property.id + "-";
var next_previous_data = previous_data[property.id] || {};
renderField(property.property_list, next_previous_data,
next_prefix);
}
});
};
renderField(property_list, previous_data);
$("#dialog-form").dialog({
autoOpen: false,
width: 350,
modal: true,
title: node_dict[node_id]._class + " " + title || "",
buttons: {
Cancel: function () {
$(this).dialog("close");
},
Delete: function () {
if (confirm("Are you sure you want to delete " + node_id +
" ?")) {
that.removeElement(node_id);
}
$(this).dialog("close");
},
Validate: function () {
var new_id = $("#id").val();
if (new_id !== node_id && new_id in node_dict) {
alert('This ID is already used.');
return;
}
var data = {}, prefixed_property_id, property_element;
var updateDataPropertyList = function (property_list, data,
prefix) {
if (prefix === undefined) {
prefix = "";
}
$.each(property_list, function (key, property) {
if (property._class === "Dream.Property") {
prefixed_property_id = prefix + property.id;
property_element = $("#" + prefixed_property_id);
data[property.id] = property_element.val();
if (property.type === "number" && data[property.id] !== "") {
data[property.id] = parseFloat(data[property.id])
}
} else if (property._class === "Dream.PropertyList") {
var next_prefix = prefix + property.id + "-";
data[property.id] = {};
updateDataPropertyList(property.property_list, data[
property.id], next_prefix);
}
});
};
updateDataPropertyList(property_list, data);
that.updateElementData(node_id, {
data: data,
name: $("#name").val() || node_id,
id: $("#id").val() || node_id
});
$(this).dialog("close");
}
},
close: function () {
//allFields.val( "" ).removeClass( "ui-state-error" );
}
});
};
priv.super_newElement = that.newElement;
that.newElement = function (element) {
var element_type = element._class.replace('.', '-');
element.element_id = that.generateElementId();
if (!element.id) {
element.id = that.generateNodeId(element_type, configuration[element_type]);
}
priv.super_newElement(element, configuration[element_type]);
$("#" + element.element_id).on('dblclick', function () {
$("#dialog-form").dialog("destroy");
priv.prepareDialogForElement(element.id, element.element_id);
$("#dialog-form").dialog("open");
});
// Store default values
var data = {}, property_list = configuration[element_type][
"property_list"
] || [];
var updateDefaultData = function (data, property_list) {
$.each(property_list, function (idx, value) {
if (value) {
if (element[value.id]) {
data[value.id] = element[value.id];
} else if (value._class === "Dream.Property") {
data[value.id] = value._default;
} else if (value._class === "Dream.PropertyList") {
data[value.id] = {};
var next_data = data[value.id];
var next_property_list = value.property_list || [];
updateDefaultData(next_data, next_property_list);
}
}
});
}; };
updateDefaultData(data, property_list);
var update_dict = {data: data}
if (element.name) {
update_dict["name"] = element.name;
} }
}); that.updateElementData(element.id, update_dict);
};
var series = [{ priv.super_start = that.start;
label: "Working", that.start = function () {
data: working_data priv.super_start();
}, { priv.displayTool();
label: "Waiting", priv.initDialog();
data: waiting_data that.initGeneralProperties();
}, { that.prepareDialogForGeneralProperties();
label: "Failures", };
data: failure_data
}, {
label: "Blockage",
data: blockage_data
}];
var options = { that.readGeneralPropertiesDialog = function () {
xaxis: { // handle Dream.General properties
minTickSize: 1, var prefix = "General-",
ticks: ticks properties = {}, prefixed_property_id;
},
yaxis: { $.each(configuration['Dream-Configuration']['property_list'],
max: 100 function (idx, property) {
}, if (property._class === "Dream.Property") {
series: { prefixed_property_id = prefix + property.id;
bars: { properties[property.id] = $("#" + prefixed_property_id).val();
show: true, if (property.type === "number" && properties[property.id] !== "") {
barWidth: 0.8, properties[property.id] = parseFloat(properties[property.id])
align: "center"
},
stack: true
} }
}; }
if (configuration['Dream-Configuration'].gui.station_utilisation_graph){ });
// XXX no need to prepare data that.setGeneralProperties(properties);
$.plot("#graph", series, options);
} }
if (configuration['Dream-Configuration'].gui.queue_stat){ /** Runs the simulation, and call the callback with results once the
var queue_stat = $("#queue_stat"); * simulation is finished.
var series = []; */
$.each(result.elementList, function(idx, el){ that.runSimulation = function (callback) {
if (el._class == 'Dream.Queue'){ that.readGeneralPropertiesDialog()
series.push({label: el.name || el.id, $.ajax(
data: el.wip_stat_list}) '../runSimulation', {
data: JSON.stringify({
json: that.getData()
}),
contentType: 'application/json',
type: 'POST',
success: function (data, textStatus, jqXHR) {
callback(data);
} }
}) });
$.plot("#queue_stat_graph", series); };
/** Runs the knowledge extraction, and call the callback with results once the
* KE is finished.
*/
that.runKnowledgeExtraction = function (callback) {
that.readGeneralPropertiesDialog()
$.ajax(
'../runKnowledgeExtraction', {
data: JSON.stringify({
json: that.getData()
}),
contentType: 'application/json',
type: 'POST',
success: function (data, textStatus, jqXHR) {
callback(data);
} }
});
};
if (configuration['Dream-Configuration'].gui.exit_stat){ that.displayResult = function (idx) {
var exit_stat = $("#exit_stat").find('div').empty(); var active_tab = $("#reports").data("ui-tabs") ?
$.each(result.elementList, function(idx, el){ $("#reports").tabs("option", "active") : 0; // XXX should not be 0, but the first enabled one
if (el._class == 'Dream.Exit'){ var result = JSON.parse($("#json_result").val())[idx]['result'];
var text = exit_stat.html() + "<table><tr><th colspan='2'>" + (
el.name || el.id) + "</th></tr>"; $('li.result').removeClass('active');
$.each(el.results, function(metric, value){ $($('li.result')[idx]).addClass('active');
if (metric == 'intervalThroughputList') { if ($("#reports").data("ui-tabs")) {
var attainment_list = [], $("#reports").tabs("destroy");
general = that.getData().general,
throughputTarget = parseFloat(general.throughputTarget);
text += "<tr><td>Daily Attainment</td><td>"
$.each(value, function(i, intervalValue) {
var icon = "fa-frown-o";
attainment_list.push((intervalValue/throughputTarget));
if (intervalValue > throughputTarget) {
icon = "fa-smile-o"
} }
text += intervalValue + ' <i class="fa ' + icon + '"/><br/>';
})
text += "</td></tr>";
text += "<tr><td>Average Daily Line Attainment</td><td>" + ( var available_widget_list = [
(attainment_list.reduce(function(a, b){return a+b}) / attainment_list.length ) * 100).toFixed(2) + "%</td></tr>"; 'debug_json',
} else { 'station_utilisation_graph',
if (typeof value == "object") { 'job_schedule_spreadsheet',
if (value.ub == value.lb) { 'job_gantt',
value = value.ub; 'exit_stat',
'queue_stat',
];
for (var i in available_widget_list) {
var widget_name = available_widget_list[i];
if (configuration['Dream-Configuration'].gui[widget_name]) {
$("li > a[href='#" + widget_name + "']").parent().show();
} else { } else {
var ci_text = "<table width='100%'><tbody>" $("li > a[href='#" + widget_name + "']").parent().hide();
ci_text += "<tr><td>Average</td><td>" + value.avg.toFixed(2) + "</td></tr>"
ci_text += "<tr><td>Lower Bound</td><td>" + value.lb.toFixed(2) + "</td></tr>"
ci_text += "<tr><td>Upper Bound</td><td>" + value.ub.toFixed(2) + "</td></tr>"
ci_text += "</tbody></table>"
value = ci_text;
}
}
if (typeof value == "number") {
value = value.toFixed(2)
}
// Rename some metric to something more meaningful
if (metric == "lifespan" ){
metric = "Cycle Time"
}
if (metric == "takt_time" ){
metric = "Average Departure Rate"
}
text += "<tr><td>" + metric + "</td><td>" + value + "</td></tr>";
} }
})
exit_stat.html(text + "</table>");
}
})
} }
if (spreadsheet_data.length > 1) { var input = that.getData(); // XXX how to get input json ?
var job_schedule_spreadsheet = $('#job_schedule_spreadsheet');
// Sort the spreadsheet data to an order convenient for end users // display each of the enabled widget
spreadsheet_data.sort( function(a, b) { if (configuration['Dream-Configuration'].gui.station_utilisation_graph){
var result = 0, station_utilisation_graph_widget(input, result);
order_id_a, order_id_b, entrance_a, entrance_b;
order_id_a = a[0].split('-')[0];
order_id_b = b[0].split('-')[0];
if (order_id_a !== order_id_b) {
if (order_id_a > order_id_b) {
result = 1;
} else {
result = -1;
} }
} else { if (configuration['Dream-Configuration'].gui.queue_stat){
entrance_a = a[4]; queue_stat_widget(input, result);
entrance_b = b[4];
if (entrance_a > entrance_b) {
result = 1;
} else if (entrance_a < entrance_b) {
result = -1;
} else {
result = 0;
} }
if (configuration['Dream-Configuration'].gui.exit_stat){
exit_stat_widget(input, result);
} }
return result;
});
if (configuration['Dream-Configuration'].gui.job_schedule_spreadsheet){ if (configuration['Dream-Configuration'].gui.job_schedule_spreadsheet){
job_schedule_spreadsheet.show(); job_schedule_spreadsheet_widget(input, result);
job_schedule_spreadsheet.handsontable({
data: spreadsheet_header.concat(spreadsheet_data),
width: function () {
return $(window).width() -
job_schedule_spreadsheet.offset().left +
$(window).scrollLeft();
},
readOnly: true
});
job_schedule_spreadsheet.find('.htCore').width(job_schedule_spreadsheet.width());
}
gantt.templates.task_class = function (start, end, obj) {
return obj.parent ? "sub_task" : "";
};
try {
gantt.clearAll();
} catch (e) {}
var gantt_output_height = 35 * (gantt_data.data.length + 1) + 1;
gantt_data.data.sort(function (a, b) {
// sort gantt data in a chronological order
var result;
if (a.start_date === undefined && b.start_date !== undefined) {
result = 1;
} else if (a.start_date !== undefined && b.start_date === undefined) {
result = - 1;
} else if (a.start_date === undefined && b.start_date === undefined) {
result = 0;
} else if (a.start_date > b.start_date) {
result = 1;
} else if (a.start_date < b.start_date) {
result = -1;
} else {
result = 0;
} }
return result;
});
if (configuration['Dream-Configuration'].gui.job_gantt){ if (configuration['Dream-Configuration'].gui.job_gantt){
$('#job_gantt').show().dhx_gantt({ job_gantt_widget(input, result);
data: gantt_data,
readonly: true,
/* for days has simulation time unit
scale_unit: 'day',
step: 7
*/
// for hours has simulation time unit
scale_unit: 'day',
duration_unit: 60*60*1000,
//date_grid: "%H:%i",
date_scale: "%M/%d",
step: 1,
subscales: [{unit:"hour", step:4, date:"%H:%i" }]
});
//$('#gantt_grid').width(1000);
} }
}
// make the tabs full width // hack: make the tabs full width
$("#reports li").width((100/$("#reports li:visible").length) - 1 +'%'); $("#reports li").width((100/$("#reports li:visible").length) - 1 +'%');
$("#reports li a").width('100%').css({'text-align': 'left'}); $("#reports li a").width('100%').css({'text-align': 'left'});
$("#reports").show().tabs({ active: active_tab }); $("#reports").show().tabs({ active: active_tab });
}; }
return that; return that;
}; };
}(window, jQuery, jsPlumb, console)); }(window, jQuery, jsPlumb, console));
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment