/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.core.gui.components.chart; import java.util.List; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.DefaultComponentRenderer; import org.olat.core.gui.components.chart.BarSeries.Stringuified; import org.olat.core.gui.render.RenderResult; import org.olat.core.gui.render.Renderer; import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.translator.Translator; import org.olat.core.util.StringHelper; /** * * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ public class BarChartComponentRenderer extends DefaultComponentRenderer { @Override public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator, RenderResult renderResult, String[] args) { BarChartComponent chartCmp = (BarChartComponent)source; List<BarSeries> seriesList = chartCmp.getSeries(); String yLegend = chartCmp.getYLegend(); String xLegend = chartCmp.getXLegend(); Stringuified infos = BarSeries.getDatasAndColors(seriesList, chartCmp.getDefaultBarClass()); String sum = getSum(seriesList); String cmpId = chartCmp.getDispatchID(); sb.append("<div id='d").append(cmpId).append("d3holder' class='d3chart' style='width:600px;height:300px'></div>\n") .append("<script type='text/javascript'>\n") .append("/* <![CDATA[ */ ") .append("jQuery(function () {\n") .append("var placeholderheight = jQuery('#d").append(cmpId).append("d3holder').height();\n") .append("var placeholderwidth = jQuery('#d").append(cmpId).append("d3holder').width();\n"); sb.append("var margin = {top: 20, right: 20, bottom: 30, left: 50},\n") .append(" width = placeholderwidth - margin.left - margin.right,\n") .append(" height = placeholderheight - margin.top - margin.bottom;\n") .append("\n") .append("var x = d3.scale.ordinal()\n") .append(" .rangeRoundBands([0, width], .1);\n") .append("\n") .append("var y = d3.scale.linear()\n") .append(" .range([height, 0]);\n") .append("\n") .append("var xAxis = d3.svg.axis()\n") .append(" .scale(x)\n") .append(" .orient('bottom');\n") .append("\n") .append("var yAxis = d3.svg.axis()\n") .append(" .scale(y)\n") .append(" .orient('left')\n"); sb.append("\n") .append("var svg = d3.select('#d").append(cmpId).append("d3holder').append('svg')\n") .append(" .attr('width', width + margin.left + margin.right)\n") .append(" .attr('height', height + margin.top + margin.bottom)\n") .append(" .append('g')\n") .append(" .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');\n") .append("\n") .append("var data = [").append(infos.getData()).append("]\n") .append("x.domain(data.map(function(d) { return d[0]; }));\n") .append("y.domain([0, d3.max(data, function(d) { return ").append(sum).append("; })]);\n") .append("\n"); //append x axis and legend sb.append("svg.append('g')\n") .append(" .attr('class', 'x axis')\n") .append(" .attr('transform', 'translate(0,' + height + ')')\n") .append(" .call(xAxis);\n"); if(StringHelper.containsNonWhitespace(xLegend)) { sb.append(" .append('text')\n") .append(" .attr('y', 0)\n") .append(" .attr('x', 0 - (width / 2))\n") .append(" .attr('dy', '1em')\n") .append(" .style('text-anchor', 'middle')\n") .append(" .text('").append(xLegend).append("');\n"); } //append y axis and legend sb.append("svg.append('g')\n") .append(" .attr('class', 'y axis')\n") .append(" .call(yAxis)\n"); if(StringHelper.containsNonWhitespace(yLegend)) { sb.append(" .append('text')\n") .append(" .attr('transform', 'rotate(-90)')\n") .append(" .attr('y', 0 - margin.left)\n") .append(" .attr('x', 0 - (height / 2))\n") .append(" .attr('dy', '1em')\n") .append(" .style('text-anchor', 'middle')\n") .append(" .text('").append(yLegend).append("');\n") .append("\n"); } appendSeries(sb, infos.getColors(), chartCmp); sb.append("});\n") .append("/* ]]> */") .append("</script>\n"); } private void appendSeries(StringOutput sb, StringBuilder colors, BarChartComponent chartCmp) { if(colors.length() > 0) { sb.append("var colors = [").append(colors).append("];"); } List<BarSeries> seriesList = chartCmp.getSeries(); for(int i=0; i<seriesList.size(); i++) { String color = seriesList.get(i).getCssClass(); if(color == null) { color = chartCmp.getDefaultBarClass(); } String correction = getCorrection(i); sb.append("svg.selectAll('.bar").append(i).append("')\n") .append(" .data(data)\n") .append(" .enter().append('rect')\n"); if(colors.length() == 0) { sb.append(" .attr('class', 'bar bar").append(i).append(" ").append(color).append("')\n"); } else { sb.append(" .attr('class', function(d, i){ if(colors.length > i) { return colors[i]; } return 'bar bar").append(i).append(" ").append(color).append("'; })\n"); } sb.append(" .attr('fill', '").append(color).append("')\n") .append(" .attr('x', function(d) { return x(d[0]); })\n") .append(" .attr('y', function(d) { return y(d[").append((i+1)).append("]) ").append(correction).append(" ; })\n") .append(" .attr('width', x.rangeBand())\n") .append(" .attr('height', function(d) { return height - y(d[").append((i+1)).append("]); });\n"); } } private String getSum(List<BarSeries> seriesList) { StringBuilder sum = new StringBuilder(); for(int i=0; i<seriesList.size(); i++) { if(sum.length() > 0) sum.append(" + "); sum.append(" d[").append((i+1)).append("]"); } return sum.toString(); } private String getCorrection(int i) { if(i == 0) return ""; if(i == 1) return "- (height - y(d[1]))"; if(i == 2) return "- (height - y(d[1] + d[2]))"; return ""; } }