/*
* Canvas line
* Author:SongYi
* Date:2015-06-29
* Version:0.1
*/
(function(){
/* ****************************************************************************
* Handle the options *
*****************************************************************************/
var defaultOptions = {
colors: ['#00A600', '#D94600', '#921AFF', '#E800E8', '#C6A300', '#f7a35c',
'#8085e9', '#f15c80', '#e4d354', '#91e8e1'],
datas:[],
global: {
width:630,
height:275,
border:true,
borderStyle:"1px solid #000"
},
chart: {
marginLeft:80,
marginRight:10,
marginTop:5,
marginBottom:30,
lineWidth:1,
yStep : 40,
xStep : 60,
yRatio : 0,
xRatio : 0,
yMax : 10000,
yMin : 0,
xMax : 0,
xMin : 0,
yRealMax:0,
yRealMin:0
},
title: {
textY: '',
textX: '(s)',
style: {
color: '#000000',
font: '11pt Arial'
}
},
labels: {
marginLeft:25,
marginTop:5,
style: {
color: '#000000',
font: '9pt Arial'
}
}
};
function Canvasy(userOptions){
var options = extend(defaultOptions,userOptions);
this.get = function(n){
return options[n];
}
this.set = function(n,v){
options[n] = v;
}
this.init();
}
Canvasy.prototype = {
/**
* Initialize the chart
*/
init: function () {
var ctx = this.get("ctx");
var global = this.get("global");
ctx.setAttribute('width',global.width);
ctx.setAttribute('height',global.height);
ctx = ctx.getContext("2d");
ctx.clearRect(0,0,global.width,global.height);
this.initOption();
this.setTitleY();
this.drawAxis();
this.drawGridlinesX();
this.drawGridlinesY();
this.setAxisLabelX();
this.setAxisLabelY();
this.drawLines();
},
initOption:function(){
var global = this.get("global");
var chart = this.get("chart");
var lines = this.get("datas");
chart.baseY = global.height - chart.marginBottom;
chart.baseX = global.width - chart.marginRight;
chart.yStep = (global.height - chart.marginTop - chart.marginBottom)/6;
chart.xStep = (global.width - chart.marginLeft - chart.marginRight)/9;
chart.yRatio = (chart.baseY-chart.marginTop)/(chart.yMax-chart.yMin);
this.set("chart",chart);
},
setTitleY:function(){
var ctx = this.get("ctx").getContext("2d");
var chart = this.get("chart");
ctx.save();
ctx.rotate(-90 * Math.PI / 180);
ctx.font = this.get("title").style.font;
ctx.fillStyle = this.get("title").style.color;
ctx.textAlign = 'center';
ctx.fillText(this.get("title").textY,-80,20);
ctx.restore();
},
drawAxis:function(){
// X axis
var ctx = this.get("ctx").getContext("2d");
var global = this.get("global");
var chart = this.get("chart");
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle="#000000";
ctx.moveTo(chart.marginLeft,global.height-chart.marginBottom);
ctx.lineTo(global.width-chart.marginRight,global.height-chart.marginBottom);
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle="#000000";
ctx.moveTo(chart.marginLeft,chart.marginTop);
ctx.lineTo(chart.marginLeft,global.height-chart.marginBottom);
ctx.stroke();
},
drawGridlinesX:function(){
var ctx = this.get("ctx").getContext("2d");
var height = this.get("global").height;
var lines = this.get("datas");
var chart = this.get("chart");
if(typeof lines !== 'undefined' && lines.length > 0){
if(chart.xMax < 10 || isInteger(chart.xMax)){
for(var i=2; i<=10;i++){
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle="#D7D7D7";
ctx.moveTo((i-1)*chart.xStep+chart.marginLeft,chart.marginTop);
ctx.lineTo((i-1)*chart.xStep+chart.marginLeft,height-chart.marginBottom);
ctx.stroke();
}
}else{
var xAxisMax = Math.floor(chart.xMax);
for(var i=0;i<9;i++){
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle="#D7D7D7";
ctx.moveTo(chart.baseX-((chart.xMax-xAxisMax)+i)*chart.xStep,chart.marginTop);
ctx.lineTo(chart.baseX-((chart.xMax-xAxisMax)+i)*chart.xStep,height-chart.marginBottom);
ctx.stroke();
}
}
}
},
drawGridlinesY:function(){
var ctx = this.get("ctx").getContext("2d");
var width = this.get("global").width;
var chart = this.get("chart");
for(var i=0; i<=5;i++){
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle="#D7D7D7";
ctx.moveTo(chart.marginLeft,i*chart.yStep+5);
ctx.lineTo(width-chart.marginRight,i*chart.yStep+5);
ctx.stroke();
}
},
drawLines:function(){
var ctx = this.get("ctx").getContext("2d");
var lines = this.get("datas");
var colors = this.get("colors");
var chart = this.get("chart");
var global = this.get("global");
ctx.save();
ctx.rect(chart.marginLeft,chart.marginTop,global.width-chart.marginLeft-chart.marginRight,global.height-chart.marginBottom-chart.marginTop);
ctx.stroke();
ctx.clip();
ctx.lineCap="round";
if(lines !== null && typeof lines !== 'undefined'){
for(var i=0;i<lines.length;i++){
var line = lines[i];
for(var j=1;j<line.data.length;j++){
var xPoint = line.data[j-1];
var point = line.data[j];
ctx.beginPath();
ctx.strokeStyle=colors[i];
if(line.focus){
ctx.lineWidth = 4*chart.lineWidth;
}else{
ctx.lineWidth = chart.lineWidth;
}
ctx.moveTo(chart.baseX-round((chart.xMax-xPoint.x)*chart.xStep),chart.baseY-round(xPoint.y*chart.yRatio));
ctx.lineTo(chart.baseX-round((chart.xMax-point.x)*chart.xStep),chart.baseY-round(point.y*chart.yRatio));
ctx.stroke();
}
}
}
ctx.restore();
},
setAxisLabelY:function(){
var ctx = this.get("ctx").getContext("2d");
var chart = this.get("chart");
var global = this.get("global");
var labels = this.get("labels");
ctx.font = labels.style.font;
ctx.fillStyle=labels.style.color;
for(var i=0;i<=6;i++){
ctx.fillText(round(chart.yRealMin+round((chart.yRealMax-chart.yRealMin)/6)*i),labels.marginLeft,chart.baseY-i*chart.yStep+labels.marginTop);
}
},
setAxisLabelX:function(){
var ctx = this.get("ctx").getContext("2d");
var lines = this.get("datas");
var chart = this.get("chart");
var labels = this.get("labels");
var height = this.get("global").height;
ctx.font = labels.style.font;
ctx.fillStyle=labels.style.color;
if(typeof lines !== 'undefined' && lines.length > 0){
if(chart.xMax < 10){
for(var i=0; i<10;i++){
ctx.fillText(i,i*chart.xStep+chart.marginLeft,height-18);
}
chart.xMax = 9;
}else{
var xAxisMax = Math.floor(chart.xMax);
for(var i=0;i<9;i++){
ctx.fillText(xAxisMax-i,chart.baseX-((chart.xMax-xAxisMax)+i)*chart.xStep-10,height-18);
}
}
}
ctx.font = this.get("title").style.font;
ctx.fillStyle = this.get("title").style.color;
ctx.fillText(this.get("title").textX,chart.baseX-30,height-5);
},
setOptions:function(options){
for(var p in options){
this.set(p,options[p]);
}
this.init();
},
addPoint:function(points){
if(points == null || points == 'undefined'){
return;
}
var lines = this.get("datas");
for(var i=0;i<lines.length;i++){
if(isArray(points)){
for(var j=0;j<points.length;j++){
if(points[j].name == lines[i].name){
lines[i].data.push(points[j].data);
}
}
}else{
if(points.name == lines[i].name){
lines[i].data.push(points.data);
}
}
}
this.set("datas",lines);
this.init();
},
resize:function(width,height,drawFlag){
var ctx = this.get("ctx");
var global = this.get("global");
global.width = width;
global.height = height;
ctx.setAttribute('width',width);
ctx.setAttribute('height',height);
if(drawFlag){
this.init();
}else{
ctx = ctx.getContext("2d");
ctx.clearRect(0,0,width,height);
}
}
}
// The Highcharts namespace
window.Canvasy = window.Canvasy || Canvasy;
/**
* Extend an object with the members of another
* @param {Object} a The object to be extended
* @param {Object} b The object to add to the first one
*/
var extend = Canvasy.extend = function (a, b) {
var n;
if (!a) {
a = {};
}
for (n in b) {
a[n] = b[n];
}
return a;
};
/**
* Check for string
* @param {Object} s
*/
function isString(s) {
return typeof s === 'string';
}
/**
* Check for object
* @param {Object} obj
*/
function isObject(obj) {
return obj && typeof obj === 'object';
}
function isInteger(obj) {
return Math.floor(obj) === obj
}
/**
* Check for array
* @param {Object} obj
*/
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
/**
* Check for number
* @param {Object} n
*/
function isNumber(n) {
return typeof n === 'number';
}
function round(n){
return Math.round(n*1000)/1000;
}
/**
* Non-recursive method to find the lowest member of an array. Math.min raises a maximum
* call stack size exceeded error in Chrome when trying to apply more than 150.000 points.
* This method is slightly slower, but safe.
*/
function arrayMin(data) {
if(data == null || data.length == 0){
return 0;
}
var i = data.length,
min = data[0];
while (i--) {
if (data[i] < min) {
min = data[i];
}
}
return min;
}
function arrayMax(data) {
if(data == null || data.length == 0){
return 0;
}
var i = data.length,
max = data[0];
while (i--) {
if (data[i] > max) {
max = data[i];
}
}
return max;
}
/**
* Provide error messages for debugging, with links to online explanation
*/
function error (code, stop) {
var msg = 'Canvasy error #' + code + ': ' + code;
if (stop) {
throw msg;
}
// else ...
if (window.console) {
console.log(msg);
}
}
})()