Browse Source

added showcase

gh-pages
Alex de Mulder 10 years ago
parent
commit
5ed75fb9eb
38 changed files with 70307 additions and 57 deletions
  1. +12
    -4
      featureRequests.html
  2. +1
    -0
      graph2d_examples.html
  3. +1
    -0
      graph3d_examples.html
  4. +3
    -6
      index.html
  5. +1
    -0
      network_examples.html
  6. +0
    -47
      showcase.html
  7. BIN
      showcase/images/midas.png
  8. +93
    -0
      showcase/index.html
  9. +216
    -0
      showcase/projects/midas/arumAgents/agentGenerator.js
  10. +40
    -0
      showcase/projects/midas/arumAgents/durationData.js
  11. +142
    -0
      showcase/projects/midas/arumAgents/durationStats.js
  12. +2037
    -0
      showcase/projects/midas/arumAgents/eventGenerator.js
  13. +85
    -0
      showcase/projects/midas/arumAgents/genericAgent.js
  14. +116
    -0
      showcase/projects/midas/arumAgents/job.js
  15. +434
    -0
      showcase/projects/midas/arumAgents/jobAgent.js
  16. +169
    -0
      showcase/projects/midas/arumAgents/jobAgentGenerator.js
  17. +428
    -0
      showcase/projects/midas/arumAgents/jobManager.js
  18. +301
    -0
      showcase/projects/midas/css/global.css
  19. +745
    -0
      showcase/projects/midas/css/vis.css
  20. BIN
      showcase/projects/midas/images/arum.png
  21. BIN
      showcase/projects/midas/images/arum_small.png
  22. BIN
      showcase/projects/midas/images/control_pause.png
  23. BIN
      showcase/projects/midas/images/control_pause_blue.png
  24. BIN
      showcase/projects/midas/images/control_play.png
  25. BIN
      showcase/projects/midas/images/control_play_blue.png
  26. BIN
      showcase/projects/midas/images/midas_big.png
  27. BIN
      showcase/projects/midas/images/midas_small.png
  28. BIN
      showcase/projects/midas/images/moon.png
  29. BIN
      showcase/projects/midas/images/shaded.png
  30. BIN
      showcase/projects/midas/images/sun.png
  31. BIN
      showcase/projects/midas/images/toggleOff.png
  32. BIN
      showcase/projects/midas/images/toggleOn.png
  33. +86
    -0
      showcase/projects/midas/index.html
  34. +31161
    -0
      showcase/projects/midas/js/evejs.js
  35. +350
    -0
      showcase/projects/midas/js/init.js
  36. +33780
    -0
      showcase/projects/midas/js/vis.js
  37. +105
    -0
      showcase/projects/midas/js/vis_eve_init.js
  38. +1
    -0
      timeline_examples.html

+ 12
- 4
featureRequests.html View File

