Recode 'Task Completation Lead/Lag' chart using jqplot4java
FEA: ItEr76S15OrganizingPerProjectDashboard
This commit is contained in:
parent
a35a468530
commit
4664896693
2 changed files with 80 additions and 151 deletions
|
|
@ -27,6 +27,7 @@ import java.util.Collection;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
|
|
@ -45,12 +46,14 @@ import org.zkoss.zul.Window;
|
|||
|
||||
import br.com.digilabs.jqplot.Chart;
|
||||
import br.com.digilabs.jqplot.JqPlotUtils;
|
||||
import br.com.digilabs.jqplot.chart.BarChart;
|
||||
import br.com.digilabs.jqplot.chart.PieChart;
|
||||
import br.com.digilabs.jqplot.elements.Serie;
|
||||
|
||||
/**
|
||||
* @author Nacho Barrientos <nacho@igalia.com>
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*
|
||||
*
|
||||
* Controller for dashboardfororder view
|
||||
*/
|
||||
@Component
|
||||
|
|
@ -113,14 +116,27 @@ public class DashboardController extends GenericForwardComposer {
|
|||
}
|
||||
|
||||
private void renderTaskCompletationLag() {
|
||||
Map<Interval, Integer> taskCompletationData = dashboardModel
|
||||
.calculateTaskCompletation();
|
||||
TaskCompletationLag taskCompletation = TaskCompletationLag.create();
|
||||
for (Interval each : taskCompletationData.keySet()) {
|
||||
Integer value = taskCompletationData.get(each);
|
||||
taskCompletation.data(each.toString(), value);
|
||||
}
|
||||
taskCompletation.render();
|
||||
final String divId = "task-completation-lag";
|
||||
|
||||
BarChart<Integer> barChart;
|
||||
barChart = new BarChart<Integer>("Task Completation Lead/Lag");
|
||||
|
||||
barChart.setFillZero(true);
|
||||
barChart.setHighlightMouseDown(true);
|
||||
barChart.setStackSeries(false);
|
||||
barChart.setBarMargin(30);
|
||||
|
||||
barChart.addSeries(new Serie("Tasks"));
|
||||
|
||||
TaskCompletationData taskCompletationData = TaskCompletationData
|
||||
.create(dashboardModel);
|
||||
barChart.setTicks(taskCompletationData.getTicks());
|
||||
barChart.addValues(taskCompletationData.getValues());
|
||||
|
||||
barChart.getAxes().getXaxis()
|
||||
.setLabel(_("Number of Days / Days Interval"));
|
||||
|
||||
renderChart(barChart, divId);
|
||||
}
|
||||
|
||||
private void renderTasksSummary() {
|
||||
|
|
@ -189,9 +205,9 @@ public class DashboardController extends GenericForwardComposer {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*
|
||||
*
|
||||
*/
|
||||
static class GlobalProgress {
|
||||
|
||||
|
|
@ -262,7 +278,7 @@ public class DashboardController extends GenericForwardComposer {
|
|||
|
||||
/**
|
||||
* The order of the ticks is taken from the keys in current
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getTicks() {
|
||||
|
|
@ -279,9 +295,9 @@ public class DashboardController extends GenericForwardComposer {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*
|
||||
*
|
||||
*/
|
||||
static class Series {
|
||||
|
||||
|
|
@ -314,61 +330,48 @@ public class DashboardController extends GenericForwardComposer {
|
|||
|
||||
}
|
||||
|
||||
static class TaskCompletationLag {
|
||||
/**
|
||||
*
|
||||
* @author Diego Pino García<dpino@igalia.com>
|
||||
*
|
||||
*/
|
||||
static class TaskCompletationData {
|
||||
|
||||
private final String id = "task_completation_lag";
|
||||
private final IDashboardModel dashboardModel;
|
||||
|
||||
private final Map<String, Integer> data = new LinkedHashMap<String, Integer>();
|
||||
|
||||
private TaskCompletationLag() {
|
||||
private Map<Interval, Integer> taskCompletationData;
|
||||
|
||||
private TaskCompletationData(IDashboardModel dashboardModel) {
|
||||
this.dashboardModel = dashboardModel;
|
||||
}
|
||||
|
||||
public static TaskCompletationLag create() {
|
||||
return new TaskCompletationLag();
|
||||
public static TaskCompletationData create(IDashboardModel dashboardModel) {
|
||||
return new TaskCompletationData(dashboardModel);
|
||||
}
|
||||
|
||||
public void data(String interval, Integer value) {
|
||||
data.put(interval, value);
|
||||
private Map<Interval, Integer> getData() {
|
||||
if (taskCompletationData == null) {
|
||||
taskCompletationData = dashboardModel
|
||||
.calculateTaskCompletation();
|
||||
}
|
||||
return taskCompletationData;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
String _data = JSONHelper.values(data);
|
||||
String ticks = JSONHelper.keys(data);
|
||||
String command = String.format("%s.render(%s, %s);", id, _data,
|
||||
ticks);
|
||||
Clients.evalJavaScript(command);
|
||||
public String[] getTicks() {
|
||||
Set<Interval> intervals = getData().keySet();
|
||||
String[] result = new String[intervals.size()];
|
||||
int i = 0;
|
||||
for (Interval each : intervals) {
|
||||
result[i++] = each.toString();
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Collection<Integer> getValues() {
|
||||
return getData().values();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class JSONHelper {
|
||||
|
||||
public static String format(Map<String, Integer> data) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
for (String key : data.keySet()) {
|
||||
Integer value = data.get(data);
|
||||
result.add(String.format("[\"%s\", %d]", key, value));
|
||||
}
|
||||
return String.format("'[%s]'", StringUtils.join(result, ','));
|
||||
}
|
||||
|
||||
public static String keys(Map<String, ?> map) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
for (String each : map.keySet()) {
|
||||
result.add(String.format("\"%s\"", each));
|
||||
}
|
||||
return String.format("'[%s]'", StringUtils.join(result, ','));
|
||||
}
|
||||
|
||||
public static String values(Map<?, Integer> map) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
for (Integer each : map.values()) {
|
||||
result.add(each.toString());
|
||||
}
|
||||
return String.format("'[%s]'", StringUtils.join(result, ','));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
<!-- VERY IMPORTANT!!
|
||||
Don't include any HTML or Javascript code here because apparently this view, Dashboard view, will be rendered OK,
|
||||
but it creates a side effect in the other views. If you include HTML here, go to Dashboard and later to other view, a big
|
||||
chunk of space will appear on the top of the view
|
||||
chunk of space will appear on the top of the view
|
||||
-->
|
||||
|
||||
<div self="@{define(content)}" height="100%" style="overflow:visible">
|
||||
|
|
@ -39,12 +39,12 @@
|
|||
<div id="projectDashboardChartsDiv" sclass="dashboards-container" height="100%" width="100%">
|
||||
|
||||
<!-- Progress -->
|
||||
<groupbox closable="false">
|
||||
<caption label="${i18n:_('Progress')}" />
|
||||
<groupbox closable="false">
|
||||
<caption label="${i18n:_('Progress')}" />
|
||||
<hbox>
|
||||
<n:div id="global-progress" style="height:200px; width:500px;"></n:div>
|
||||
<n:div id="task-status" style="height:200px; width:400px; margin-left: 100px;"></n:div>
|
||||
|
||||
<n:div id="global-progress" style="height:200px; width:500px;"></n:div>
|
||||
<n:div id="task-status" style="height:200px; width:400px; margin-left: 100px;"></n:div>
|
||||
|
||||
<!-- Tasks summary -->
|
||||
<grid id="gridTasksSummary" style="margin-top: 50px;" width="300px">
|
||||
<auxhead>
|
||||
|
|
@ -73,18 +73,18 @@
|
|||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
<!-- Time -->
|
||||
<groupbox closable="false">
|
||||
<caption label="${i18n:_('Time')}" />
|
||||
<groupbox closable="false">
|
||||
<caption label="${i18n:_('Time')}" />
|
||||
<hbox>
|
||||
<n:div id="task-completation-lag" style="height:200px; width:560px;"></n:div>
|
||||
<n:div id="deadline-violation" style="height:200px; width:400px; margin-left: 100px;"></n:div>
|
||||
<n:div id="margin-with-deadline" style="height:200px; width:400px; margin-left: 100px;"></n:div>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
<n:div id="task-completation-lag" style="height:200px; width:580px;"></n:div>
|
||||
<n:div id="deadline-violation" style="height:200px; width:400px; margin-left: 100px;"></n:div>
|
||||
<n:div id="margin-with-deadline" style="height:200px; width:400px; margin-left: 100px;"></n:div>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -101,22 +101,8 @@
|
|||
<!-- The variable for containing the 'global progress' has to be global and created before defer -->
|
||||
<script type="text/javascript">
|
||||
var global_progress = { };
|
||||
var task_completation_lag = { };
|
||||
</script>
|
||||
|
||||
<n:style type="text/css">
|
||||
.tooltip {
|
||||
display:none;
|
||||
position:absolute;
|
||||
border:1px solid #333;
|
||||
background-color:#161616;
|
||||
border-radius:5px;
|
||||
padding:10px;
|
||||
color:#fff;
|
||||
font-size:12px Arial;
|
||||
}
|
||||
</n:style>
|
||||
|
||||
<!-- Configure the parameters for the 'global progress' chart. The object contains a method 'render' that
|
||||
is called from the Java file once all objects in the view have been created -->
|
||||
<script type="text/javascript" defer="true">
|
||||
|
|
@ -139,7 +125,7 @@
|
|||
label: "Progress percentage per progress type"
|
||||
},
|
||||
yaxis: {
|
||||
renderer: $.jqplot.CategoryAxisRenderer,
|
||||
renderer: $.jqplot.CategoryAxisRenderer,
|
||||
ticks: ['1','2','3'],
|
||||
tickOptions: {
|
||||
showGridline: false,
|
||||
|
|
@ -161,77 +147,17 @@
|
|||
this.axes.yaxis.ticks = jQuery.parseJSON(ticks);
|
||||
}
|
||||
if (series !== undefined) {
|
||||
this.series = jQuery.parseJSON(series);
|
||||
this.series = jQuery.parseJSON(series);
|
||||
}
|
||||
this.plot = $.jqplot(this.id, jQuery.parseJSON(data), this);
|
||||
}
|
||||
};
|
||||
|
||||
task_completation_lag = {
|
||||
id: 'task-completation-lag',
|
||||
title: 'Task completation lag',
|
||||
data: [],
|
||||
seriesDefaults:{
|
||||
renderer:$.jqplot.BarRenderer,
|
||||
rendererOptions: {
|
||||
fillToZero: true
|
||||
}
|
||||
},
|
||||
axesDefaults: {
|
||||
tickRenderer: $.jqplot.CanvasAxisTickRenderer ,
|
||||
tickOptions: {
|
||||
angle: -30,
|
||||
fontSize: '10pt'
|
||||
}
|
||||
},
|
||||
axes: {
|
||||
xaxis: {
|
||||
label: 'Number of Days / Days Interval',
|
||||
renderer: $.jqplot.CategoryAxisRenderer,
|
||||
},
|
||||
},
|
||||
render: function(data, conf) {
|
||||
if (conf.ticks !== undefined) {
|
||||
this.axes.xaxis.ticks = jQuery.parseJSON(conf.ticks);
|
||||
}
|
||||
if (conf.titles !== undefined) {
|
||||
this.axes.xaxis.ticks = jQuery.parseJSON(conf.ticks);
|
||||
}
|
||||
|
||||
this.plot = $.jqplot(this.id, [jQuery.parseJSON(data)], this);
|
||||
this.attachTooltip();
|
||||
},
|
||||
attachTooltip: function() {
|
||||
var node = $('#' + this.id);
|
||||
node.bind('jqplotDataHighlight',
|
||||
function (ev, seriesIndex, pointIndex, data) {
|
||||
var x = ev.pageX - node.offset().left;
|
||||
var y = ev.pageY - node.offset().top;
|
||||
|
||||
var tooltip = $('<span class="tooltip"></span>');
|
||||
tooltip.text(data[1]).appendTo(node);
|
||||
tooltip.css({'top': y, 'left': x, 'position': 'absolute'});
|
||||
tooltip.fadeIn('slow');
|
||||
}
|
||||
);
|
||||
node.bind('jqplotDataUnhighlight',
|
||||
function (ev) {
|
||||
$('.tooltip').remove();
|
||||
}
|
||||
);
|
||||
node.mousemove(function(ev) {
|
||||
var x = ev.pageX - node.offset().left;
|
||||
var y = ev.pageY - node.offset().top;
|
||||
$('.tooltip').css({'top': y, 'left': x, 'position': 'absolute'})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<!-- Include jqPlot styles -->
|
||||
<n:link class="include" rel="stylesheet" type="text/css" href="/libreplan-webapp/jqplot/jquery.jqplot.min.css" />
|
||||
<n:link class="include" rel="stylesheet" type="text/css" href="/libreplan-webapp/jqplot/jquery.jqplot.min.css" />
|
||||
|
||||
<!-- Include jqPlot library and additional plugins -->
|
||||
<n:script type="text/javascript" src="/libreplan-webapp/jqplot/jquery.js"></n:script>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue