Skip to content

Commit

Permalink
HTML5: First attempt at chart.html
Browse files Browse the repository at this point in the history
Hope to keep the canvas area small enough to prevent scrolling. Will need to revise some of the calculations. Please test!!

git-svn-id: https://xerteonlinetoolkits.googlecode.com/svn/trunk@583 912cdd6b-5c7d-d5a7-a2ba-d0f0cdb91641
  • Loading branch information
JohnSmith-LT committed Dec 8, 2012
1 parent c589978 commit 0747a00
Showing 1 changed file with 325 additions and 0 deletions.
325 changes: 325 additions & 0 deletions modules/xerte/parent_templates/Nottingham/models_html5/chart.html
@@ -0,0 +1,325 @@
<script type="text/javascript">
// -----------------------------------------------------------------------------------------
// All drawing code based on Actionscript routines by Ric Ewing (ric@formequalsfunction.com)
// -----------------------------------------------------------------------------------------

// pageChanged & sizeChanged functions are needed in every model file
// other functions for model should also be in here to avoid conflicts
var chart = new function() {
var allSeries;

// function called every time the page is viewed after it has initially loaded
this.pageChanged = function() {

};

// function called every time the size of the LO is changed
this.sizeChanged = function() {

};

this.doAxesAndLabels = function(canvas, w, w1, yMin, yMax, scalar, hMax) {
canvas.strokeStyle = '#000000';
canvas.fillStyle = '#000000';
canvas.beginPath();
canvas.moveTo(0,30 + allSeries.length * 20);
canvas.lineTo(0,445);
canvas.moveTo(-5,440);
canvas.lineTo(350,440);
canvas.fill();
canvas.stroke();

//draw the legend
canvas.beginPath();
for (var i = 0;i < allSeries.length; i++) {
canvas.strokeStyle = allSeries[i].colour;
canvas.fillStyle = allSeries[i].colour;
canvas.fillRect(-50, 23 + i * 20, 12, 12);
canvas.fill()
canvas.stroke();

canvas.fillStyle = '#000000';
canvas.textBaseline = "top";
canvas.fillText(allSeries[i].name, -30, 22 + i * 20);
}

//draw the x labels
for (var i = 0; i < allSeries[0].data.length; i++) {
canvas.fillStyle = '#000000';
canvas.textBaseline = "top";
canvas.fillText(allSeries[0].data[i].x, w * (i + 0.5) - 5, 444);
}

//draw the y labels
canvas.fillText(yMin, -25, 434);
canvas.fillText(yMax, -25, 434-hMax);
};

this.doStackedBar = function(canvas, w, hMax) {
var cumH = [];

for (i = 0; i < allSeries[0].data.length; i++) {
cumH[i] = 0;
}

var tempCH, maxCH = 0;
//find total colum height
for (i = 0; i < allSeries[0].data.length; i++) { //for each dimension
tempCH = 0;
for (j = 0; j < allSeries.length; j++) {
tempCH += allSeries[j].data[i].y;
}
}
if (tempCH > maxCH) {
maxCH = tempCH;
}

var scalar = hMax / maxCH;

var tempH
canvas.lineWidth = 2;
for (i = 0; i < allSeries.length; i++) { //for each series
canvas.strokeStyle = allSeries[i].colour;
canvas.fillStyle = allSeries[i].colour;
for (j = 0; j < allSeries[i].data.length; j++) {
tempH = allSeries[i].data[j].y;
canvas.fillRect(w * j, 440 - cumH[j] * scalar, w * 0.9 , -tempH * scalar);
cumH[j] += tempH;
}
canvas.fill();
canvas.stroke();
}
};

this.doBar = function(canvas, w, w1, yMin, scalar) {
var tempH;
canvas.lineWidth = 2;
for (var i=0; i<allSeries.length; i++) {
canvas.strokeStyle = allSeries[i].colour;
canvas.fillStyle = allSeries[i].colour;
for (var j=0; j<allSeries[i].data.length; j++) {
if (!isNaN(allSeries[i].data[j].y)) {
tempH = (allSeries[i].data[j].y - yMin) * scalar;
canvas.fillRect(w*j+i*w1, 440, w*0.9 / allSeries.length, -tempH);
}
}
canvas.fill();
canvas.stroke();
}
};

this.doLine = function(canvas, w, yMin, scalar) {
canvas.lineWidth = 2;
for (var i=0; i<allSeries.length; i++) {
canvas.beginPath();
canvas.strokeStyle = allSeries[i].colour;
canvas.moveTo(w/2, 440 - (allSeries[i].data[0].y - yMin) * scalar);
for (var j=0; j<allSeries[i].data.length; j++) {
if (!isNaN(allSeries[i].data[j].y)) {
canvas.lineTo(w*j + w/2, 440 - (allSeries[i].data[j].y - yMin) * scalar);
}
}
canvas.stroke();
}
};

this.doPie = function(canvas) {
var hexToRgb = function (hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
};

var rgbToHex = function (r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
};

// build the colour array
var colours = [];
var rgb = hexToRgb(allSeries[0].colour);
for (var i = 0; i < allSeries[0].data.length; i++) {
colours.push(rgbToHex(
parseInt(rgb.r + i * (255 - rgb.r)/allSeries[0].data.length),
parseInt(rgb.g + i * (255 - rgb.g)/allSeries[0].data.length),
parseInt(rgb.b + i * (255 - rgb.b)/allSeries[0].data.length)
));
}

var colOff = 100 / allSeries.length;
for (var i = 0; i < allSeries[0].data.length; i++) {
canvas.strokeStyle = '#000000';
canvas.fillStyle = colours[i];
canvas.lineWidth = 1;
canvas.fillRect(-50, 22 + i * 20, 12, 12);
canvas.strokeRect(-50, 22 + i * 20, 12, 12);
canvas.fill();
canvas.stroke();
canvas.textBaseline = "top";
canvas.fillStyle = '#000000';
canvas.fillText(allSeries[0].data[i].y, -30, 22 + i * 20);
}

///draw chart
for (var i = 0; i < 1; i++) { //for first series
//get the total for this series
var sT = 0;
for (j = 0; j < allSeries[i].data.length; j++) {
sT += allSeries[i].data[j].y;
}

var theta, exTheta = 0;
for (var j = 0; j < allSeries[i].data.length; j++) { //draw each segment...
theta = Number(allSeries[i].data[j].y) / sT * 360;
this.drawWedge(canvas, 170, 260, 150 - i * (150 / allSeries.length), theta, exTheta, colours[j]);
exTheta += theta;
}
}
};

this.drawWedge = function(canvas, x, y, radius, arc, r, colour) {
canvas.save();
canvas.translate(x, y);
canvas.rotate( -r * Math.PI / 180);
canvas.fillStyle = colour;
canvas.strokeStyle = colour;
canvas.beginPath();
canvas.moveTo(0, 0);
var segAngle, theta, angle, angleMid, segs, ax, ay, bx, by, cx, cy;
if (Math.abs(arc) > 360) {
arc = 360;
}
segs = Math.ceil(Math.abs(arc) / 45);
segAngle = arc / segs;
theta = - Math.PI * segAngle / 180;
angle = - Math.PI * 0 / 180;
if (segs > 0) {
ax = Math.cos(0 * Math.PI / 180) * radius;
ay = Math.sin(-0 * Math.PI / 180) * radius;
canvas.lineTo(ax, ay);
for (var i = 0; i < segs; i++) {
angle += theta;
angleMid = angle - theta / 2;
bx = Math.cos(angle) * radius;
by = Math.sin(angle) * radius;
cx = Math.cos(angleMid) * radius / Math.cos(theta / 2);
cy = Math.sin(angleMid) * radius / Math.cos(theta / 2);
canvas.quadraticCurveTo(cx, cy, bx, by);
}
canvas.lineTo(0, 0);
}
canvas.closePath();
canvas.fill();
canvas.globalAlpha = 100;
canvas.stroke();
canvas.restore();
};

this.init = function() {
var $pageContents = $("#pageContents");
var $textHolder = $("#textHolder");
var $panel = $("#pageContents .panel");
var $chartTitle = $("#chartTitle");
var chartHolder = document.getElementById('chartHolder');

$textHolder.html(x_addLineBreaks(x_currentPageXML.getAttribute("text")));
$chartTitle.html(x_currentPageXML.getAttribute("chartTitle"));

allSeries = [];
var yMin, yMax;
var series = $(x_currentPageXML).children();
if (series.length == 0) {
// There are no series
}
else {
yMin = 1000000, yMax = 0;
$(x_currentPageXML).children().each(function () {
var name = this.getAttribute("name");
var dataString = this.getAttribute("data");
var colour = this.getAttribute("colour");
if (colour.substring(0, 2) == '0x') { // hex value
colour = '#' + Array(9-colour.length).join('0') + colour.substring(2);
}

var dataPair, dataPairs = dataString.split('||');
var data = [];
for (var i=0; i<dataPairs.length; i++) {
dataPair = dataPairs[i].split('|');
data.push({"x":parseInt(dataPair[0]), "y":parseInt(dataPair[1])});
if (!isNaN(parseInt(dataPair[1]))) {
yMax = Math.max(yMax, parseInt(dataPair[1]));
yMin = Math.floor(Math.min(yMin, parseInt(dataPair[1])) * 0.9);
}
}
allSeries.push({"name":name, "colour": colour, "data":data});
});
}

var hMax = 410 - allSeries.length * 20;
var scalar = hMax / (yMax - yMin);
var w = 350 / allSeries[0].data.length;
var w1 = w * 0.9 / allSeries.length;

chartHolder.width = 410;
chartHolder.height = 460;

chartHolder.getContext("2d").translate(60, 0);

switch (x_currentPageXML.getAttribute("chartType")) {
case "stacked bar":
this.doStackedBar(chartHolder.getContext("2d"), w, hMax);
break;
case "pie":
this.doPie(chartHolder.getContext("2d"));
break;
case "bar":
this.doBar(chartHolder.getContext("2d"), w, w1, yMin, scalar);
break;
case "line":
this.doLine(chartHolder.getContext("2d"), w, yMin, scalar);
}

if (x_currentPageXML.getAttribute("chartType") != "pie") {
this.doAxesAndLabels(chartHolder.getContext("2d"), w, w1, yMin, yMax, scalar, hMax)
}

if (x_currentPageXML.getAttribute("align") != "right") {
$panel.addClass("x_floatRight");
} else {
$panel.addClass("x_floatLeft");
}

// call this function in every model once everything's loaded
x_pageLoaded();
};
};

chart.init();

</script>

<style type="text/css">

#chartTitle {
font-weight: bold;
text-align: center;
}

</style>

<div id="pageContents">

<div id="tableHolder" class="mobileAlign"> <!-- this tag is only used when viewed on mobiles to change layout -->
<div class="panel inline">
<div id="chartTitle"></div>
<canvas id="chartHolder"></canvas>
</div>
</div>

<div id="textHolder">

</div>

</div>

0 comments on commit 0747a00

Please sign in to comment.