@ -20,6 +20,7 @@
<style> <style>
body { body {
padding:10px; padding:10px;
font-family: Lustria,Georgia,Times,"Times New Roman",serif !important;
} }
div.textHTMLContent { div.textHTMLContent {
@ -55,8 +56,16 @@
</head> </head>
<body> <body>
<h1>Feature requests</h1> <h1>Feature requests</h1>
<hr class="featurette-divider">
<div class="textHTMLContent"> <div class="textHTMLContent">
<h4>We get a lot of feature requests, here's the list of them!</h4>
<p class="text-justify">
The requests that come in on Github usually have a good argumentation and a lot of these ideas have made it into vis! To keep a nice overview of them, to clean up
our Github issues and to supply a pool of ideas for people to contribute, we have made this list.
<br /><br />
This is by no means an end-of-the-line for your feature, but just something that we cannot pick up right away or cannot use in our projects at this time.
We'd like to invite people who want to contribute to pick up one (or more!) of these features.
</p>
Legend: Legend:
<ul> <ul>
<li class="blue">Feature being worked on by us.</li> <li class="blue">Feature being worked on by us.</li>
@ -66,8 +75,7 @@ Legend:
<li class="orange">Feature needing major overhauling of the current framework, not planned soon and unlikely to be picked up by community.</li> <li class="orange">Feature needing major overhauling of the current framework, not planned soon and unlikely to be picked up by community.</li>
</ul> </ul>
</div> </div>
<hr class="featurette-divider">
<h3 id="all">All</h3> <h3 id="all">All</h3>
<ul> <ul>
<li class="normal">(<a href="https://github.com/almende/vis/issues/308" target="_blank">308</a>) Add a click-to-scroll option similar to click-to-use but it should allow dragging all the time, only block the scrolling without activating it.</li> <li class="normal">(<a href="https://github.com/almende/vis/issues/308" target="_blank">308</a>) Add a click-to-scroll option similar to click-to-use but it should allow dragging all the time, only block the scrolling without activating it.</li>
@ -124,7 +132,7 @@ Legend:
<ul> <ul>
<li class="normal">(<a href="https://github.com/almende/vis/issues/516" target="_blank">516</a>) Stacking of line graphs similar to how the bar charts can be stacked.</li> <li class="normal">(<a href="https://github.com/almende/vis/issues/516" target="_blank">516</a>) Stacking of line graphs similar to how the bar charts can be stacked.</li>
<li class="normal">(<a href="https://github.com/almende/vis/issues/500" target="_blank">500</a>) Adding a group visibility in legends.</li> <li class="normal">(<a href="https://github.com/almende/vis/issues/500" target="_blank">500</a>) Adding a group visibility in legends.</li>
<li class="normal">(<a href="https://github.com/almende/vis/issues/388" target="_blank">388</a>, <a href="https://github.com/almende/vis/issues/311" target="_blank">311</a>, <a href="https://github.com/almende/vis/issues/282" target="_blank">282</a>) ToolTips: this should give a stylable tooltip with the value at the position of the cursor. Options should include: <ul><li class="normal"><strong>snapToDatapoint</strong> (only show tooltips on datapoints, if off, show interpolated value at position)</li><li class="normal"> <strong>alwaysOn</strong> (always show tooltips on datapoints, perhaps with an optional tag that you can specify here?)</li>
<li class="normal">(<a href="https://github.com/almende/vis/issues/388" target="_blank">388</a>, <a href="https://github.com/almende/vis/issues/311" target="_blank">311</a>, <a href="https://github.com/almende/vis/issues/282" target="_blank">282</a>) ToolTips: this should give a stylable tooltip with the value at the position of the cursor. Options should include: <ul><li class="normal"><strong>snapToDatapoint</strong> (only show tooltips on datapoints, if off, show interpolated value at position)</li><li class="normal"> <strong>alwaysOn</strong> (always show tooltips on datapoints, perhaps with an optional tag that you can specify here?)</li></ul>
<li class="normal">(<a href="https://github.com/almende/vis/issues/354" target="_blank">354</a>) Add uncertainty plot styles (box, candle, shaded area, etc.)</li> <li class="normal">(<a href="https://github.com/almende/vis/issues/354" target="_blank">354</a>) Add uncertainty plot styles (box, candle, shaded area, etc.)</li>
<li class="normal">(<a href="https://github.com/almende/vis/issues/314" target="_blank">314</a>) Logarithmic scale (y-axis initially, if numeric range for x-axis is implemented, could be ported over to x-axis as well).</li> <li class="normal">(<a href="https://github.com/almende/vis/issues/314" target="_blank">314</a>) Logarithmic scale (y-axis initially, if numeric range for x-axis is implemented, could be ported over to x-axis as well).</li>
</ul> </ul>

+ 1
- 0
graph2d_examples.html View File

@ -24,6 +24,7 @@
<style> <style>
body { body {
padding:10px; padding:10px;
font-family: Lustria,Georgia,Times,"Times New Roman",serif !important;
} }
pre { pre {

+ 1
- 0
graph3d_examples.html View File

@ -24,6 +24,7 @@
<style> <style>
body { body {
padding:10px; padding:10px;
font-family: Lustria,Georgia,Times,"Times New Roman",serif !important;
} }
pre { pre {

+ 3
- 6
index.html View File

@ -18,11 +18,8 @@
<![endif]--> <![endif]-->
<style> <style>
#forkme {
position:absolute;
top:0px;
right:0px;
z-index:9000;
body {
font-family: Lustria,Georgia,Times,"Times New Roman",serif !important;
} }
img.icon { img.icon {
@ -201,7 +198,7 @@
<div class="valign_parent"> <div class="valign_parent">
<div class="valign_child"> <div class="valign_child">
<h2 class="featurette-heading">Showcase; <span class="text-muted">see vis in action!</span></h2> <h2 class="featurette-heading">Showcase; <span class="text-muted">see vis in action!</span></h2>
<p class="lead"><a href="showcase.html">
<p class="lead"><a href="./showcase/index.html">
In this section you can see cool projects that vis was used in.</a> If you have made something and would like it featured, In this section you can see cool projects that vis was used in.</a> If you have made something and would like it featured,
please make an <a href="https://github.com/almende/vis/issues" target="_blank">issue on github</a> with your project and how you'd like to be credited.</p> please make an <a href="https://github.com/almende/vis/issues" target="_blank">issue on github</a> with your project and how you'd like to be credited.</p>
</div> </div>

+ 1
- 0
network_examples.html View File

@ -23,6 +23,7 @@
<style> <style>
body { body {
padding:10px; padding:10px;
font-family: Lustria,Georgia,Times,"Times New Roman",serif !important;
} }
pre { pre {

+ 0
- 47
showcase.html View File

@ -1,47 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Feature Requests</title>
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<style>
body {
padding:10px;
}
div.textHTMLContent {
display:block;
width:800px;
}
</style>
</head>
<body>
<h1>Showcase projects</h1>
<div class="textHTMLContent">
- MIDAS
- Git
- Cool examples (?)
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
</body>
</html>

BIN
showcase/images/midas.png View File

Before After
Width: 900  |  Height: 400  |  Size: 124 KiB

+ 93
- 0
showcase/index.html View File

@ -0,0 +1,93 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Feature Requests</title>
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<style>
a {
text-decoration: none;
}
body {
padding:10px;
font-family: Lustria,Georgia,Times,"Times New Roman",serif !important;
}
div.textHTMLContent {
display:block;
width:970px;
}
img.showcase {
position:relative;
border: 1px solid #dddddd;
border-radius:20px;
width:900px;
height:350px;
}
div.description{
width:880px;
position:relative;
border-radius:20px;
padding:20px;
text-decoration: none;
color:#ffffff;
background-color:#064880;
margin-top:-80px;
margin-left:20px;
z-index:2;
box-shadow: 0px 0px 8px #000000;
}
div.descriptionHeader {
font-size:25px;
font-weight:bold;
padding-bottom:5px;
}
</style>
</head>
<body>
<h1>Showcase projects</h1>
<div class="textHTMLContent">
<a href="./projects/midas/index.html">
<div class="showcase">
<img src="./images/midas.png" class="showcase">
<div class="description">
<div class="descriptionHeader">
M.I.D.A.S. : Manufacturing Incident Detection Agent Solution
</div>
<div class="descriptionContent">
MIDAS collects statistics of incidents during the production process.
It analyses the manufacturing process and handles disruptive events during the ramp-up phase.
Almende developed the software tool especially for this project, based on the inhouse toolchain,
specifically Eve, AIM and vis.js.
</div>
</div>
</div>
</a>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
</body>
</html>

+ 216
- 0
showcase/projects/midas/arumAgents/agentGenerator.js View File

@ -0,0 +1,216 @@
'use strict';
function AgentGenerator(id) {
// execute super constructor
eve.Agent.call(this, id);
this.rpc = this.loadModule('rpc', this.rpcFunctions);
var me = this;
this.amountOfEvents = 0;
this.eventNumber = 0;
this.eventsToFire = 0;
this.lastEndOfDayTime = null;
this.events = [];
conn = this.connect(eve.system.transports.getAll());
// connect to websocket if not online only
if (conn[0].connect !== undefined) {
conn[0].connect(EVENTS_AGENT_ADDRESS)
.then(function () {
console.log('Connected to ', EVENTS_AGENT_ADDRESS);
me.rpc.request(EVENTS_AGENT_ADDRESS, {
method: "loadEvents",
params: {filename: "events.csv", actuallySend: true}
}).done(function (reply) {
me.amountOfEvents = reply;
me.getEvents(AMOUNT_OF_INITIAL_EVENTS);
});
})
.catch(function (err) {
console.log('Error: Failed to connect to the conductor agent');
console.log(err);
// keep trying until the conductor agent is online
setTimeout(connect, RECONNECT_DELAY);
});
}
//use local connection
else {
EVENTS_AGENT_ADDRESS = 'eventGenerator';
setTimeout(function() {
me.rpc.request(EVENTS_AGENT_ADDRESS, {
method: "loadEvents",
params: {filename: "events.csv", actuallySend: true}
}).done(function (reply) {
me.amountOfEvents = reply;
me.getEvents(AMOUNT_OF_INITIAL_EVENTS);
});
},40);
}
}
// extend the eve.Agent prototype
AgentGenerator.prototype = Object.create(eve.Agent.prototype);
AgentGenerator.prototype.constructor = AgentGenerator;
// define RPC functions, preferably in a separated object to clearly distinct
// exposed functions from local functions.
AgentGenerator.prototype.rpcFunctions = {};
AgentGenerator.prototype.rpcFunctions.receiveEvent = function(params) {
// setup timeline
this.events.push(JSON.stringify(params));
if (params.performedBy == "global") {
this.imposeWorkingHours(params);
}
else {
if (agentList[params.performedBy] === undefined) {
agentList[params.performedBy] = new GenericAgent(params.performedBy, params.type);
}
this.rpc.request(params.performedBy, {method: "newEvent", params: params});
}
// check if we need to get another event, its done here to avoid raceconditions
if (this.eventsToFire != 0) {
var me = this;
setTimeout(function() {
me.eventNumber += 1;
eventCounter.innerHTML = me.eventNumber +""; // make string so it works
me.rpc.request(EVENTS_AGENT_ADDRESS, {method:'nextEvent', params:{}}).done();
me.eventsToFire -= 1;
},EVENT_DELAY);
if (INCREASE_SPEED == true) {
EVENT_DELAY = Math.max(0, 1000 - (1000 * (me.eventNumber / 205)));
}
}
};
AgentGenerator.prototype.getEvents = function (count) {
if (this.eventNumber + count > this.amountOfEvents) {
count = this.amountOfEvents - this.eventNumber;
}
if (count != 0) {
this.eventsToFire = count - 1;
this.rpc.request(EVENTS_AGENT_ADDRESS, {method: 'nextEvent', params: {}}).done();
this.eventNumber += 1;
eventCounter.innerHTML = this.eventNumber + ""; // make string so it works
}
};
AgentGenerator.prototype.rpcFunctions.updateOpenJobs = function(params) {
var skipJob = params.jobId;
var time = params.time;
this.moveTimeline(params);
for (var agentId in agentList) {
if (agentList.hasOwnProperty(agentId)) {
agentList[agentId].jobs.updateJobs(time, skipJob);
}
}
};
AgentGenerator.prototype.moveTimeline = function(params) {
timeline.setCustomTime(params.time);
var range = timeline.getWindow();
var duration = range.end - range.start;
var hiddenDates = timeline.body.hiddenDates;
var DateUtil = vis.timeline.DateUtil;
var hiddenDuration = DateUtil.getHiddenDurationBetween(hiddenDates, range.start, range.end);
var visibleDuration = duration - hiddenDuration;
var fraction = 0.15;
var requiredStartDuration = (1-fraction) * visibleDuration;
var requiredEndDuration = fraction * visibleDuration;
var convertedTime = new Date(params.time).getTime();
var newStart;
var newEnd;
var elapsedDuration = 0;
var previousPoint = convertedTime;
for (var i = hiddenDates.length-1; i > 0; i--) {
var startDate = hiddenDates[i].start;
var endDate = hiddenDates[i].end;
// if time after the cutout, and the
if (endDate <= convertedTime) {
elapsedDuration += previousPoint - endDate;
previousPoint = startDate;
if (elapsedDuration >= requiredStartDuration) {
newStart = endDate + (elapsedDuration - requiredStartDuration);
break;
}
}
}
if (newStart === undefined) {
newStart = endDate - (requiredStartDuration - elapsedDuration);
}
elapsedDuration = 0;
previousPoint = convertedTime;
for (var i = 0; i < hiddenDates.length; i++) {
var startDate = hiddenDates[i].start;
var endDate = hiddenDates[i].end;
// if time after the cutout, and the
if (startDate >= convertedTime) {
elapsedDuration += startDate - previousPoint;
previousPoint = endDate;
if (elapsedDuration >= requiredEndDuration) {
newEnd = startDate - (elapsedDuration - requiredEndDuration);
break;
}
}
}
if (newEnd === undefined) {
newEnd = endDate + (requiredEndDuration - elapsedDuration);
}
timeline.setWindow(newStart, newEnd, {animate:Math.min(100,EVENT_DELAY)});
};
AgentGenerator.prototype.imposeWorkingHours = function(params) {
var time = params.time;
var operation = params.operation;
for (var agentId in agentList) {
if (agentList.hasOwnProperty(agentId)) {
var agent = agentList[agentId];
for (var jobId in agent.jobs.openJobs) {
if (agent.jobs.openJobs.hasOwnProperty(jobId)) {
var job = agent.jobs.openJobs[jobId];
agent.updateAssignment(jobId, job.type, time, operation);
}
}
}
}
if (operation == 'endOfDay') {
this.lastEndOfDayTime = time;
}
else {
if (this.lastEndOfDayTime !== null) {
timelineItems.update({
id: 'night' + uuid(),
start: this.lastEndOfDayTime,
end: time,
type: 'background',
className: 'night'
});
this.lastEndOfDayTime = null;
}
}
};
AgentGenerator.prototype.printEvents = function() {
var str = "";
str += "[";
for (var i = 0; i < this.events.length; i++) {
str += this.events[i];
if (i < this.events.length - 1) {
str += ","
}
}
str += "]";
console.log(str);
}

+ 40
- 0
showcase/projects/midas/arumAgents/durationData.js View File

@ -0,0 +1,40 @@
/**
* Created by Alex on 9/25/2014.
*/
function DurationData() {
this.fields = ['duration','durationWithPause','durationWithStartup','durationWithBoth'];
for (var i = 0; i < this.fields.length; i++) {
this[this.fields[i]] = 0;
}
}
DurationData.prototype.setData = function(otherData) {
for (var i = 0; i < this.fields.length; i++) {
this[this.fields[i]] = otherData[this.fields[i]];
}
};
DurationData.prototype.getData = function() {
var dataObj = {};
for (var i = 0; i < this.fields.length; i++) {
dataObj[this.fields[i]] = this[this.fields[i]];
}
return dataObj;
};
DurationData.prototype.useHighest = function(otherData) {
for (var i = 0; i < this.fields.length; i++) {
var field = this.fields[i];
if (this[field] < otherData[field]) {
this[field] = otherData[field];
}
}
};
DurationData.prototype.calculateDuration = function(time, timeStart, elapsedTime, elapsedTimeWithPause, startupTime) {
this.duration = elapsedTime;
this.durationWithPause = elapsedTimeWithPause;
this.durationWithStartup = elapsedTime + startupTime.durationWithStartup;
this.durationWithBoth = elapsedTimeWithPause + startupTime.durationWithBoth;
};

+ 142
- 0
showcase/projects/midas/arumAgents/durationStats.js View File

@ -0,0 +1,142 @@
/**
* Created by Alex on 9/25/2014.
*/
function DurationStats() {
this.fields = ['duration','durationWithPause','durationWithStartup','durationWithBoth'];
for (var i = 0; i < this.fields.length; i++) {
this[this.fields[i]] = {mean: 0, std: 0};
}
}
DurationStats.prototype.clearStats = function() {
for (var i = 0; i < this.fields.length; i++) {
var field = this.fields[i];
this[field].mean = 0;
this[field].std = 0;
}
};
DurationStats.prototype.sumStats = function(otherData) {
for (var i = 0; i < this.fields.length; i++) {
var field = this.fields[i];
this[field].mean += otherData[field].mean;
this[field].std += Math.pow(otherData[field].std,2);
}
};
DurationStats.prototype.averageStats = function(datapoints) {
for (var i = 0; i < this.fields.length; i++) {
var field = this.fields[i];
this[field].mean /= datapoints;
this[field].std = Math.sqrt(this[field].std / datapoints);
}
};
DurationStats.prototype.getMeanData = function() {
var dataObj = {};
for (var i = 0; i < this.fields.length; i++) {
dataObj[this.fields[i]] = this[this.fields[i]].mean;
}
return dataObj;
};
DurationStats.prototype.getData = function() {
var dataObj = {};
for (var i = 0; i < this.fields.length; i++) {
dataObj[this.fields[i]] = {};
dataObj[this.fields[i]].mean = this[this.fields[i]].mean;
dataObj[this.fields[i]].std = this[this.fields[i]].std;
}
return dataObj;
};
DurationStats.prototype.setData = function(otherData) {
for (var i = 0; i < this.fields.length; i++) {
var field = this.fields[i];
this[field].mean = otherData[field].mean;
this[field].std = otherData[field].std;
}
};
DurationStats.prototype.generateData = function(otherData) {
for (var i = 0; i < this.fields.length; i++) {
var field = this.fields[i];
this[field].mean = otherData[i] * 3600000;
this[field].std = otherData[i] * 0.1;
}
};
DurationStats.prototype.useHighest = function(otherData) {
for (var i = 0; i < this.fields.length; i++) {
var field = this.fields[i];
if (this[field].mean < otherData[field].mean) {
this[field].mean = otherData[field].mean;
this[field].std = otherData[field].std;
}
}
};
DurationStats.prototype.getFakeStats = function(type) {
switch (type) {
case "Assemble Coffeemaker":
this.generateData([1.3,1.3,1.3,1.3]);
break;
case "Discuss potential NC":
this.generateData([0.5,0.5,0.9,0.9]);
break;
case "Drilling rework":
this.generateData([5,5,8,8]);
break;
case "Go to station":
var a = 0.3;
this.generateData([a,a,a,a]);
break;
case "Inspect finished Coffeemaker":
var a = 2;
this.generateData([a,a,a,a]);
break;
case "Inspect potential NC":
var a = 0.5;
this.generateData([a,a,a,a]);
break;
case "Kitting Coffeemaker":
var a = 1.2;
this.generateData([a,a,a,a]);
break;
case "NC Meeting":
var a = 15;
this.generateData([3,3.5,a,a]);
break;
case "Go to NC meeting":
var a = 12;
this.generateData([a,a,a,a]);
break;
case "Organise drilling rework":
var a = 2;
this.generateData([a,a,3,3]);
break;
case "Produce Coffeemaker":
var a = 35;
this.generateData([a,a,a,a]);
break;
case "Transport to delivery":
var a = 0.4;
this.generateData([a,a,a,a]);
break;
default:
console.log("CANNOT MATCH", type);
break;
}
};

+ 2037
- 0
showcase/projects/midas/arumAgents/eventGenerator.js
File diff suppressed because it is too large
View File


+ 85
- 0
showcase/projects/midas/arumAgents/genericAgent.js View File

@ -0,0 +1,85 @@
'use strict';
if (typeof window === 'undefined') {
var eve = require('evejs');
}
function GenericAgent(id, type) {
// execute super constructor
eve.Agent.call(this, id);
this.id = id;
this.rpc = this.loadModule('rpc', this.rpcFunctions);
this.connect(eve.system.transports.getAll());
this.type = type;
this.jobs = new JobManager(this);
this.timelineDataset = timelineItems;
timelineGroups.add({id:id, content:type + ": " + id, className: 'timelineGroup ' + type});
this.availableSubgroups = [0,1,2,3,4,5,6,7,8,9,10];
this.freeSubgroups = {};
for (var i = 0; i < this.availableSubgroups.length; i++) {
this.freeSubgroups[this.availableSubgroups[i]] = true;
}
this.usedSubgroups = {};
}
// extend the eve.Agent prototype
GenericAgent.prototype = Object.create(eve.Agent.prototype);
GenericAgent.prototype.constructor = GenericAgent;
// define RPC functions, preferably in a separated object to clearly distinct
// exposed functions from local functions.
GenericAgent.prototype.rpcFunctions = {};
GenericAgent.prototype.allocateSubgroup = function(type) {
for (var i = 0; i < this.availableSubgroups.length; i++) {
if (this.freeSubgroups[this.availableSubgroups[i]] == true) {
this.usedSubgroups[type] = i;
this.freeSubgroups[this.availableSubgroups[i]] = false;
break;
}
}
};
GenericAgent.prototype.freeSubgroup = function(type) {
this.freeSubgroups[this.usedSubgroups[type]] = true;
delete this.usedSubgroups[type];
};
GenericAgent.prototype.newAssignment = function(id, type, time, prerequisites) {
this.allocateSubgroup(type);
this.jobs.add(id, type, time, prerequisites);
};
/**
* @param id
* @param time
* @param type
*/
GenericAgent.prototype.finishAssignment = function(id, type, time) {
this.jobs.finish(id, type, time);
};
GenericAgent.prototype.updateAssignment = function(id, type, time, operation) {
this.jobs.update(id, type, time, operation);
};
GenericAgent.prototype.rpcFunctions.newEvent = function(params) {
// handle events
if (params.operation == 'start') {
this.newAssignment(params.jobId, params.assignment, params.time, params.prerequisites)
}
else if (params.operation == 'finish') {
this.finishAssignment(params.jobId, params.assignment, params.time);
}
else if (params.operation == 'pause' || params.operation == 'resume') {
this.updateAssignment(params.jobId,params.assignment,params.time, params.operation);
}
};
if (typeof window === 'undefined') {
module.exports = GenericAgent;
}

+ 116
- 0
showcase/projects/midas/arumAgents/job.js View File

@ -0,0 +1,116 @@
'use strict';
function uuid() {
return (Math.random()*1e15).toString(32) + "-" + (Math.random()*1e15).toString(32);
}
/**
* This is a local assignment, this keeps track on how long an assignment takes THIS worker.
*
* @param id
* @param type
* @param timeStart
* @constructor
*/
function Job(id, type, timeStart, agentId, prerequisites) {
this.id = id;
this.type = type;
this.agentId = agentId;
this.timeStart = timeStart;
this.timeResumed = timeStart;
this.timePaused = 0;
this.elapsedTime = 0;
this.elapsedTimeWithPause = 0;
this.endOfDayPause = false;
this.paused = false;
this.finished = false;
this.duration = new DurationData();
this.prediction = new DurationStats();
this.startupTime = new DurationData();
this.predictedStartupTime = new DurationStats();
this.prerequisites = prerequisites;
}
Job.prototype.prerequisiteFinished = function(params) {
var uuid = params.uuid;
for (var i = 0; i < this.prerequisites.length; i++) {
var prereq = this.prerequisites[i];
if (prereq.uuid == uuid) {
prereq.times.setData(params.duration);
break;
}
}
};
Job.prototype.watchingPrerequisite = function(preliminaryStats, uuid) {
for (var i = 0; i < this.prerequisites.length; i++) {
var prereq = this.prerequisites[i];
if (prereq.uuid == uuid) {
prereq.stats.setData(preliminaryStats);
this.predictedStartupTime.useHighest(preliminaryStats);
break;
}
}
};
Job.prototype.finalizePrerequisites = function() {
for (var i = 0; i < this.prerequisites.length; i++) {
this.startupTime.useHighest(this.prerequisites[i].times);
}
};
Job.prototype.finish = function(time) {
this.finished = true;
this.elapsedTime += new Date(time).getTime() - new Date(this.timeResumed).getTime();
this.elapsedTimeWithPause += new Date(time).getTime() - new Date(this.timeResumed).getTime();
this.finalizePrerequisites();
this.duration.calculateDuration(time, this.timeStart, this.elapsedTime, this.elapsedTimeWithPause, this.startupTime);
};
Job.prototype.pause = function(time, endOfDay) {
// if this is the endOfDay AND the job is paused, count the pause time and set the endOfDay pause to true
if (endOfDay == true && this.paused == true) {
this.elapsedTimeWithPause += new Date(time).getTime() - new Date(this.timePaused).getTime();
this.endOfDayPause = true;
}
// if this is the endOfDay AND the job is NOT paused, pause the job, increment the timers
else if (endOfDay == true && this.paused == false) {
this.elapsedTimeWithPause += new Date(time).getTime() - new Date(this.timeResumed).getTime();
this.elapsedTime += new Date(time).getTime() - new Date(this.timeResumed).getTime();
this.endOfDayPause = true;
}
else if (this.paused == false) {
this.elapsedTimeWithPause += new Date(time).getTime() - new Date(this.timeResumed).getTime();
this.elapsedTime += new Date(time).getTime() - new Date(this.timeResumed).getTime();
this.timePaused = time;
this.paused = true;
}
};
Job.prototype.resume = function(time, startOfDay) {
// if the job was paused because of the endOfDay, resume it and set the timeResumed to now
if (this.endOfDayPause == true && startOfDay == true && this.paused == false) {
this.timeResumed = time;
this.endOfDayPause = false;
}
// if the job was paused before the endOfDay, keep it paused, but set the paused time to now.
else if (this.endOfDayPause == true && startOfDay == true && this.paused == true) {
this.timePaused = time;
this.endOfDayPause = false;
}
// if this is NOT the start of day and the job was paused, resume job, increment
else if (startOfDay == false && this.paused == true) {
this.elapsedTimeWithPause += new Date(time).getTime() - new Date(this.timePaused).getTime();
this.timeResumed = time;
this.paused = false;
}
};

+ 434
- 0
showcase/projects/midas/arumAgents/jobAgent.js View File

@ -0,0 +1,434 @@
'use strict';
function JobAgent(id) {
// execute super constructor
eve.Agent.call(this, id);
this.rpc = this.loadModule('rpc', this.rpcFunctions);
this.connect(eve.system.transports.getAll());
this.id = id;
this.type = this.id.replace('job_','');
this.globalStats = new DurationStats();
this.globalStats.getFakeStats(id);
this.agentStats = {};
this.allJobs = {}; // used to quickly look up a job ID
this.openJobs = {}; // used to check if there is a watcher to
this.closedJobs = {};// keeps a list of agentIds containing jobs, used for stats collection
// optimization would be nice with running averages, but N samples are needed, wait for demo data.
this.watchers = {};
}
// extend the eve.Agent prototype
JobAgent.prototype = Object.create(eve.Agent.prototype);
JobAgent.prototype.constructor = JobAgent;
// define RPC functions, preferably in a separated object to clearly distinct
// exposed functions from local functions.
JobAgent.prototype.rpcFunctions = {};
JobAgent.prototype.expandPrerequisites = function(prerequisites) {
var expanded = [];
if (prerequisites !== undefined) {
for (var i = 0; i < prerequisites.length; i++) {
var prereq = prerequisites[i];
if (typeof prereq == 'string') {
expanded.push({
jobId: prereq,
uuid: uuid(),
times : new DurationData(),
stats: new DurationStats()
});
}
else if (typeof prereq == 'object' && prereq.type !== undefined) { //&& prereq.agentId !== undefined not needed since the same items will be added when only type exists
prereq.uuid = uuid();
prereq.times = new DurationData();
prereq.stats = new DurationStats();
expanded.push(prereq);
}
else {
console.log('ERROR: cannot use the prerequisites! Not in array of strings or array of objects with correct fields format.');
throw new Error('ERROR: cannot use the prerequisites! Not in array of strings or array of objects with correct fields format.');
}
}
}
return expanded;
};
/**
* Create new Job for agent
* @param params
*/
JobAgent.prototype.rpcFunctions.add = function(params) {
var agentId = params.agentId;
var jobId = params.jobId;
// create stats if not yet exits
if (this.agentStats[agentId] === undefined) {
this.agentStats[agentId] = new DurationStats();
}
// create open job
if (this.openJobs[agentId] === undefined) {
this.openJobs[agentId] = {};
}
if (this.openJobs[agentId][jobId] !== undefined) {
console.log('cannot start new job, jobId:', jobId, ' already exists!');
throw new Error('cannot start new job, jobId:' + jobId + ' already exists!');
}
var prerequisites = this.expandPrerequisites(params.prerequisites);
this.openJobs[agentId][jobId] = new Job(jobId, this.id, params.time, agentId, prerequisites);
this.allJobs[jobId] = this.openJobs[agentId][jobId];
this.addWatchers(jobId, prerequisites);
// return prediction
var statsData;
if (this.agentStats[agentId].duration.mean == 0) {
statsData = this.globalStats.getData();
}
else {
statsData = this.agentStats[agentId].getData();
}
return statsData;
};
/**
* finish the job of an agent
* @param params
*/
JobAgent.prototype.rpcFunctions.finish = function(params) {
var agentId = params.agentId;
var jobId = params.jobId;
var job = this.openJobs[agentId][jobId];
// finish job
job.finish(params.time);
// notify watchers that a job is finished.
if (this.watchers[jobId] !== undefined) {
for (var i = 0; i < this.watchers[jobId].length; i++) {
var val = this.watchers[jobId][i];
var address = val.address;
var parentJobId = val.parentJobId;
var uuid = val.uuid;
this.rpc.request(address, {method:'watchedJobFinished', params:{
uuid: uuid,
parentJobId: parentJobId,
duration: job.duration.getData()
}}).done();
}
}
// cleanup watchers
delete this.watchers[jobId];
// move from open to closed jobs.
if (this.closedJobs[agentId] === undefined) {
this.closedJobs[agentId] = {};
}
if (this.closedJobs[agentId][jobId] !== undefined) {
console.log('cannot close job, jobId:', jobId, ' already exists!');
throw new Error('cannot close job, jobId:' + jobId + ' already exists!');
}
this.closedJobs[agentId][jobId] = this.openJobs[agentId][jobId];
delete this.openJobs[agentId][jobId];
this.updateStats();
return {
elapsedTime: this.closedJobs[agentId][jobId].elapsedTime,
elapsedTimeWithPause: this.closedJobs[agentId][jobId].elapsedTimeWithPause,
duration: this.closedJobs[agentId][jobId].duration.getData(),
prediction: this.globalStats.getData()
};
};
/**
* update the job of an agent
* @param params
*/
JobAgent.prototype.rpcFunctions.update = function(params) {
var agentId = params.agentId;
var jobId = params.jobId;
var job = this.openJobs[agentId][jobId];
var operation = params.operation;
switch (operation) {
case 'pause':
job.pause(params.time, false);
break;
case 'endOfDay':
job.pause(params.time, true);
break;
case 'startOfDay':
job.resume(params.time, true);
break;
case 'resume':
job.resume(params.time, false);
break;
}
return {jobId: jobId, type: this.type, elapsedTime: job.elapsedTime, elapsedTimeWithPause: job.elapsedTimeWithPause};
};
/**
* return agent stats
* @param params
* @returns {*}
*/
JobAgent.prototype.rpcFunctions.getAgentStats = function(params) {
return this.agentStats[params.agentId];
};
/**
* return global stats
* @param params
* @returns {{mean: number, std: number}|*}
*/
JobAgent.prototype.rpcFunctions.getGlobalStats = function(params) {
return this.globalStats;
};
JobAgent.prototype.rpcFunctions.watchedJobFinished = function(params) {
var jobId = params.parentJobId;
this.allJobs[jobId].prerequisiteFinished(params);
};
/**
*
* @param params
* @param sender
* @returns {*}
*/
JobAgent.prototype.rpcFunctions.addWatcherOnJobId = function(params, sender) {
var jobId = params.jobId;
var uuid = params.uuid;
var parentJobId = params.parentJobId;
var job = this.allJobs[jobId];
// if the job is already finished, call the finished callback
if (job.finished == true) {
this.rpc.request(sender, {method:'watchedJobFinished', params:{
uuid: uuid,
parentJobId: parentJobId,
duration: job.duration.getData() // we need the pure json data, not the class
}}).done();
}
else {
// we will create a watcher on a job which will alert the watcher when the job is finished with all the times.
if (this.watchers[jobId] === undefined) {
this.watchers[jobId] = [];
}
this.watchers[jobId].push({address: params.address, uuid: uuid});
}
// return the best prediction we have
if (this.agentStats[job.agentId].mean == 0) {
return this.globalStats.getData(); // we need the pure json data, not the class
}
return this.agentStats[job.agentId].getData(); // we need the pure json data, not the class
};
/**
*
* @param params
* @param sender
* @returns {*}
*/
JobAgent.prototype.rpcFunctions.addWatcherByAgentID = function(params, sender) {
var agentId = params.agentId;
var parentJobId = params.parentJobId;
var jobId = null;
var uuid = params.uuid;
var returnStats;
// see which statistics collection we will need to return.
if (this.agentStats[agentId].duration.mean == 0) {
returnStats = this.globalStats;
}
else {
returnStats = this.agentStats[agentId];
}
// see if we have an open job with that agent of this type
if (this.openJobs[agentId] !== undefined) {
for (var jId in this.openJobs[agentId]) {
if (this.openJobs[agentId].hasOwnProperty(jId)) {
jobId = jId;
break;
}
}
}
// there is no open job from supplied agent of this type. return the mean of the return stats
if (jobId === null) {
this.rpc.request(params.address, {method:'watchedJobFinished', params:{
uuid: uuid,
parentJobId: parentJobId,
duration: returnStats.getMeanData(), // we need the pure json data, not the class
oldData: true
}}).done();
}
else {
params.jobId = jobId;
this.rpcFunctions.addWatcherOnJobId.call(this, params, sender);
}
// return the best prediction we have
return returnStats.getData(); // we need the pure json data, not the class
};
/**
*
* @param params
* @param sender
* @returns {*}
*/
JobAgent.prototype.rpcFunctions.addWatcherByType = function(params, sender) {
// since we cannot watch a global type, we return the global stats at that point.
this.rpc.request(params.address, {method:'watchedJobFinished', params:{
uuid: params.uuid,
parentJobId: params.parentJobId,
duration: this.globalStats.getMeanData(), // we need the pure json data, not the class
oldData: true
}}).done();
return this.globalStats.getData(); // we need the pure json data, not the class
};
/**
*
* @param parentJobId | ID from the job that wants to WATCH other jobs
* @param prerequisites
*/
JobAgent.prototype.addWatchers = function(parentJobId, prerequisites) {
for (var i = 0; i < prerequisites.length; i++) {
var prereq = prerequisites[i];
var params = {
uuid: prereq.uuid,
address: this.id, // this is the callback address
parentJobId: parentJobId// this is the job that wants to watch the other one.
};
var me = this;
if (prereq.jobId !== undefined) {
// we now have a parentJobId to watch
// we first need to find the type of job this belongs to.
this.rpc.request('JobAgentGenerator', {method: 'returnJobAddress', params: {jobId: prereq.jobId}})
// now that we have an address, set a watcher on the job id
.done(function (address) {
if (address != 'doesNotExist') {
params.jobId = prereq.jobId; // this is the job we want to watch
me.rpc.request(address, {method: 'addWatcherOnJobId', params: params})
.done(function (preliminaryStats) {
me.allJobs[parentJobId].watchingPrerequisite(preliminaryStats, prereq.uuid);
})
}
else {
console.log('ERROR: watch job does not exist.');
throw new Error('ERROR: watch job does not exist.');
}
});
}
else if (prereq.agentId !== undefined && prereq.type !== undefined) {
// we now have an agentId and a jobType to watch.
params.agentId = prereq.agentId; // this is the job we want to watch
this.rpc.request(prereq.type, {method: 'addWatcherByAgentID', params: params})
.done(function (preliminaryStats) {
me.allJobs[parentJobId].watchingPrerequisite(preliminaryStats, prereq.uuid);
})
}
else if (prereq.type !== undefined) {
this.rpc.request(prereq.type, {method: 'addWatcherByType', params: params})
.done(function (preliminaryStats) {
me.allJobs[parentJobId].watchingPrerequisite(preliminaryStats, prereq.uuid);
})
}
}
};
JobAgent.prototype.updatePredictedStartup = function(jobId, prediction) {
var jobPrediction = this.allJobs[jobId].predictedStartupTime;
jobPrediction.mean = Math.max(jobPrediction.mean, prediction.mean);
jobPrediction.std = Math.sqrt(Math.pow(jobPrediction.std,2) + Math.pow(prediction.std,2));
this.allJobs[jobId].prerequisitesCount += 1;
};
/**
* Update all statistics
*
*/
JobAgent.prototype.updateStats = function() {
this.globalStats.clearStats();
var count = 0;
for (var agentId in this.closedJobs) {
if (this.closedJobs.hasOwnProperty(agentId)) {
var collection = this.closedJobs[agentId];
// could be optimised with rolling average for efficient memory management
this.agentStats[agentId].setData(this.updateStatsIn(collection));
this.globalStats.sumStats(this.agentStats[agentId]);
count += 1;
}
}
this.globalStats.averageStats(count);
};
/**
*
* @param collection
* @returns {{duration: *, durationWithPause: *, durationWithStartup: *, durationWithBoth: *}}
*/
JobAgent.prototype.updateStatsIn = function(collection) {
var stats = {};
for (var i = 0; i < this.globalStats.fields.length; i++) {
var field = this.globalStats.fields[i];
stats[field] = this.collectStatsIn(collection, field);
}
return stats;
};
JobAgent.prototype.collectStatsIn = function(collection, field) {
var total = 0;
var mean = 0;
var std = 0;
var minVal = 1e16;
var maxVal = 0;
var count = 0;
for (var jobId in collection) {
if (collection.hasOwnProperty(jobId)) {
var value = collection[jobId].duration[field];
maxVal = value > maxVal ? value : maxVal;
minVal = value < minVal ? value : minVal;
total += collection[jobId].duration[field];
count += 1;
}
}
if (count > 0) {
mean = total / count;
for (var jobId in collection) {
if (collection.hasOwnProperty(jobId)) {
std += Math.pow(collection[jobId].duration[field] - mean,2);
}
}
std = Math.sqrt(std/count);
return {mean: mean, std: std, min: minVal, max: maxVal};
}
else {
return {mean: 0, std: 0, min: 0, max: 0};
}
};
JobAgent.prototype.hasJob = function(params) {
return this.allJobs[params.jobId] !== undefined;
};

+ 169
- 0
showcase/projects/midas/arumAgents/jobAgentGenerator.js View File

@ -0,0 +1,169 @@
'use strict';
function JobAgentGenerator(id) {
// execute super constructor
eve.Agent.call(this, id);
this.rpc = this.loadModule('rpc', this.rpcFunctions);
this.connect(eve.system.transports.getAll());
}
// extend the eve.Agent prototype
JobAgentGenerator.prototype = Object.create(eve.Agent.prototype);
JobAgentGenerator.prototype.constructor = AgentGenerator;
// define RPC functions, preferably in a separated object to clearly distinct
// exposed functions from local functions.
JobAgentGenerator.prototype.rpcFunctions = {};
JobAgentGenerator.prototype.rpcFunctions.createJob = function(params) {
var jobAgentName = params.type;
if (jobList[jobAgentName] === undefined) {
jobList[jobAgentName] = new JobAgent(jobAgentName);
graph2dGroups.add([
{
id: jobAgentName+'_pred_duration_std_lower',
content: "prediction",
className: 'prediction_std',
options: {drawPoints:false}
},
{
id: jobAgentName+'_pred_durationWithPause_std_lower',
content: "predWithPause",
className: 'prediction_std',
options: {drawPoints:false}
},
{
id: jobAgentName+'_pred_durationWithStartup_std_lower',
content: "predWithStartup",
className: 'prediction_std',
options: {drawPoints:false}
},
{
id: jobAgentName+'_pred_durationWithBoth_std_lower',
content: "predWithBoth",
className: 'prediction_std',
options: {drawPoints:false}
},
{
id: jobAgentName+'_pred_duration_std_higher',
content: "prediction",
className: 'prediction_std',
options: {drawPoints:false}
},
{
id: jobAgentName+'_pred_durationWithPause_std_higher',
content: "predWithPause",
className: 'prediction_std',
options: {drawPoints:false}
},
{
id: jobAgentName+'_pred_durationWithStartup_std_higher',
content: "predWithStartup",
className: 'prediction_std',
options: {drawPoints:false}
},
{
id: jobAgentName+'_pred_durationWithBoth_std_higher',
content: "predWithBoth",
className: 'prediction_std',
options: {drawPoints:false}
},{
id: jobAgentName+'_pred_duration_original',
content: "prediction",
className: 'prediction_original'
},
{
id: jobAgentName+'_pred_durationWithPause_original',
content: "predWithPause",
className: 'prediction_original'
},
{
id: jobAgentName+'_pred_durationWithStartup_original',
content: "predWithStartup",
className: 'prediction_original'
},
{
id: jobAgentName+'_pred_durationWithBoth_original',
content: "predWithBoth",
className: 'prediction_original'
},
{
id: jobAgentName+'_pred_duration',
content: "prediction",
className: 'prediction'
},
{
id: jobAgentName+'_pred_durationWithPause',
content: "predWithPause",
className: 'prediction'
},
{
id: jobAgentName+'_pred_durationWithStartup',
content: "predWithStartup",
className: 'prediction'
},
{
id: jobAgentName+'_pred_durationWithBoth',
content: "predWithBoth",
className: 'prediction'
},
{
id: jobAgentName+'_duration',
content: "duration",
className: 'duration'
},
{
id: jobAgentName+'_durationWithPause',
content: "durationWithPause",
className: 'duration'
},
{
id: jobAgentName+'_durationWithStartup',
content: "durationWithStartup",
className: 'duration'
},
{
id: jobAgentName+'_durationWithBoth',
content: "durationWithBoth",
className: 'duration'
}
]);
var visibilityUpdate = {};
//visibilityUpdate[jobAgentName+'_pred'] = false;
//visibilityUpdate[jobAgentName+'_predWithPause'] = false;
//visibilityUpdate[jobAgentName+'_predWithStartup'] = false;
//visibilityUpdate[jobAgentName+'_predWithBoth'] = false;
//visibilityUpdate[jobAgentName+'_duration'] = false;
//visibilityUpdate[jobAgentName+'_durationWithPause'] = false;
//visibilityUpdate[jobAgentName+'_durationWithStartup'] = false;
//visibilityUpdate[jobAgentName+'_durationWithBoth'] = false;
graph2d.setOptions({groups:{visible:visibilityUpdate}});
refreshJobs();
}
};
JobAgentGenerator.prototype.rpcFunctions.returnJobAddress = function(params) {
var instanceId = params.instanceId;
var hasJob = false;
for (var jobAgentName in jobList) {
if (jobList.hasOwnProperty(jobAgentName)) {
hasJob = jobList[jobAgentName].hasJob(instanceId);
if (hasJob == true) {
return jobAgentName;
}
}
}
return "doesNotExist";
};
JobAgentGenerator.prototype.getAllJobNames = function() {
var list = [];
for (var jobAgentName in jobList) {
if (jobList.hasOwnProperty(jobAgentName)) {
list.push(jobAgentName);
}
}
return list;
};

+ 428
- 0
showcase/projects/midas/arumAgents/jobManager.js View File

@ -0,0 +1,428 @@
'use strict';
function JobManager(agent) {
this.agent = agent;
this.jobs = {
id:{},
type:{
open:{},
closed:{}
}
};
this.openJobs = {};
}
JobManager.prototype.add = function(id, type, time, prerequisites) {
var me = this;
// create job agent. This agent will keep track of the global job stats. Jobs per type.
this.agent.rpc.request('jobAgentGenerator',{method:'createJob', params:{type:type}}).done();
this.jobs.id[id] = {
type: type,
startTime: time,
prediction: null,
predictionCounter: 0,
elapsedTime: 0,
elapsedTimeWithPause: 0,
pauseCount: 0,
endOfDay: false,
paused: false,
pauseAreaID: ""
};
// assign agent to job.
this.agent.rpc.request(type, {method:'add', params:{
agentId: this.agent.id,
time:time,
jobId: id,
prerequisites: prerequisites
}})
.done(function (prediction) {
if (prediction.duration.mean != 0) {
me.agent.timelineDataset.update({
id: id + "_predMean0",
start: time,
end: new Date(time).getTime() + prediction.duration.mean,
group: me.agent.id,
type: 'range',
content: "",
subgroup: me.agent.usedSubgroups[type],
className: 'prediction'
});
}
me.jobs.id[id].prediction = prediction;
});
if (this.jobs.type.open[type] === undefined) {this.jobs.type.open[type] = {}}
this.jobs.type.open[type][id] = time;
this.openJobs[id] = this.jobs.id[id];
var addQuery = [{id:id, start:time, content:"started: "+ type, group:this.agent.id, subgroup: this.agent.usedSubgroups[type]}];
this.agent.timelineDataset.add(addQuery);
this.agent.rpc.request("agentGenerator", {method: 'updateOpenJobs', params:{jobId: id, time: time}}).done();
};
JobManager.prototype.finish = function(id, type, time) {
var me = this;
// finish the job.
this.agent.rpc.request(type, {method:'finish', params:{
agentId: this.agent.id,
time: time,
jobId: id
}})
.done(function (reply) {
var prediction = reply.prediction;
var originalPrediction = me.jobs.id[id].prediction;
me.jobs.id[id].elapsedTime = reply.elapsedTime;
me.jobs.id[id].elapsedTimeWithPause = reply.elapsedTimeWithPause;
me.updateDataSetsFinish(id, type, time, me.jobs.id[id].prediction);
graph2dDataset.push({x: time, y: reply.duration.duration/3600000 ,group: type + '_duration', type: type});
graph2dDataset.push({x: time, y: reply.duration.durationWithPause/3600000 ,group: type + '_durationWithPause', type: type});
graph2dDataset.push({x: time, y: reply.duration.durationWithStartup/3600000 ,group: type + '_durationWithStartup', type: type});
graph2dDataset.push({x: time, y: reply.duration.durationWithBoth/3600000 ,group: type + '_durationWithBoth', type: type});
graph2dDataset.push({x: time, y: prediction.duration.mean/3600000 ,group: type + '_pred_duration', type: type});
graph2dDataset.push({x: time, y: prediction.durationWithPause.mean/3600000 ,group: type + '_pred_durationWithPause', type: type});
graph2dDataset.push({x: time, y: prediction.durationWithStartup.mean/3600000 ,group: type + '_pred_durationWithStartup', type: type});
graph2dDataset.push({x: time, y: prediction.durationWithBoth.mean/3600000 ,group: type + '_pred_durationWithBoth', type: type});
graph2dDataset.push({x: time, y: (prediction.duration.mean + prediction.duration.std)/3600000 ,group: type + '_pred_duration_std_higher', type: type});
graph2dDataset.push({x: time, y: (prediction.durationWithPause.mean + prediction.durationWithPause.std)/3600000 ,group: type + '_pred_durationWithPause_std_higher', type: type});
graph2dDataset.push({x: time, y: (prediction.durationWithStartup.mean + prediction.durationWithStartup.std)/3600000 ,group: type + '_pred_durationWithStartup_std_higher', type: type});
graph2dDataset.push({x: time, y: (prediction.durationWithBoth.mean + prediction.durationWithBoth.std)/3600000 ,group: type + '_pred_durationWithBoth_std_higher', type: type});
graph2dDataset.push({x: time, y: (prediction.duration.mean - prediction.duration.std)/3600000 ,group: type + '_pred_duration_std_lower', type: type});
graph2dDataset.push({x: time, y: (prediction.durationWithPause.mean - prediction.durationWithPause.std)/3600000 ,group: type + '_pred_durationWithPause_std_lower', type: type});
graph2dDataset.push({x: time, y: (prediction.durationWithStartup.mean - prediction.durationWithStartup.std)/3600000 ,group: type + '_pred_durationWithStartup_std_lower', type: type});
graph2dDataset.push({x: time, y: (prediction.durationWithBoth.mean - prediction.durationWithBoth.std)/3600000 ,group: type + '_pred_durationWithBoth_std_lower', type: type});
graph2dDataset.push({x: time, y: originalPrediction.duration.mean/3600000 ,group: type + '_pred_duration_original', type: type});
graph2dDataset.push({x: time, y: originalPrediction.durationWithPause.mean/3600000 ,group: type + '_pred_durationWithPause_original', type: type});
graph2dDataset.push({x: time, y: originalPrediction.durationWithStartup.mean/3600000 ,group: type + '_pred_durationWithStartup_original', type: type});
graph2dDataset.push({x: time, y: originalPrediction.durationWithBoth.mean/3600000 ,group: type + '_pred_durationWithBoth_original', type: type});
});
delete this.jobs.type.open[type][id];
delete this.openJobs[id];
if (this.jobs.type.closed[type] === undefined) {this.jobs.type.closed[type] = {}}
this.jobs.type.closed[type][id] = time;
};
JobManager.prototype.update = function(id, type, time, operation) {
var me = this;
var eventId = uuid();
if (operation == 'endOfDay' || operation == 'startOfDay') {
for (var jobId in this.openJobs) {
if (this.openJobs.hasOwnProperty(jobId)) {
var type = this.openJobs[jobId].type;
this.agent.rpc.request(type, {method:'update', params:{
agentId: this.agent.id,
time: time,
jobId: jobId,
operation: operation
}})
.done(function (reply) {
me.jobs.id[reply.jobId].elapsedTime = reply.elapsedTime;
me.jobs.id[reply.jobId].elapsedTimeWithPause = reply.elapsedTimeWithPause;
me.updateDataSetsOperation(reply.jobId, reply.type, time, operation, eventId);
});
}
}
}
else {
this.agent.rpc.request(type, {method:'update', params:{
agentId: this.agent.id,
time: time,
jobId: id,
operation: operation
}})
.done(function (reply) {
me.jobs.id[id].elapsedTime = reply.elapsedTime;
me.jobs.id[id].elapsedTimeWithPause = reply.elapsedTimeWithPause;
me.updateDataSetsOperation(id, type, time, operation, eventId);
});
}
};
JobManager.prototype.updateDataSetsOperation = function(id, type, time, operation, eventId) {
switch (operation) {
case 'pause':
this.updateDataSetsPause(id, type, time, operation, this.jobs.id[id].prediction, eventId);
break;
case 'endOfDay':
this.updateDataSetsPause(id, type, time, operation, this.jobs.id[id].prediction, eventId);
break;
case 'startOfDay':
this.updateDataSetsResume(id, type, time, operation, this.jobs.id[id].prediction, eventId);
break;
case 'resume':
this.updateDataSetsResume(id, type, time, operation, this.jobs.id[id].prediction, eventId);
break;
}
};
JobManager.prototype.updateDataSetsFinish = function(id, type, time, prediction) {
var updateQuery = [];
var field = 'duration';
var elapsedTime = this.jobs.id[id].elapsedTime;
// gather statistic indicator data
if (this.jobs.id[id].pauseCount > 0) {
field = 'durationWithPause';
elapsedTime = this.jobs.id[id].elapsedTimeWithPause;
}
// generate indicator
var predictedTimeLeft = 0;
if (prediction[field].mean != 0) {
predictedTimeLeft = prediction[field].mean - elapsedTime;
this.updatePredictionOnFinish(id, type, time, prediction[field], elapsedTime);
}
updateQuery.push({
id: id,
end: time,
content: type,
type: 'range',
className: 'finished',
style: 'background-color: ' + this.generateColors(predictedTimeLeft, elapsedTime) + ' !important;'
});
this.agent.freeSubgroup(type);
this.agent.timelineDataset.update(updateQuery);
this.agent.rpc.request("agentGenerator", {method: 'updateOpenJobs', params:{jobId: id, time: time}}).done();
};
JobManager.prototype.updateDataSetsPause = function(id, type, time, operation, prediction, eventId) {
var updateQuery = [];
var image = '<img src="./images/control_pause.png" class="icon"/>';
var flagId = id + "_pauseNotifier" + eventId;
var title = 'Calling RAO for possible NC';
// this causes there to be only one flag for the end of day as well as a moon icon
if (operation == 'endOfDay') {
// don't end-of-day jobs twice
if (this.jobs.id[id].endOfDay == true) {
return;
}
this.jobs.id[id].endOfDay = true;
image = '<img src="./images/moon.png" class="icon"/>';
flagId = id + "endOfDayNotifier" + eventId;
title = "End of working day"
}
else {
this.jobs.id[id].pauseCount += 1;
this.jobs.id[id].pauseAreaID = this.agent.id + "_" + "_pauseArea_" + eventId;
var shadedPauseArea = {
id: this.jobs.id[id].pauseAreaID,
start: time,
end: time,
content: '',
group: this.agent.id,
subgroup: this.agent.usedSubgroups[type],
className: 'pausedArea',
title: 'Job paused.'
};
updateQuery.push(shadedPauseArea);
}
var field = 'duration';
var elapsedTime = this.jobs.id[id].elapsedTime;
if (this.jobs.id[id].pauseCount > 0) {
field = 'durationWithPause';
elapsedTime = this.jobs.id[id].elapsedTimeWithPause;
}
updateQuery.push({id: id, end: time, content: type, type: 'range'});
var imageUpdate = {
id: flagId,
start: time,
end: time,
content: image,
group: this.agent.id,
subgroup: this.agent.usedSubgroups[type],
className: 'pause',
title: title
};
if (this.agent.id == "Paolo") {
imageUpdate.title = "Going to inspect possible NC.";
}
updateQuery.push(imageUpdate);
var predictedTimeLeft = prediction[field].mean - elapsedTime;
var predictionExists = prediction[field].mean != 0;
// update the predicted line if the job is not ALREADY pauseds
if (predictedTimeLeft > 0 && predictionExists == true && this.jobs.id[id].paused != true) {
updateQuery.push({
id: id + "_predMean" + this.jobs.id[id].predictionCounter,
end: time,
group: this.agent.id,
className: 'prediction'
})
}
// set the status to paused if needed
if (operation != 'endOfDay') {
this.jobs.id[id].paused = true;
}
this.agent.timelineDataset.update(updateQuery);
this.agent.rpc.request("agentGenerator", {method: 'updateOpenJobs', params:{jobId: id, time: time}})
};
JobManager.prototype.updateDataSetsResume = function(id, type, time, operation, prediction, eventId) {
var updateQuery = [];
var image = '<img src="./images/control_play.png" class="icon"/>';
var flagId = id + "_resumeNotifier" + eventId;
// this causes there to be only one flag for the start of day as well as a sun icon
if (operation == 'startOfDay') {
// don't start-of-day jobs twice
if (this.jobs.id[id].endOfDay == false) {
return;
}
this.jobs.id[id].endOfDay = false;
image = '<img src="./images/sun.png" class="icon"/>';
flagId = id + "startOfDayNotifier_" + eventId;
}
else {
updateQuery.push({id: this.jobs.id[id].pauseAreaID, end: time, content: '', type: 'range'});
this.jobs.id[id].pauseAreaID = "";
this.jobs.id[id].pauseCount += 1;
}
var field = 'duration';
var elapsedTime = this.jobs.id[id].elapsedTime;
if (this.jobs.id[id].pauseCount > 0) {
field = 'durationWithPause';
elapsedTime = this.jobs.id[id].elapsedTimeWithPause;
}
updateQuery.push({id: id, end: time, content: type, type: 'range'});
updateQuery.push({
id: flagId,
start: time,
end: time,
content: image,
group: this.agent.id,
subgroup: this.agent.usedSubgroups[type],
className: 'pause',
title: 'Resuming job'
});
var predictedTimeLeft = prediction[field].mean - elapsedTime;
// no not increase the prediction line at the start of the day if the job is PAUSED
if (predictedTimeLeft > 0 && !(operation == 'startOfDay' && this.jobs.id[id].paused == true)) {
this.jobs.id[id].predictionCounter += 1;
updateQuery.push({
id: id + "_predMean" + this.jobs.id[id].predictionCounter,
start: time,
end: new Date(time).getTime() + predictedTimeLeft,
group: this.agent.id,
content: "",
subgroup: this.agent.usedSubgroups[type],
type: 'range',
className: 'prediction'
});
}
// resume if needed
if (operation != 'startOfDay'){
this.jobs.id[id].paused = false;
}
this.agent.timelineDataset.update(updateQuery);
this.agent.rpc.request("agentGenerator", {method: 'updateOpenJobs', params:{jobId: id, time: time}})
};
JobManager.prototype.updatePredictionOnFinish = function(id,type,time,prediction,elapsedTime) {
if (prediction.mean != 0) {
var predictedTimeLeft = prediction.mean - elapsedTime;
if (predictedTimeLeft > 0) {
this.agent.timelineDataset.remove({id: id + "_predMean" + this.jobs.id[id].predictionCounter})
}
}
};
JobManager.prototype.updateJobs = function(time, skipId) {
var updateQuery = [];
for (var jobId in this.openJobs) {
if (this.openJobs.hasOwnProperty(jobId) && jobId != skipId) {
var type = this.openJobs[jobId].type;
var prediction = this.openJobs[jobId].prediction;
var predictedTimeLeft = 0;
// never been paused before
if (this.jobs.id[jobId].pauseCount == 0) {
if (prediction !== null && prediction.duration !== null) {
predictedTimeLeft = prediction.duration.mean - this.jobs.id[jobId].elapsedTime;
}
}
else {
if (prediction !== null && prediction.durationWithPause !== null) {
predictedTimeLeft = prediction.durationWithPause.mean - this.jobs.id[jobId].elapsedTimeWithPause;
}
}
updateQuery.push({id: jobId, end: time, content: type, type: 'range'});
if (this.openJobs[jobId].paused == true) {
updateQuery.push({id: this.openJobs[jobId].pauseAreaID, end: time});
}
}
}
this.agent.timelineDataset.update(updateQuery);
};
JobManager.prototype.generateColors = function(predictedTime, elapsedTime) {
var ratio = (elapsedTime + predictedTime) / elapsedTime;
if (ratio > 1) {
ratio = Math.min(2,ratio) - 1; // 2 -- 1
var rgb = HSVToRGB(94/360,ratio*0.6 + 0.2,1);
}
else {
ratio = Math.max(0.5,ratio) - 0.5; // 1 -- 0.5
var rgb = HSVToRGB(40/360,(1-(2*ratio))*0.6 + 0.1 ,1);
}
return "rgb(" + rgb.r + "," + rgb.g + "," + rgb.b + ")";
};
function HSVToRGB(h, s, v) {
var r, g, b;
var i = Math.floor(h * 6);
var f = h * 6 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return {r:Math.floor(r * 255), g:Math.floor(g * 255), b:Math.floor(b * 255) };
}
function RGBToHSV (red,green,blue) {
red=red/255; green=green/255; blue=blue/255;
var minRGB = Math.min(red,Math.min(green,blue));
var maxRGB = Math.max(red,Math.max(green,blue));
// Black-gray-white
if (minRGB == maxRGB) {
return {h:0,s:0,v:minRGB};
}
// Colors other than black-gray-white:
var d = (red==minRGB) ? green-blue : ((blue==minRGB) ? red-green : blue-red);
var h = (red==minRGB) ? 3 : ((blue==minRGB) ? 1 : 5);
var hue = 60*(h - d/(maxRGB - minRGB))/360;
var saturation = (maxRGB - minRGB)/maxRGB;
var value = maxRGB;
return {h:hue,s:saturation,v:value};
}

+ 301
- 0
showcase/projects/midas/css/global.css View File

@ -0,0 +1,301 @@
body {
font-family : Verdana, "Bitstream Vera Sans", "DejaVu Sans", Tahoma, Geneva, Arial, Sans-serif;
font-size: 13px;
min-width:980px;
}
div.group {
background-color: rgba(0, 0, 0, 0.005);
}
/*.vis.timeline .item.background {*/
/*background-color: rgba(40, 148, 255, 0.20) !important;*/
/*z-index:9999 !important;*/
/*}*/
.vis.timeline .item.range.prediction {
border: 1px solid rgba(0, 164, 255, 0.50) !important;
background-color: rgba(28, 183, 255, 0.10) !important;
box-shadow: rgba(0, 83, 128, 0.15) 0px 0px 10px !important;
z-index:-1 !important;
height:34px !important;
}
.vis.timeline .item.background.night {
background-color: rgba(60, 60, 60, 0.3) !important;
z-index:9999 !important;
}
.vis.timeline .labelset .timelineGroup .inner {
/*height:100px !important;*/
width:140px !important;
}
.vis.timeline .labelset .timelineGroup.worker{
background-color: #ffffff;
}
.vis.timeline .labelset .timelineGroup.rao{
background-color: #f5f5f5;
}
.vis.timeline .labelset .timelineGroup.pm{
background-color: #dfeaf2;
}
.vis.timeline .labelset .timelineGroup.mt{
background-color: #b8d6e6;
}
.vis.timeline .item.range {
height:34px !important;
}
.vis.timeline .item.range.pause{
height:34px !important;
width:26px !important;
box-shadow: rgba(0,0,0,0.2) 0px 0px 10px !important;
padding:3px !important;
z-index:999999;
background-color: #ffffff !important
}
.vis.timeline .item.range.pausedArea{
height:34px !important;
padding:3px !important;
z-index:999950;
border-width: 0px !important;
background: url('../images/shaded.png');
background-color: rgba(0,0,0,0) !important;
}
.vis.timeline .item {
border-radius: 0px !important;
border-color: #7d807d !important;
background-color: #ffffff !important;
/*background-color: #c4e0ff !important;*/
}
.vis.timeline .item.box {
height:22px !important;
border-radius: 0px !important;
border-color: #7d807d !important;
background-color: #ffffff !important;
box-shadow: rgba(0, 0, 0, 0.52) 0px 0px 12px 0px;
}
img.icon{
width:16px;
height:16px;
}
#multiselect {
position:relative;
top:1px;
width:200px;
height:452px;
}
table.wrapper {
position:relative;
height:500px;
width:100%;
}
/*table.wrapper td {*/
/*border:1px solid #ff0000;*/
/*}*/
#selectTD {
width:200px;
}
div.typeButtons {
height:50px;
width:100%;
overflow:hidden;
}
div.typeButton {
display:inline-block;
width:150px;
height:24px;
border:2px solid #ffffff;
border-radius: 40px;
text-align:center;
font-size:12px;
color: #848484;
padding-top:8px;
background-color: #dedede;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor:pointer;
margin:5px;
box-shadow: rgba(50,50,50,0.3) 0px 0px 3px;
}
div.typeButton.selected {
background-color: #9aff4d;
color: #000000;
}
div.toggleButton {
background-image: url("../images/toggleOff.png");
background-repeat: no-repeat;
background-position: 2px 2px;
display:inline-block;
width:138px;
height:24px;
font-size:12px;
border:1px solid #d0d0d0;
text-align:left;
padding-top:10px;
padding-left:60px;
padding-right:0px;
border-radius: 40px;
background-color: #ffffff;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor:pointer;
}
div.toggleButton.square{
height:28px;
border-radius: 0px;
}
div.toggleButton.selected {
background-image: url("../images/toggleOn.png");
background-color: #ffffff;
}
div.graph2dContent{
height:450px;
width:100%;
}
#graphWrapper {
display:none;
border: 1px solid #dddddd;
padding:5px;
}
#timelineWrapper {
display:block;
border: 1px solid #dddddd;
padding:5px;
}
.prediction_original {
fill: rgb(123, 199, 255);
fill-opacity:0;
stroke-width:2px;
stroke: rgb(123, 199, 255);
}
.prediction {
fill: #77da2e;
fill-opacity:0;
stroke-width:2px;
stroke: #77da2e;
}
.duration {
fill: rgb(170, 34, 206);
fill-opacity:0;
stroke-width:2px;
stroke: rgb(170, 34, 206);
}
.fill {
fill-opacity:0.1;
stroke: none;
}
.bar {
fill-opacity:0.5;
stroke-width:1px;
}
.point {
stroke-width:2px;
fill-opacity:1.0;
}
.legendBackground {
stroke-width:1px;
fill-opacity:0.9;
fill: #ffffff;
stroke: #c2c2c2;
}
.outline {
stroke-width:1px;
fill-opacity:1;
fill: #ffffff;
stroke: #e5e5e5;
}
.iconFill {
fill-opacity:0.3;
stroke: none;
}
div.descriptionContainer {
float:left;
height:30px;
min-width:160px;
padding-left:5px;
padding-right:5px;
line-height: 30px;
}
div.iconContainer {
float:left;
}
div.legendElementContainer {
display:inline-block;
height:30px;
border-style:solid;
border-width:1px;
border-color: #d0d0d0;
background-color: #ffffff;
margin-right:6px;
padding:4px;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor:pointer;
}
svg.legendIcon {
width:30px;
height:30px;
}
div.externalLegend {
position:relative;
top:1px;
width: 700px;
}
.differencePositive {
fill: #afff33;
stroke-width:2px;
stroke: #96db22;
}
.differenceNegative {
fill: #ff9f00;
stroke-width:2px;
stroke: #e58f00;
}

+ 745
- 0
showcase/projects/midas/css/vis.css View File

@ -0,0 +1,745 @@
.vis .overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
/* Must be displayed above for example selected Timeline items */
z-index: 10;
}
.vis-active {
box-shadow: 0 0 10px #86d5f8;
}
.vis.timeline {
}
.vis.timeline.root {
position: relative;
border: 1px solid #bfbfbf;
overflow: hidden;
padding: 0;
margin: 0;
box-sizing: border-box;
}
.vis.timeline .vispanel {
position: absolute;
padding: 0;
margin: 0;
box-sizing: border-box;
}
.vis.timeline .vispanel.center,
.vis.timeline .vispanel.left,
.vis.timeline .vispanel.right,
.vis.timeline .vispanel.top,
.vis.timeline .vispanel.bottom {
border: 1px #bfbfbf;
}
.vis.timeline .vispanel.center,
.vis.timeline .vispanel.left,
.vis.timeline .vispanel.right {
border-top-style: solid;
border-bottom-style: solid;
overflow: hidden;
}
.vis.timeline .vispanel.center,
.vis.timeline .vispanel.top,
.vis.timeline .vispanel.bottom {
border-left-style: solid;
border-right-style: solid;
}
.vis.timeline .background {
overflow: hidden;
}
.vis.timeline .vispanel > .content {
position: relative;
}
.vis.timeline .vispanel .shadow {
position: absolute;
width: 100%;
height: 1px;
box-shadow: 0 0 10px rgba(0,0,0,0.8);
/* TODO: find a nice way to ensure shadows are drawn on top of items
z-index: 1;
*/
}
.vis.timeline .vispanel .shadow.top {
top: -1px;
left: 0;
}
.vis.timeline .vispanel .shadow.bottom {
bottom: -1px;
left: 0;
}
.vis.timeline .labelset {
position: relative;
width: 100%;
overflow: hidden;
box-sizing: border-box;
}
.vis.timeline .labelset .vlabel {
position: relative;
left: 0;
top: 0;
width: 100%;
color: #4d4d4d;
box-sizing: border-box;
}
.vis.timeline .labelset .vlabel {
border-bottom: 1px solid #bfbfbf;
}
.vis.timeline .labelset .vlabel:last-child {
border-bottom: none;
}
.vis.timeline .labelset .vlabel .inner {
display: inline-block;
padding: 5px;
}
.vis.timeline .labelset .vlabel .inner.hidden {
padding: 0;
}
.vis.timeline .itemset {
position: relative;
padding: 0;
margin: 0;
box-sizing: border-box;
}
.vis.timeline .itemset .background,
.vis.timeline .itemset .foreground {
position: absolute;
width: 100%;
height: 100%;
overflow: visible;
}
.vis.timeline .axis {
position: absolute;
width: 100%;
height: 0;
left: 0;
z-index: 1;
}
.vis.timeline .foreground .group {
position: relative;
box-sizing: border-box;
border-bottom: 1px solid #bfbfbf;
}
.vis.timeline .foreground .group:last-child {
border-bottom: none;
}
.vis.timeline .item {
position: absolute;
color: #1A1A1A;
border-color: #97B0F8;
border-width: 1px;
background-color: #D5DDF6;
display: inline-block;
padding: 5px;
}
.vis.timeline .item.selected {
border-color: #FFC200;
background-color: #FFF785;
/* z-index must be higher than the z-index of custom time bar and current time bar */
z-index: 2;
}
.vis.timeline .editable .item.selected {
cursor: move;
}
.vis.timeline .item.point.selected {
background-color: #FFF785;
}
.vis.timeline .item.box {
text-align: center;
border-style: solid;
border-radius: 2px;
}
.vis.timeline .item.point {
background: none;
}
.vis.timeline .item.dot {
position: absolute;
padding: 0;
border-width: 4px;
border-style: solid;
border-radius: 4px;
}
.vis.timeline .item.range {
border-style: solid;
border-radius: 2px;
box-sizing: border-box;
}
.vis.timeline .item.background {
overflow: hidden;
border: none;
background-color: rgba(213, 221, 246, 0.4);
box-sizing: border-box;
padding: 0;
margin: 0;
}
.vis.timeline .item.range .content {
position: relative;
display: inline-block;
overflow: hidden;
max-width: 100%;
}
.vis.timeline .item.background .content {
position: absolute;
display: inline-block;
overflow: hidden;
max-width: 100%;
margin: 5px;
}
.vis.timeline .item.line {
padding: 0;
position: absolute;
width: 0;
border-left-width: 1px;
border-left-style: solid;
}
.vis.timeline .item .content {
white-space: nowrap;
overflow: hidden;
}
.vis.timeline .item .delete {
background: url('img/timeline/delete.png') no-repeat top center;
position: absolute;
width: 24px;
height: 24px;
top: 0;
right: -24px;
cursor: pointer;
}
.vis.timeline .item.range .drag-left {
position: absolute;
width: 24px;
height: 100%;
top: 0;
left: -4px;
cursor: w-resize;
}
.vis.timeline .item.range .drag-right {
position: absolute;
width: 24px;
height: 100%;
top: 0;
right: -4px;
cursor: e-resize;
}
.vis.timeline .timeaxis {
position: relative;
overflow: hidden;
}
.vis.timeline .timeaxis.foreground {
top: 0;
left: 0;
width: 100%;
}
.vis.timeline .timeaxis.background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.vis.timeline .timeaxis .text {
position: absolute;
color: #4d4d4d;
padding: 3px;
white-space: nowrap;
}
.vis.timeline .timeaxis .text.measure {
position: absolute;
padding-left: 0;
padding-right: 0;
margin-left: 0;
margin-right: 0;
visibility: hidden;
}
.vis.timeline .timeaxis .grid.vertical {
position: absolute;
width: 0;
border-right: 1px solid;
}
.vis.timeline .timeaxis .grid.minor {
border-color: #e5e5e5;
}
.vis.timeline .timeaxis .grid.major {
border-color: #bfbfbf;
}
.vis.timeline .currenttime {
background-color: #FF7F6E;
width: 2px;
z-index: 1;
}
.vis.timeline .customtime {
background-color: #6E94FF;
width: 2px;
cursor: move;
z-index: 1;
}
.vis.timeline.root {
/*
-webkit-transition: height .4s ease-in-out;
transition: height .4s ease-in-out;
*/
}
.vis.timeline .vispanel {
/*
-webkit-transition: height .4s ease-in-out, top .4s ease-in-out;
transition: height .4s ease-in-out, top .4s ease-in-out;
*/
}
.vis.timeline .axis {
/*
-webkit-transition: top .4s ease-in-out;
transition: top .4s ease-in-out;
*/
}
/* TODO: get animation working nicely
.vis.timeline .item {
-webkit-transition: top .4s ease-in-out;
transition: top .4s ease-in-out;
}
.vis.timeline .item.line {
-webkit-transition: height .4s ease-in-out, top .4s ease-in-out;
transition: height .4s ease-in-out, top .4s ease-in-out;
}
/**/
.vis.timeline .vispanel.background.horizontal .grid.horizontal {
position: absolute;
width: 100%;
height: 0;
border-bottom: 1px solid;
}
.vis.timeline .vispanel.background.horizontal .grid.minor {
border-color: #e5e5e5;
}
.vis.timeline .vispanel.background.horizontal .grid.major {
border-color: #bfbfbf;
}
.vis.timeline .dataaxis .yAxis.major {
width: 100%;
position: absolute;
color: #4d4d4d;
white-space: nowrap;
}
.vis.timeline .dataaxis .yAxis.major.measure{
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
visibility: hidden;
width: auto;
}
.vis.timeline .dataaxis .yAxis.minor{
position: absolute;
width: 100%;
color: #bebebe;
white-space: nowrap;
}
.vis.timeline .dataaxis .yAxis.minor.measure{
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
visibility: hidden;
width: auto;
}
.vis.timeline .legend {
background-color: rgba(247, 252, 255, 0.65);
padding: 5px;
border-color: #b3b3b3;
border-style:solid;
border-width: 1px;
box-shadow: 2px 2px 10px rgba(154, 154, 154, 0.55);
}
.vis.timeline .legendText {
/*font-size: 10px;*/
white-space: nowrap;
display: inline-block
}
.vis.timeline .graphGroup0 {
fill:#4f81bd;
fill-opacity:0;
stroke-width:2px;
stroke: #4f81bd;
}
.vis.timeline .graphGroup1 {
fill:#f79646;
fill-opacity:0;
stroke-width:2px;
stroke: #f79646;
}
.vis.timeline .graphGroup2 {
fill: #8c51cf;
fill-opacity:0;
stroke-width:2px;
stroke: #8c51cf;
}
.vis.timeline .graphGroup3 {
fill: #75c841;
fill-opacity:0;
stroke-width:2px;
stroke: #75c841;
}
.vis.timeline .graphGroup4 {
fill: #ff0100;
fill-opacity:0;
stroke-width:2px;
stroke: #ff0100;
}
.vis.timeline .graphGroup5 {
fill: #37d8e6;
fill-opacity:0;
stroke-width:2px;
stroke: #37d8e6;
}
.vis.timeline .graphGroup6 {
fill: #042662;
fill-opacity:0;
stroke-width:2px;
stroke: #042662;
}
.vis.timeline .graphGroup7 {
fill:#00ff26;
fill-opacity:0;
stroke-width:2px;
stroke: #00ff26;
}
.vis.timeline .graphGroup8 {
fill:#ff00ff;
fill-opacity:0;
stroke-width:2px;
stroke: #ff00ff;
}
.vis.timeline .graphGroup9 {
fill: #8f3938;
fill-opacity:0;
stroke-width:2px;
stroke: #8f3938;
}
.vis.timeline .fill {
fill-opacity:0.1;
stroke: none;
}
.vis.timeline .bar {
fill-opacity:0.5;
stroke-width:1px;
}
.vis.timeline .point {
stroke-width:2px;
fill-opacity:1.0;
}
.vis.timeline .legendBackground {
stroke-width:1px;
fill-opacity:0.9;
fill: #ffffff;
stroke: #c2c2c2;
}
.vis.timeline .outline {
stroke-width:1px;
fill-opacity:1;
fill: #ffffff;
stroke: #e5e5e5;
}
.vis.timeline .iconFill {
fill-opacity:0.3;
stroke: none;
}
div.network-manipulationDiv {
border-width: 0;
border-bottom: 1px;
border-style:solid;
border-color: #d6d9d8;
background: #ffffff; /* Old browsers */
background: -moz-linear-gradient(top, #ffffff 0%, #fcfcfc 48%, #fafafa 50%, #fcfcfc 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(48%,#fcfcfc), color-stop(50%,#fafafa), color-stop(100%,#fcfcfc)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* IE10+ */
background: linear-gradient(to bottom, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#fcfcfc',GradientType=0 ); /* IE6-9 */
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 30px;
}
div.network-manipulation-editMode {
position:absolute;
left: 0;
top: 0;
height: 30px;
margin-top:20px;
}
div.network-manipulation-closeDiv {
position:absolute;
right: 0;
top: 0;
width: 30px;
height: 30px;
background-position: 20px 3px;
background-repeat: no-repeat;
background-image: url("img/network/cross.png");
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
div.network-manipulation-closeDiv:hover {
opacity: 0.6;
}
span.network-manipulationUI {
font-family: verdana;
font-size: 12px;
-moz-border-radius: 15px;
border-radius: 15px;
display:inline-block;
background-position: 0px 0px;
background-repeat:no-repeat;
height:24px;
margin: -14px 0px 0px 10px;
vertical-align:middle;
cursor: pointer;
padding: 0px 8px 0px 8px;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
span.network-manipulationUI:hover {
box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.20);
}
span.network-manipulationUI:active {
box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.50);
}
span.network-manipulationUI.back {
background-image: url("img/network/backIcon.png");
}
span.network-manipulationUI.none:hover {
box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.0);
cursor: default;
}
span.network-manipulationUI.none:active {
box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.0);
}
span.network-manipulationUI.none {
padding: 0;
}
span.network-manipulationUI.notification{
margin: 2px;
font-weight: bold;
}
span.network-manipulationUI.add {
background-image: url("img/network/addNodeIcon.png");
}
span.network-manipulationUI.edit {
background-image: url("img/network/editIcon.png");
}
span.network-manipulationUI.edit.editmode {
background-color: #fcfcfc;
border-style:solid;
border-width:1px;
border-color: #cccccc;
}
span.network-manipulationUI.connect {
background-image: url("img/network/connectIcon.png");
}
span.network-manipulationUI.delete {
background-image: url("img/network/deleteIcon.png");
}
/* top right bottom left */
span.network-manipulationLabel {
margin: 0px 0px 0px 23px;
line-height: 25px;
}
div.network-seperatorLine {
display:inline-block;
width:1px;
height:20px;
background-color: #bdbdbd;
margin: 5px 7px 0px 15px;
}
div.network-navigation_wrapper {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
div.network-navigation {
width:34px;
height:34px;
-moz-border-radius: 17px;
border-radius: 17px;
position:absolute;
display:inline-block;
background-position: 2px 2px;
background-repeat:no-repeat;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
div.network-navigation:hover {
box-shadow: 0px 0px 3px 3px rgba(56, 207, 21, 0.30);
}
div.network-navigation:active {
box-shadow: 0px 0px 1px 3px rgba(56, 207, 21, 0.95);
}
div.network-navigation.up {
background-image: url("img/network/upArrow.png");
bottom:50px;
left:55px;
}
div.network-navigation.down {
background-image: url("img/network/downArrow.png");
bottom:10px;
left:55px;
}
div.network-navigation.left {
background-image: url("img/network/leftArrow.png");
bottom:10px;
left:15px;
}
div.network-navigation.right {
background-image: url("img/network/rightArrow.png");
bottom:10px;
left:95px;
}
div.network-navigation.zoomIn {
background-image: url("img/network/plus.png");
bottom:10px;
right:15px;
}
div.network-navigation.zoomOut {
background-image: url("img/network/minus.png");
bottom:10px;
right:55px;
}
div.network-navigation.zoomExtends {
background-image: url("img/network/zoomExtends.png");
bottom:50px;
right:15px;
}

BIN
showcase/projects/midas/images/arum.png View File

Before After
Width: 340  |  Height: 115  |  Size: 27 KiB

BIN
showcase/projects/midas/images/arum_small.png View File

Before After
Width: 266  |  Height: 90  |  Size: 31 KiB

BIN
showcase/projects/midas/images/control_pause.png View File

Before After
Width: 16  |  Height: 16  |  Size: 598 B

BIN
showcase/projects/midas/images/control_pause_blue.png View File

Before After
Width: 16  |  Height: 16  |  Size: 721 B

BIN
showcase/projects/midas/images/control_play.png View File

Before After
Width: 16  |  Height: 16  |  Size: 592 B

BIN
showcase/projects/midas/images/control_play_blue.png View File

Before After
Width: 16  |  Height: 16  |  Size: 717 B

BIN
showcase/projects/midas/images/midas_big.png View File

Before After
Width: 600  |  Height: 180  |  Size: 36 KiB

BIN
showcase/projects/midas/images/midas_small.png View File

Before After
Width: 340  |  Height: 102  |  Size: 32 KiB

BIN
showcase/projects/midas/images/moon.png View File

Before After
Width: 16  |  Height: 16  |  Size: 18 KiB

BIN
showcase/projects/midas/images/shaded.png View File

Before After
Width: 15  |  Height: 34  |  Size: 18 KiB

BIN
showcase/projects/midas/images/sun.png View File

Before After
Width: 16  |  Height: 16  |  Size: 18 KiB

BIN
showcase/projects/midas/images/toggleOff.png View File

Before After
Width: 52  |  Height: 30  |  Size: 20 KiB

BIN
showcase/projects/midas/images/toggleOn.png View File

Before After
Width: 52  |  Height: 30  |  Size: 20 KiB

+ 86
- 0
showcase/projects/midas/index.html View File

@ -0,0 +1,86 @@
<!doctype html>
<html>
<head>
<title>ARUM - MIDAS</title>
<link href="./css/global.css" rel="stylesheet" type="text/css" />
<link href="./css/vis.css" rel="stylesheet" type="text/css" />
<script language="javascript">
var EVENT_DELAY = 1000;
var EVENTS_AGENT_ADDRESS = 'ws://localhost:8082/ws/events';
var AMOUNT_OF_INITIAL_EVENTS = 1;
var TIMELINE_START = '2014-09-18 10:00:00';
var TIMELINE_END = '2014-09-19 18:00:00';
var INCREASE_SPEED = true;
var ONLINE_ONLY = true;
</script>
<script type="text/javascript" src="./js/vis.js"></script>
<script type="text/javascript" src="./js/evejs.js"></script>
<script type="text/javascript" src="./arumAgents/job.js"></script>
<script type="text/javascript" src="./arumAgents/durationStats.js"></script>
<script type="text/javascript" src="./arumAgents/durationData.js"></script>
<script type="text/javascript" src="./arumAgents/jobManager.js"></script>
<script type="text/javascript" src="./arumAgents/jobAgent.js"></script>
<script type="text/javascript" src="./js/vis_eve_init.js"></script>
<script type="text/javascript" src="./arumAgents/genericAgent.js"></script>
<script type="text/javascript" src="./arumAgents/agentGenerator.js"></script>
<script type="text/javascript" src="./arumAgents/jobAgentGenerator.js"></script>
<script type="text/javascript" src="./arumAgents/eventGenerator.js"></script>
<script type="text/javascript" src="./js/init.js"></script>
</head>
<body onload="draw()">
<img src="./images/arum_small.png" style="position:relative; top:-6px;"><img src="./images/midas_small.png" style="float:right;"><br>
<div class="typeButton selected" onclick="showTimelineBtn()" id="showTimeline">Show by Timeline</div>
<div class="typeButton" onclick="showGraphBtn()" id="showGraph">Show by Job</div>
<div id="timelineWrapper">
<input type="button" value="Next Event" onclick="getNewEvent()">
eventNo:<div id="eventCounter" style="display:inline;">-1</div>
<input type="button" value="Next 10 Events" onclick="getTenNewEvents()">
<input type="button" value="Get All Events" onclick="getAllEvents()">
<input type="button" value="Get All Events Quickly" onclick="getAllEventsQuickly()"> <br>
<div id="timeline"></div>
</div>
<div id="graphWrapper">
<table class="wrapper">
<tr>
<td>
<div class="toggleButton" onclick="togglePrediction()" id="togglePrediction">Prediction</div>
</td>
<td width="6px">&nbsp;</td>
<td>
<div class="typeButton selected" onclick="turnOn('duration')" id="duration">Ideal</div>
<div class="typeButton" onclick="turnOn('durationWithPause')" id="durationWithPause">Ideal + Pause</div>
<div class="typeButton" onclick="turnOn('durationWithStartup')" id="durationWithStartup">Ideal + Prerequisites</div>
<div class="typeButton" onclick="turnOn('durationWithBoth')" id="durationWithBoth">Total Time</div>
</td>
</tr>
<tr>
<td id="selectTD">
<select name="jobs" id="multiselect" multiple onclick="updateGraph()"></select>
</td>
<td colspan="2">
<div class="graph2dContent">
<div id="graph2d"></div>
</div>
</td>
</tr>
<tr>
<td>
<div class="toggleButton square" onclick="toggleDifference()" id="difference">Switch View</div>
</td>
<td colspan="2">
<div id="Legend" class="externalLegend"></div>
</td>
</tr>
</table>
</div>
<p id="selection"></p>
<p id="stabilization"></p>
</body>
</html>

+ 31161
- 0
showcase/projects/midas/js/evejs.js
File diff suppressed because it is too large
View File


+ 350
- 0
showcase/projects/midas/js/init.js View File

@ -0,0 +1,350 @@
/**
* Created by Alex on 10/27/2014.
*/
var GETTING_EVENTS = false;
var agentList = {};
var jobList = {};
var eventGen = new EventGenerator("eventGenerator");
var agentGen = new AgentGenerator("agentGenerator");
var jobGen = new JobAgentGenerator("jobAgentGenerator");
// eventGen.start();
function getNewEvent() {
agentGen.getEvents(1);
}
function getTenNewEvents() {
agentGen.getEvents(10);
}
function getAllEvents() {
if (GETTING_EVENTS == false) {
GETTING_EVENTS = true;
agentGen.getEvents(agentGen.amountOfEvents);
}
}
function getAllEventsQuickly() {
INCREASE_SPEED = false;
EVENT_DELAY = 0;
if (GETTING_EVENTS == false) {
GETTING_EVENTS = true;
agentGen.getEvents(agentGen.amountOfEvents);
}
else {
}
}
function refreshJobs() {
var multiSelect = document.getElementById("multiselect");
while (multiSelect.firstChild) {
multiSelect.removeChild(multiSelect.firstChild);
}
var jobNames = jobGen.getAllJobNames();
for (var i = 0; i < jobNames.length; i++) {
var jobOption = new Option(jobNames[i], jobNames[i]);
multiSelect.appendChild(jobOption);
}
}
function updateGraph() {
var multiSelect = document.getElementById("multiselect");
var selection = [];
for (var i = 0; i < multiSelect.children.length; i++) {
if (multiSelect.children[i].selected) {
selection.push(multiSelect.children[i].value);
}
}
var filteredValues = [];
var originalPredictionValues = [];
var durationValues = [];
var predictionValues = [];
var diffValues = [];
var graphGroup = null;
var stdGroup = null;
var predictionGroup = null;
var originalPredictionGroup = null;
for (var i = 0; i < graph2dDataset.length; i++) {
if (selection.indexOf(graph2dDataset[i].type) != -1) {
if (showDuration == true) {
if (graph2dDataset[i].group == graph2dDataset[i].type + "_" + selectedGroup) {
filteredValues.push(graph2dDataset[i]);
durationValues.push(graph2dDataset[i]);
graphGroup = graph2dDataset[i].group;
}
}
if (showPrediction == true) {
if (graph2dDataset[i].group == graph2dDataset[i].type + "_pred_" + selectedGroup) {
filteredValues.push(graph2dDataset[i]);
predictionValues.push(graph2dDataset[i]);
predictionGroup = graph2dDataset[i].group;
}
if (graph2dDataset[i].group == graph2dDataset[i].type + "_pred_" + selectedGroup + "_std_higher") {
filteredValues.push(graph2dDataset[i]);
stdGroup = graph2dDataset[i].group;
}
if (graph2dDataset[i].group == graph2dDataset[i].type + "_pred_" + selectedGroup + "_std_lower") {
filteredValues.push(graph2dDataset[i]);
stdGroup = graph2dDataset[i].group;
}
if (graph2dDataset[i].group == graph2dDataset[i].type + "_pred_" + selectedGroup + "_original") {
filteredValues.push(graph2dDataset[i]);
originalPredictionValues.push(graph2dDataset[i]);
originalPredictionGroup = graph2dDataset[i].group;
}
}
}
}
graph2DItems.clear();
if (differenceWithPrediction == true) {
for (var i = 0; i < durationValues.length; i++) {
var item = {};
item.x = i < 10 ? '2014-09-0' + i : '2014-09-' + i;
item.y = durationValues[i].y;
item.type = durationValues[i].type;
item.y -= originalPredictionValues[i].y;
var group = 'differenceNegative';
if (item.y < 0) {
item.y *= -1;
group = 'differencePositive'
}
item.group = group;
diffValues.push(item);
}
var legendDiv = document.getElementById("Legend");
legendDiv.innerHTML = "";
populateExternalLegend('differencePositive', "Faster than predicted (hours)");
populateExternalLegend('differenceNegative', "Slower than predicted (hours)");
graph2DItems.add(diffValues);
}
else {
var filteredValues = [];
for (var i = 0; i < durationValues.length; i++) {
var durationItem = {};
durationItem.x = i < 10 ? '2014-09-0' + i : '2014-09-' + i;
durationItem.y = durationValues[i].y;
durationItem.type = durationValues[i].type;
durationItem.group = durationValues[i].group;
filteredValues.push(durationItem);
if (showPrediction == true) {
var predItem = {};
predItem.x = i < 10 ? '2014-09-0' + i : '2014-09-' + i;
predItem.y = predictionValues[i].y;
predItem.type = predictionValues[i].type;
predItem.group = predictionValues[i].group;
filteredValues.push(predItem);
var originalPred = {};
originalPred.x = i < 10 ? '2014-09-0' + i : '2014-09-' + i;
originalPred.y = originalPredictionValues[i].y;
originalPred.type = originalPredictionValues[i].type;
originalPred.group = originalPredictionValues[i].group;
filteredValues.push(originalPred);
}
}
var legendDiv = document.getElementById("Legend");
legendDiv.innerHTML = "";
if (graphGroup != null) {
populateExternalLegend(graphGroup, "duration (hours)");
}
// if (stdGroup != null) {populateExternalLegend(stdGroup, "standard deviation");}
if (predictionGroup != null) {
populateExternalLegend(predictionGroup, "updated prediction (hours)");
}
if (originalPredictionGroup != null) {
populateExternalLegend(originalPredictionGroup, "initial prediction (hours)");
}
graph2DItems.add(filteredValues);
}
graph2d.fit();
}
function turnOff(type) {
var btn = document.getElementById(type);
btn.className = btn.className.replace(" selected", "");
}
function turnOffAll() {
var types = ['duration', 'durationWithPause', 'durationWithStartup', 'durationWithBoth'];
for (var i = 0; i < types.length; i++) {
turnOff(types[i]);
}
}
function turnOn(type) {
turnOffAll();
var btn = document.getElementById(type);
selectedGroup = type;
btn.className += " selected";
updateGraph();
}
function togglePrediction() {
if (differenceWithPrediction != true) {
var btn = document.getElementById('togglePrediction');
if (showPrediction == true) {
btn.className = btn.className.replace("selected", "");
showPrediction = false;
}
else {
showPrediction = true;
btn.className += " selected";
}
updateGraph();
}
}
function toggleDuration() {
if (differenceWithPrediction != true) {
var btn = document.getElementById('toggleDuration');
if (showDuration == true) {
btn.className = btn.className.replace("selected", "");
showDuration = false;
}
else {
showDuration = true;
btn.className += " selected";
}
updateGraph();
}
}
function toggleDifference() {
differenceWithPrediction = !differenceWithPrediction;
var btn = document.getElementById('togglePrediction');
if (showPrediction == false && differenceWithPrediction == true) {
showPrediction = true;
btn.className += " selected";
}
btn = document.getElementById('toggleDuration');
if (showDuration == false && differenceWithPrediction == true) {
showDuration = true;
btn.className += " selected";
}
var btn2 = document.getElementById('difference');
if (differenceWithPrediction == false) {
btn2.className = btn2.className.replace("selected", "");
}
else {
btn2.className += " selected";
}
updateGraph();
}
function showTimelineBtn() {
var timelineBtn = document.getElementById('showTimeline');
var graphBtn = document.getElementById('showGraph');
if (showTimeline == false) {
graphBtn.className = graphBtn.className.replace("selected", "");
timelineBtn.className += " selected";
var timelinewrapper = document.getElementById("timelineWrapper");
var graphwrapper = document.getElementById("graphWrapper");
graphwrapper.style.display = "none";
timelinewrapper.style.display = "block";
showTimeline = true;
showGraph = false;
}
}
function showGraphBtn() {
var timelineBtn = document.getElementById('showTimeline');
var graphBtn = document.getElementById('showGraph');
if (showGraph == false) {
timelineBtn.className = graphBtn.className.replace("selected", "");
graphBtn.className += " selected";
var timelinewrapper = document.getElementById("timelineWrapper");
var graphwrapper = document.getElementById("graphWrapper");
timelinewrapper.style.display = "none";
graphwrapper.style.display = "block";
showTimeline = false;
showGraph = true;
}
}
/**
* this function fills the external legend with content using the getLegend() function.
*/
function populateExternalLegend(groupDataItem, description) {
var legendDiv = document.getElementById("Legend");
// create divs
var containerDiv = document.createElement("div");
var iconDiv = document.createElement("div");
var descriptionDiv = document.createElement("div");
// give divs classes and Ids where necessary
containerDiv.className = 'legendElementContainer';
containerDiv.id = groupDataItem + "_legendContainer";
iconDiv.className = "iconContainer";
descriptionDiv.className = "descriptionContainer";
// get the legend for this group.
var legend = graph2d.getLegend(groupDataItem, 30, 30);
// append class to icon. All styling classes from the vis.css have been copied over into the head here to be able to style the
// icons with the same classes if they are using the default ones.
legend.icon.setAttributeNS(null, "class", "legendIcon");
// append the legend to the corresponding divs
iconDiv.appendChild(legend.icon);
descriptionDiv.innerHTML = description;
// determine the order for left and right orientation
if (legend.orientation == 'left') {
descriptionDiv.style.textAlign = "left";
containerDiv.appendChild(iconDiv);
containerDiv.appendChild(descriptionDiv);
}
else {
descriptionDiv.style.textAlign = "right";
containerDiv.appendChild(descriptionDiv);
containerDiv.appendChild(iconDiv);
}
// append to the legend container div
legendDiv.appendChild(containerDiv);
}
function printEvents(events) {
var str = "";
str += "[";
for (var i = 0; i < events.length; i++) {
str += "{";
var first = true;
for (var eventField in events[i]) {
if (events[i].hasOwnProperty(eventField)) {
if (first == false) {
str += ","
}
first = false;
if (eventField == "time") {
str += eventField + ": '" + new Date(events[i][eventField]).valueOf() + "'";
}
else if(events[i][eventField] instanceof Array) {
str += eventField + ": [";
for (var j = 0; j < events[i][eventField].length; j++) {
str += "'" + events[i][eventField][j] + "'";
if (j != events[i][eventField].length - 1) {
str += ",";
}
}
}
else {
str += eventField + ": '" + events[i][eventField] + "'";
}
}
}
str += "}";
if (i < events.length -1) {
str += ",";
}
}
str += "]";
console.log(str);
}

+ 33780
- 0
showcase/projects/midas/js/vis.js
File diff suppressed because it is too large
View File


+ 105
- 0
showcase/projects/midas/js/vis_eve_init.js View File

@ -0,0 +1,105 @@
/**
* Created by Alex on 10/27/2014.
*/
'use strict';
var timeline;
var timelineItems = new vis.DataSet();
var timelineGroups = new vis.DataSet();
var graph2d;
var graph2dDataset = [];
var graph2DItems = new vis.DataSet();
var graph2dGroups = new vis.DataSet();
graph2dGroups.add({
id: 'differencePositive', content: 'differencePositive', className: "differencePositive", options: {
drawPoints: false,
style: 'bar',
barChart: {width: 50, align: 'center'} // align: left, center, right
}
});
graph2dGroups.add({
id: 'differenceNegative', content: 'differenceNegative', className: "differenceNegative", options: {
drawPoints: false,
style: 'bar',
barChart: {width: 50, align: 'center'} // align: left, center, right
}
});
var eventCounter;
var selectedGroup = 'duration';
var showDuration = true;
var showPrediction = false;
var showTimeline = true;
var showGraph = false;
var differenceWithPrediction = false;
function draw() {
eventCounter = document.getElementById('eventCounter');
// add items to the DataSet
var timelineContainer = document.getElementById('timeline');
var timelineOptions = {
hiddenDates: [
{start: '2013-10-26 00:00:00', end: '2013-10-28 00:00:00', repeat: 'weekly'}, // daily weekly monthly yearly
{start: '2013-03-29 18:30:00', end: '2013-03-30 08:00:00', repeat: 'daily'} // daily weekly monthly yearly
],
start: TIMELINE_START,
end: TIMELINE_END,
autoResize: false,
showCustomTime: true,
showCurrentTime: false,
stack: false
};
timeline = new vis.Timeline(timelineContainer, timelineItems, timelineGroups, timelineOptions);
var graph2dContainer = document.getElementById('graph2d');
var graph2dOptions = {
style:'bar',
barChart: {width:50, align:'center', handleOverlap:'sideBySide'},
start: '2014-08-25',
end: '2014-09-25',
autoResize: false,
// height: '450px',
showCurrentTime: false,
catmullRom: false,
showMajorLabels: false,
showMinorLabels: false,
graphHeight:'450px',
dataAxis: {
customRange: {
left: {
min:-0.5
}
}
},
drawPoints:false //{style:'circle'}
};
graph2d = new vis.Graph2d(graph2dContainer, graph2DItems, graph2dGroups, graph2dOptions);
}
window.onresize = function () {
timeline.redraw();
graph2d.redraw();
}
var conn;
if (ONLINE_ONLY == true) {
eve.system.init({
transports: [
{
type: 'local'
}
]
});
}
else {
eve.system.init({
transports: [
{
type: 'ws'
}
]
});
}

+ 1
- 0
timeline_examples.html View File

@ -25,6 +25,7 @@
<style> <style>
body { body {
padding:10px; padding:10px;
font-family: Lustria,Georgia,Times,"Times New Roman",serif !important;
} }
pre { pre {

Loading…
Cancel
Save