Files

4062 lines
123 KiB
JavaScript

/*
Product Name: dhtmlxSuite
Version: 4.0.3
Edition: Professional
License: content of this file is covered by DHTMLX Commercial or Enterprise license. Usage without proper license is prohibited. To obtain it contact sales@dhtmlx.com
Copyright UAB Dinamenta http://www.dhtmlx.com
*/
/* DHX DEPEND FROM FILE 'group.js'*/
/*DHX:Depend datastore.js*/
/*DHX:Depend dhtmlx.js*/
dhtmlx.Group = {
_init:function(){
dhtmlx.assert(this.data,"DataStore required for grouping");
this.data.attachEvent("onStoreLoad",dhtmlx.bind(function(){
if (this._settings.group)
this.group(this._settings.group,false);
},this));
this.attachEvent("onBeforeRender",dhtmlx.bind(function(data){
if (this._settings.sort){
data.block();
data.sort(this._settings.sort);
data.unblock();
}
},this));
this.attachEvent("onBeforeSort",dhtmlx.bind(function(){
this._settings.sort = null;
},this));
},
_init_group_data_event:function(data,master){
data.attachEvent("onClearAll",dhtmlx.bind(function(){
this.ungroup(false);
this.block();
this.clearAll();
this.unblock();
},master));
},
sum:function(property, data){
property = dhtmlx.Template.setter(property);
data = data || this.data;
var summ = 0;
data.each(function(obj){
summ+=property(obj)*1;
});
return summ;
},
min:function(property, data){
property = dhtmlx.Template.setter(property);
data = data || this.data;
var min = Infinity;
data.each(function(obj){
if (property(obj)*1 < min) min = property(obj)*1;
});
return min*1;
},
max:function(property, data){
property = dhtmlx.Template.setter(property);
data = data || this.data;
var max = -Infinity;
data.each(function(obj){
if (property(obj)*1 > max) max = property(obj)*1;
});
return max;
},
_split_data_by:function(stats){
var any=function(property, data){
property = dhtmlx.Template.setter(property);
return property(data[0]);
};
var key = dhtmlx.Template.setter(stats.by);
if (!stats.map[key])
stats.map[key] = [key, any];
var groups = {};
var labels = [];
this.data.each(function(data){
var current = key(data);
if (!groups[current]){
labels.push({id:current});
groups[current] = dhtmlx.toArray();
}
groups[current].push(data);
});
for (var prop in stats.map){
var functor = (stats.map[prop][1]||any);
if (typeof functor != "function")
functor = this[functor];
for (var i=0; i < labels.length; i++) {
labels[i][prop]=functor.call(this, stats.map[prop][0], groups[labels[i].id]);
}
}
// if (this._settings.sort)
// labels.sortBy(stats.sort);
this._not_grouped_data = this.data;
this.data = new dhtmlx.DataStore();
this.data.provideApi(this,true);
this._init_group_data_event(this.data, this);
this.parse(labels,"json");
},
group:function(config,mode){
this.ungroup(false);
this._split_data_by(config);
if (mode!==false)
this.render();
},
ungroup:function(mode){
if (this._not_grouped_data){
this.data = this._not_grouped_data;
this.data.provideApi(this, true);
}
if (mode!==false)
this.render();
},
group_setter:function(config){
dhtmlx.assert(typeof config == "object", "Incorrect group value");
dhtmlx.assert(config.by,"group.by is mandatory");
dhtmlx.assert(config.map,"group.map is mandatory");
return config;
},
//need to be moved to more appropriate object
sort_setter:function(config){
if (typeof config != "object")
config = { by:config };
this._mergeSettings(config,{
as:"string",
dir:"asc"
});
return config;
}
};
/* DHX DEPEND FROM FILE 'date.js'*/
/*DHX:Depend dhtmlx.js*/
dhtmlx.Date={
Locale: {
month_full:["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
month_short:["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
day_full:["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
day_short:["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
},
date_part:function(date){
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date;
},
time_part:function(date){
return (date.valueOf()/1000 - date.getTimezoneOffset()*60)%86400;
},
week_start:function(date){
var shift=date.getDay();
if (this.config.start_on_monday){
if (shift===0) shift=6;
else shift--;
}
return this.date_part(this.add(date,-1*shift,"day"));
},
month_start:function(date){
date.setDate(1);
return this.date_part(date);
},
year_start:function(date){
date.setMonth(0);
return this.month_start(date);
},
day_start:function(date){
return this.date_part(date);
},
add:function(date,inc,mode){
var ndate=new Date(date.valueOf());
switch(mode){
case "day": ndate.setDate(ndate.getDate()+inc); break;
case "week": ndate.setDate(ndate.getDate()+7*inc); break;
case "month": ndate.setMonth(ndate.getMonth()+inc); break;
case "year": ndate.setYear(ndate.getFullYear()+inc); break;
case "hour": ndate.setHours(ndate.getHours()+inc); break;
case "minute": ndate.setMinutes(ndate.getMinutes()+inc); break;
default:
return dhtmlx.Date["add_"+mode](date,inc,mode);
}
return ndate;
},
to_fixed:function(num){
if (num<10) return "0"+num;
return num;
},
copy:function(date){
return new Date(date.valueOf());
},
date_to_str:function(format,utc){
format=format.replace(/%[a-zA-Z]/g,function(a){
switch(a){
case "%d": return "\"+dhtmlx.Date.to_fixed(date.getDate())+\"";
case "%m": return "\"+dhtmlx.Date.to_fixed((date.getMonth()+1))+\"";
case "%j": return "\"+date.getDate()+\"";
case "%n": return "\"+(date.getMonth()+1)+\"";
case "%y": return "\"+dhtmlx.Date.to_fixed(date.getFullYear()%100)+\"";
case "%Y": return "\"+date.getFullYear()+\"";
case "%D": return "\"+dhtmlx.Date.Locale.day_short[date.getDay()]+\"";
case "%l": return "\"+dhtmlx.Date.Locale.day_full[date.getDay()]+\"";
case "%M": return "\"+dhtmlx.Date.Locale.month_short[date.getMonth()]+\"";
case "%F": return "\"+dhtmlx.Date.Locale.month_full[date.getMonth()]+\"";
case "%h": return "\"+dhtmlx.Date.to_fixed((date.getHours()+11)%12+1)+\"";
case "%g": return "\"+((date.getHours()+11)%12+1)+\"";
case "%G": return "\"+date.getHours()+\"";
case "%H": return "\"+dhtmlx.Date.to_fixed(date.getHours())+\"";
case "%i": return "\"+dhtmlx.Date.to_fixed(date.getMinutes())+\"";
case "%a": return "\"+(date.getHours()>11?\"pm\":\"am\")+\"";
case "%A": return "\"+(date.getHours()>11?\"PM\":\"AM\")+\"";
case "%s": return "\"+dhtmlx.Date.to_fixed(date.getSeconds())+\"";
case "%W": return "\"+dhtmlx.Date.to_fixed(dhtmlx.Date.getISOWeek(date))+\"";
default: return a;
}
});
if (utc) format=format.replace(/date\.get/g,"date.getUTC");
return new Function("date","return \""+format+"\";");
},
str_to_date:function(format,utc){
var splt="var temp=date.split(/[^0-9a-zA-Z]+/g);";
var mask=format.match(/%[a-zA-Z]/g);
for (var i=0; i<mask.length; i++){
switch(mask[i]){
case "%j":
case "%d": splt+="set[2]=temp["+i+"]||1;";
break;
case "%n":
case "%m": splt+="set[1]=(temp["+i+"]||1)-1;";
break;
case "%y": splt+="set[0]=temp["+i+"]*1+(temp["+i+"]>50?1900:2000);";
break;
case "%g":
case "%G":
case "%h":
case "%H":
splt+="set[3]=temp["+i+"]||0;";
break;
case "%i":
splt+="set[4]=temp["+i+"]||0;";
break;
case "%Y": splt+="set[0]=temp["+i+"]||0;";
break;
case "%a":
case "%A": splt+="set[3]=set[3]%12+((temp["+i+"]||'').toLowerCase()=='am'?0:12);";
break;
case "%s": splt+="set[5]=temp["+i+"]||0;";
break;
}
}
var code ="set[0],set[1],set[2],set[3],set[4],set[5]";
if (utc) code =" Date.UTC("+code+")";
return new Function("date","var set=[0,0,1,0,0,0]; "+splt+" return new Date("+code+");");
},
getISOWeek: function(ndate) {
if(!ndate) return false;
var nday = ndate.getDay();
if (nday === 0) {
nday = 7;
}
var first_thursday = new Date(ndate.valueOf());
first_thursday.setDate(ndate.getDate() + (4 - nday));
var year_number = first_thursday.getFullYear(); // year of the first Thursday
var ordinal_date = Math.floor( (first_thursday.getTime() - new Date(year_number, 0, 1).getTime()) / 86400000); //ordinal date of the first Thursday - 1 (so not really ordinal date)
var week_number = 1 + Math.floor( ordinal_date / 7);
return week_number;
},
getUTCISOWeek: function(ndate){
return this.getISOWeek(ndate);
}
};
/* DHX DEPEND FROM FILE 'math.js'*/
dhtmlx.math = {};
dhtmlx.math._toHex=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];
dhtmlx.math.toHex = function(number, length){
number=parseInt(number,10);
str = "";
while (number>0){
str=this._toHex[number%16]+str;
number=Math.floor(number/16);
}
while (str.length <length)
str = "0"+str;
return str;
};
dhtmlx.math.hexToDec = function(hex){
return parseInt(hex, 16);
};
dhtmlx.math.toRgb = function(rgb){
var r,g,b,rgbArr;
if (typeof(rgb) != 'string') {
r = rgb[0];
g = rgb[1];
b = rgb[2];
} else if (rgb.indexOf('rgb')!=-1) {
rgbArr = rgb.substr(rgb.indexOf("(")+1,rgb.lastIndexOf(")")-rgb.indexOf("(")-1).split(",");
r = rgbArr[0];
g = rgbArr[1];
b = rgbArr[2];
} else {
if (rgb.substr(0, 1) == '#') {
rgb = rgb.substr(1);
}
r = this.hexToDec(rgb.substr(0, 2));
g = this.hexToDec(rgb.substr(2, 2));
b = this.hexToDec(rgb.substr(4, 2));
}
r = (parseInt(r,10)||0);
g = (parseInt(g,10)||0);
b = (parseInt(b,10)||0);
if (r < 0 || r > 255)
r = 0;
if (g < 0 || g > 255)
g = 0;
if (b < 0 || b > 255)
b = 0;
return [r,g,b];
}
dhtmlx.math.hsvToRgb = function(h, s, v){
var hi,f,p,q,t,r,g,b;
hi = Math.floor((h/60))%6;
f = h/60-hi;
p = v*(1-s);
q = v*(1-f*s);
t = v*(1-(1-f)*s);
r = 0;
g = 0;
b = 0;
switch(hi) {
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;
}
r = Math.floor(r*255);
g = Math.floor(g*255);
b = Math.floor(b*255);
return [r, g, b];
};
dhtmlx.math.rgbToHsv = function(r, g, b){
var r0,g0,b0,min0,max0,s,h,v;
r0 = r/255;
g0 = g/255;
b0 = b/255;
var min0 = Math.min(r0, g0, b0);
var max0 = Math.max(r0, g0, b0);
h = 0;
s = max0==0?0:(1-min0/max0);
v = max0;
if (max0 == min0) {
h = 0;
} else if (max0 == r0 && g0>=b0) {
h = 60*(g0 - b0)/(max0 - min0)+0;
} else if (max0 == r0 && g0 < b0) {
h = 60*(g0 - b0)/(max0 - min0)+360;
} else if (max0 == g0) {
h = 60*(b0 - r0)/(max0-min0)+120;
} else if (max0 == b0) {
h = 60*(r0 - g0)/(max0 - min0)+240;
}
return [h, s, v];
}
/* DHX DEPEND FROM FILE 'ext/chart/presets.js'*/
/*chart presents*/
if(!dhtmlx.presets)
dhtmlx.presets = {};
dhtmlx.presets.chart = {
"simple":{
item:{
borderColor: "#ffffff",
color: "#2b7100",
shadow: false,
borderWidth:2
},
line:{
color:"#8ecf03",
width:2
}
},
"plot":{
color:"#1293f8",
item:{
borderColor:"#636363",
borderWidth:1,
color: "#ffffff",
type:"r",
shadow: false
},
line:{
color:"#1293f8",
width:2
}
},
"diamond":{
color:"#b64040",
item:{
borderColor:"#b64040",
color: "#b64040",
type:"d",
radius:3,
shadow:true
},
line:{
color:"#ff9000",
width:2
}
},
"point":{
color:"#fe5916",
disableLines:true,
fill:false,
disableItems:false,
item:{
color:"#feb916",
borderColor:"#fe5916",
radius:2,
borderWidth:1,
type:"r"
},
alpha:1
},
"line":{
line:{
color:"#3399ff",
width:2
},
item:{
color:"#ffffff",
borderColor:"#3399ff",
radius:2,
borderWidth:2,
type:"d"
},
fill:false,
disableItems:false,
disableLines:false,
alpha:1
},
"area":{
fill:"#3399ff",
line:{
color:"#3399ff",
width:1
},
disableItems:true,
alpha: 0.2,
disableLines:false
},
"round":{
item:{
radius:3,
borderColor:"#3f83ff",
borderWidth:1,
color:"#3f83ff",
type:"r",
shadow:false,
alpha:0.6
}
},
"square":{
item:{
radius:3,
borderColor:"#447900",
borderWidth:2,
color:"#69ba00",
type:"s",
shadow:false,
alpha:1
}
},
/*bar*/
"column":{
color:"RAINBOW",
gradient:false,
width:45,
radius:0,
alpha:1,
border:true
},
"stick":{
width:5,
gradient:false,
color:"#67b5c9",
radius:2,
alpha:1,
border:false
},
"alpha":{
color:"#b9a8f9",
width:70,
gradient:"falling",
radius:0,
alpha:0.5,
border:true
}
};
/* DHX DEPEND FROM FILE 'map.js'*/
/*DHX:Depend dhtmlx.js*/
dhtmlx.ui.Map = function(key){
this.name = "Map";
this._id = "map_"+dhtmlx.uid();
this._key = key;
this._map = [];
};
dhtmlx.ui.Map.prototype = {
addRect: function(id,points,userdata) {
this._createMapArea(id,"RECT",points,userdata);
},
addPoly: function(id,points,userdata) {
this._createMapArea(id,"POLY",points,userdata);
},
_createMapArea:function(id,shape,coords,userdata){
var extra_data = "";
if(arguments.length==4)
extra_data = "userdata='"+userdata+"'";
this._map.push("<area "+this._key+"='"+id+"' shape='"+shape+"' coords='"+coords.join()+"' "+extra_data+"></area>");
},
addSector:function(id,alpha0,alpha1,x,y,R,ky,userdata){
var points = [];
points.push(x);
points.push(Math.floor(y*ky));
for(var i = alpha0; i < alpha1; i+=Math.PI/18){
points.push(Math.floor(x+R*Math.cos(i)));
points.push(Math.floor((y+R*Math.sin(i))*ky));
}
points.push(Math.floor(x+R*Math.cos(alpha1)));
points.push(Math.floor((y+R*Math.sin(alpha1))*ky));
points.push(x);
points.push(Math.floor(y*ky));
return this.addPoly(id,points,userdata);
},
render:function(obj){
var d = dhtmlx.html.create("DIV");
d.style.cssText="position:absolute; width:100%; height:100%; top:0px; left:0px;";
obj.appendChild(d);
var src = dhtmlx._isIE?"":"src='data:image/gif;base64,R0lGODlhEgASAIAAAP///////yH5BAUUAAEALAAAAAASABIAAAIPjI+py+0Po5y02ouz3pwXADs='";
d.innerHTML="<map id='"+this._id+"' name='"+this._id+"'>"+this._map.join("\n")+"</map><img "+src+" class='dhx_map_img' usemap='#"+this._id+"'>";
obj._htmlmap = d; //for clearing routine
this._map = [];
}
};
/* DHX DEPEND FROM FILE 'ext/chart/chart_base.js'*/
/*DHX:Depend map.js*/
dhtmlx.chart = {};
/* DHX DEPEND FROM FILE 'ext/chart/chart_scatter.js'*/
/*DHX:Depend ext/chart/chart_base.js*/
dhtmlx.chart.scatter = {
/**
* renders a graphic
* @param: ctx - canvas object
* @param: data - object those need to be displayed
* @param: point0 - top left point of a chart
* @param: point1 - right bottom point of a chart
* @param: sIndex - index of drawing chart
* @param: map - map object
*/
pvt_render_scatter:function(ctx, data, point0, point1, sIndex, map){
if(!this._settings.xValue)
return dhtmlx.log("warning","Undefined propery: xValue");
/*max in min values*/
var limitsY = this._getLimits();
var limitsX = this._getLimits("h","xValue");
/*render scale*/
if(!sIndex){
if(!this.canvases["x"])
this.canvases["x"] = new dhtmlx.ui.Canvas(this._obj,"axis_x");
if(!this.canvases["y"])
this.canvases["y"] = new dhtmlx.ui.Canvas(this._obj,"axis_y");
this._drawYAxis(this.canvases["y"].getCanvas(),data,point0,point1,limitsY.min,limitsY.max);
this._drawHXAxis(this.canvases["x"].getCanvas(),data,point0,point1,limitsX.min,limitsX.max);
}
limitsY = {min:this._settings.yAxis.start,max:this._settings.yAxis.end};
limitsX = {min:this._settings.xAxis.start,max:this._settings.xAxis.end};
var params = this._getScatterParams(ctx,data,point0,point1,limitsX,limitsY);
this._mapStart = point0;
for(var i=0;i<data.length;i++){
this._drawScatterItem(ctx,map,point0, point1, params,limitsX,limitsY,data[i],sIndex);
}
},
_getScatterParams:function(ctx, data, point0, point1,limitsX,limitsY){
var params = {};
/*available space*/
params.totalHeight = point1.y-point0.y;
/*available width*/
params.totalWidth = point1.x-point0.x;
/*unit calculation (y_position = value*unit)*/
this._calcScatterUnit(params,limitsX.min,limitsX.max,params.totalWidth,"X");
this._calcScatterUnit(params,limitsY.min,limitsY.max,params.totalHeight,"Y");
return params;
},
_drawScatterItem:function(ctx,map,point0, point1,params,limitsX,limitsY,obj,sIndex){
var x0 = this._calculateScatterItemPosition(params, point1, point0, limitsX, obj, "X");
var y0 = this._calculateScatterItemPosition(params, point0, point1, limitsY, obj, "Y");
this. _drawItem(ctx,x0,y0,obj,this._settings.label.call(this,obj),sIndex,map);
},
_calculateScatterItemPosition:function(params, point0, point1, limits, obj, axis){
/*the real value of an object*/
var value = this._settings[axis=="X"?"xValue":"value"].call(this,obj);
/*a relative value*/
var valueFactor = params["valueFactor"+axis];
var v = (parseFloat(value||0) - limits.min)*valueFactor;
/*a vertical coordinate*/
var unit = params["unit"+axis];
var pos = point1[axis.toLowerCase()] - (axis=="X"?(-1):1)*Math.floor(unit*v);
/*the limit of the minimum value is the minimum visible value*/
if(v<0)
pos = point1[axis.toLowerCase()];
/*the limit of the maximum value*/
if(value > limits.max)
pos = point0[axis.toLowerCase()];
/*the limit of the minimum value*/
if(value < limits.min)
pos = point1[axis.toLowerCase()];
return pos;
},
_calcScatterUnit:function(p,min,max,size,axis){
var relativeValues = this._getRelativeValue(min,max);
axis = (axis||"");
p["relValue"+axis] = relativeValues[0];
p["valueFactor"+axis] = relativeValues[1];
p["unit"+axis] = (p["relValue"+axis]?size/p["relValue"+axis]:10);
}
};
/* DHX DEPEND FROM FILE 'ext/chart/chart_radar.js'*/
/*DHX:Depend ext/chart/chart_base.js*/
dhtmlx.chart.radar = {
pvt_render_radar:function(ctx,data,x,y,sIndex,map){
this._renderRadarChart(ctx,data,x,y,sIndex,map);
},
/**
* renders a pie chart
* @param: ctx - canvas object
* @param: data - object those need to be displayed
* @param: x - the width of the container
* @param: y - the height of the container
* @param: ky - value from 0 to 1 that defines an angle of inclination (0<ky<1 - 3D chart)
*/
_renderRadarChart:function(ctx,data,point0,point1,sIndex,map){
if(!data.length)
return;
var coord = this._getPieParameters(point0,point1);
/*scale radius*/
var radius = (this._settings.radius?this._settings.radius:coord.radius);
/*scale center*/
var x0 = (this._settings.x?this._settings.x:coord.x);
var y0 = (this._settings.y?this._settings.y:coord.y);
/*angles for each unit*/
var ratioUnits = [];
for(var i=0;i<data.length;i++)
ratioUnits.push(1)
var ratios = this._getRatios(ratioUnits,data.length);
this._mapStart = point0;
if(!sIndex)
this._drawRadarAxises(ratios,x0,y0,radius,data);
this._drawRadarData(ctx,ratios,x0,y0,radius,data,sIndex,map);
},
_drawRadarData:function(ctx,ratios,x,y,radius,data,sIndex,map){
var alpha0 ,alpha1, config, i, min, max, pos0, pos1, posArr,
r0, r1, relValue, startAlpha, value, value0, value1, valueFactor,
unit, unitArr;
config = this._settings;
/*unit calculation (item_radius_pos = value*unit)*/
min = config.yAxis.start;
max = config.yAxis.end;
unitArr = this._getRelativeValue(min,max);
relValue = unitArr[0];
unit = (relValue?radius/relValue:radius/2);
valueFactor = unitArr[1];
startAlpha = -Math.PI/2;
alpha0 = alpha1 = startAlpha;
posArr = [];
pos1 = 0;
for(i=0;i<data.length;i++){
if(!value1){
value = config.value(data[i]);
/*a relative value*/
value0 = (parseFloat(value||0) - min)*valueFactor;
}
else
value0 = value1;
r0 = Math.floor(unit*value0);
value = config.value((i!=(data.length-1))?data[i+1]:data[0]);
value1 = (parseFloat(value||0) - min)*valueFactor;
r1 = Math.floor(unit*value1);
alpha0 = alpha1;
alpha1 = ((i!=(data.length-1))?(startAlpha+ratios[i]-0.0001):startAlpha);
pos0 = (pos1||this._getPositionByAngle(alpha0,x,y,r0));
pos1 = this._getPositionByAngle(alpha1,x,y,r1);
/*creates map area*/
/*areaWidth = (config.eventRadius||(parseInt(config.item.radius.call(this,data[i]),10)+config.item.borderWidth));
map.addRect(data[i].id,[pos0.x-areaWidth,pos0.y-areaWidth,pos0.x+areaWidth,pos0.y+areaWidth],sIndex);*/
//this._drawLine(ctx,pos0.x,pos0.y,pos1.x,pos1.y,config.line.color.call(this,data[i]),config.line.width)
posArr.push(pos0);
}
if(config.fill)
this._fillRadarChart(ctx,posArr,data);
if(!config.disableLines)
this._strokeRadarChart(ctx,posArr,data);
if(!config.disableItems)
this._drawRadarItemMarkers(ctx,posArr,data,sIndex,map);
posArr = null;
},
_drawRadarItemMarkers:function(ctx,points,data,sIndex,map){
for(var i=0;i < points.length;i++){
this._drawItem(ctx,points[i].x,points[i].y,data[i],this._settings.label.call(this,data),sIndex,map);
}
},
_fillRadarChart:function(ctx,points,data){
var pos0,pos1;
ctx.globalAlpha= this._settings.alpha.call(this,{});
ctx.beginPath();
for(var i=0;i < points.length;i++){
ctx.fillStyle = this._settings.fill.call(this,data[i]);
pos0 = points[i];
pos1 = (points[i+1]|| points[0]);
if(!i){
ctx.moveTo(pos0.x,pos0.y);
}
ctx.lineTo(pos1.x,pos1.y)
}
ctx.fill();
ctx.globalAlpha=1;
},
_strokeRadarChart:function(ctx,points,data){
var pos0,pos1;
for(var i=0;i < points.length;i++){
pos0 = points[i];
pos1 = (points[i+1]|| points[0]);
this._drawLine(ctx,pos0.x,pos0.y,pos1.x,pos1.y,this._settings.line.color.call(this,data[i]),this._settings.line.width)
}
},
_drawRadarAxises:function(ratios,x,y,radius,data){
var configY = this._settings.yAxis;
var configX = this._settings.xAxis;
var start = configY.start;
var end = configY.end;
var step = configY.step;
var scaleParam= {};
var config = this._configYAxis;
if(typeof config.step =="undefined"||typeof config.start=="undefined"||typeof config.end =="undefined"){
var limits = this._getLimits();
scaleParam = this._calculateScale(limits.min,limits.max);
start = scaleParam.start;
end = scaleParam.end;
step = scaleParam.step;
configY.end = end;
configY.start = start;
}
var units = [];
var i,j,p;
var c=0;
var stepHeight = radius*step/(end-start);
/*correction for small step*/
var power,corr;
if(step<1){
power = Math.min(this._log10(step),(start<=0?0:this._log10(start)));
corr = Math.pow(10,-power);
}
var angles = [];
if(!this.canvases["scale"])
this.canvases["scale"] = new dhtmlx.ui.Canvas(this._obj,"radar_scale");
var ctx = this.canvases["scale"].getCanvas();
for(i = end; i>=start; i -=step){
if(scaleParam.fixNum) i = parseFloat((new Number(i)).toFixed(scaleParam.fixNum));
units.push(Math.floor(c*stepHeight)+ 0.5);
if(corr){
i = Math.round(i*corr)/corr;
}
var unitY = y-radius+units[units.length-1];
this.canvases["scale"].renderTextAt("middle","left",x,unitY,
configY.template(i.toString()),
"dhx_axis_item_y dhx_radar"
);
if(ratios.length<2){
this._drawScaleSector(ctx,"arc",x,y,radius-units[units.length-1],-Math.PI/2,3*Math.PI/2,i);
return;
}
var startAlpha = -Math.PI/2;/*possibly need to moved in config*/
var alpha0 = startAlpha;
var alpha1;
for(j=0;j< ratios.length;j++){
if(i==end)
angles.push(alpha0);
alpha1 = startAlpha+ratios[j]-0.0001;
this._drawScaleSector(ctx,(config.lineShape||"line"),x,y,radius-units[units.length-1],alpha0,alpha1,i,j,data[i]);
alpha0 = alpha1;
}
c++;
}
/*renders radius lines and labels*/
for(i=0;i< angles.length;i++){
p = this._getPositionByAngle(angles[i],x,y,radius);
if(configX.lines.call(this,data[i],i))
this._drawLine(ctx,x,y,p.x,p.y,(configX?configX.lineColor.call(this,data[i]):"#cfcfcf"),1);
this._drawRadarScaleLabel(ctx,x,y,radius,angles[i],(configX?configX.template.call(this,data[i]):"&nbsp;"));
}
},
_drawScaleSector:function(ctx,shape,x,y,radius,a1,a2,i,j){
var pos1, pos2;
if(radius<0)
return false;
pos1 = this._getPositionByAngle(a1,x,y,radius);
pos2 = this._getPositionByAngle(a2,x,y,radius);
var configY = this._settings.yAxis;
if(configY.bg){
ctx.beginPath();
ctx.moveTo(x,y);
if(shape=="arc")
ctx.arc(x,y,radius,a1,a2,false);
else{
ctx.lineTo(pos1.x,pos1.y);
ctx.lineTo(pos2.x,pos2.y);
}
ctx.fillStyle = configY.bg(i,j);
ctx.moveTo(x,y);
ctx.fill();
ctx.closePath();
}
if(configY.lines.call(this,i)){
ctx.lineWidth = 1;
ctx.beginPath();
if(shape=="arc")
ctx.arc(x,y,radius,a1,a2,false);
else{
ctx.moveTo(pos1.x,pos1.y);
ctx.lineTo(pos2.x,pos2.y);
}
ctx.strokeStyle = configY.lineColor.call(this,i);
ctx.stroke();
}
},
_drawRadarScaleLabel:function(ctx,x,y,r,a,text){
var t = this.canvases["scale"].renderText(0,0,text,"dhx_axis_radar_title",1);
var width = t.scrollWidth;
var height = t.offsetHeight;
var delta = 0.001;
var pos = this._getPositionByAngle(a,x,y,r+5);
var corr_x=0,corr_y=0;
if(a<0||a>Math.PI){
corr_y = -height;
}
if(a>Math.PI/2){
corr_x = -width;
}
if(Math.abs(a+Math.PI/2)<delta||Math.abs(a-Math.PI/2)<delta){
corr_x = -width/2;
}
else if(Math.abs(a)<delta||Math.abs(a-Math.PI)<delta){
corr_y = -height/2;
}
t.style.top = pos.y+corr_y+"px";
t.style.left = pos.x+corr_x+"px";
t.style.width = width+"px";
t.style.whiteSpace = "nowrap";
}
};
/* DHX DEPEND FROM FILE 'ext/chart/chart_area.js'*/
/*DHX:Depend ext/chart/chart_base.js*/
dhtmlx.chart.area = {
/**
* renders an area chart
* @param: ctx - canvas object
* @param: data - object those need to be displayed
* @param: width - the width of the container
* @param: height - the height of the container
* @param: sIndex - index of drawing chart
*/
pvt_render_area:function(ctx, data, point0, point1, sIndex, map){
var align, config, i, mapRect, obj, params, path,
res1, res2, x0, x1, y1, x2, y2, y0;
params = this._calculateLineParams(ctx,data,point0,point1,sIndex);
config = this._settings;
//the size of map area
mapRect = (config.eventRadius||Math.floor(params.cellWidth/2));
if (data.length) {
// area points
path = [];
//the x position of the first item
x0 = (!config.offset?point0.x:point0.x+params.cellWidth*0.5);
/*
iterates over all data items:
calculates [x,y] for area path, adds rect to chart map and renders labels
*/
for(i=0; i < data.length;i ++){
obj = data[i];
res2 = this._getPointY(obj,point0,point1,params);
x2 = x0 + params.cellWidth*i ;
if(res2){
y2 = (typeof res2 == "object"?res2.y0:res2);
if(i && this._settings.fixOverflow){
res1 = this._getPointY(data[i-1],point0,point1,params);
if(res1.out && res1.out == res2.out){
continue;
}
x1 = params.cellWidth*(i-1) - 0.5 + x0;
y1 = (typeof res1 == "object"?res1.y0:res1);
if(res1.out){
y0 = (res1.out == "min"?point1.y:point0.y);
path.push([this._calcOverflowX(x1,x2,y1,y2,y0),y0]);
}
if(res2.out){
y0 = (res2.out == "min"?point1.y:point0.y);
path.push([this._calcOverflowX(x1,x2,y1,y2,y0),y0]);
if(i == (data.length-1) && y0 == point0.y)
path.push([x2,point0.y]);
}
}
if(!res2.out){
path.push([x2,y2]);
//map
map.addRect(obj.id,[x2-mapRect-point0.x,y2-mapRect-point0.y,x2+mapRect-point0.x,y2+mapRect-point0.y],sIndex);
}
//labels
if(!config.yAxis){
align = (!config.offset&&(i == data.length-1)?"left":"center");
this.canvases[sIndex].renderTextAt(false, align, x2, y2-config.labelOffset,config.label(obj));
}
}
}
if(path.length){
path.push([x2,point1.y]);
path.push([path[0][0],point1.y]);
}
//filling area
ctx.globalAlpha = this._settings.alpha.call(this,data[0]);
ctx.fillStyle = this._settings.color.call(this,data[0]);
ctx.beginPath();
this._path(ctx,path);
ctx.fill();
//border
if(config.border){
ctx.lineWidth = config.borderWidth||1;
if(config.borderColor)
ctx.strokeStyle = config.borderColor.call(this,data[0]);
else
this._setBorderStyles(ctx,ctx.fillStyle);
ctx.beginPath();
this._path(ctx,path);
ctx.stroke();
}
ctx.lineWidth = 1;
ctx.globalAlpha =1;
}
}
};
dhtmlx.chart.stackedArea ={
/**
* renders an area chart
* @param: ctx - canvas object
* @param: data - object those need to be displayed
* @param: width - the width of the container
* @param: height - the height of the container
* @param: sIndex - index of drawing chart
*/
pvt_render_stackedArea:function(ctx, data, point0, point1, sIndex, map){
var a0, a1, align, config, i, j, lastItem, mapRect, obj, params, path, x, y, yPos;
params = this._calculateLineParams(ctx,data,point0,point1,sIndex);
config = this._settings;
/*the value that defines the map area position*/
mapRect = (config.eventRadius||Math.floor(params.cellWidth/2));
/*drawing all items*/
if (data.length) {
// area points
path = [];
// y item positions
yPos = [];
//the x position of the first item
x = (!config.offset?point0.x:point0.x+params.cellWidth*0.5);
var setOffset = function(i,y){
return sIndex?(data[i].$startY?y-point1.y+data[i].$startY:0):y;
};
var solveEquation = function(x,p0,p1){
var k = (p1.y - p0.y)/(p1.x - p0.x);
return k*x + p0.y - k*p0.x;
};
/*
iterates over all data items:
calculates [x,y] for area path, adds rect to chart map and renders labels
*/
for(i=0; i < data.length;i ++){
obj = data[i];
if(!i){
y = setOffset(i,point1.y);
path.push([x,y]);
}
else{
x += params.cellWidth ;
}
y = setOffset(i,this._getPointY(obj,point0,point1,params));
yPos.push((isNaN(y)&&!i)?(data[i].$startY||point1.y):y);
if(y){
path.push([x,y]);
//map
map.addRect(obj.id,[x-mapRect-point0.x,y-mapRect-point0.y,x+mapRect-point0.x,y+mapRect-point0.y],sIndex);
//labels
if(!config.yAxis){
align = (!config.offset&&lastItem?"left":"center");
this.canvases[sIndex].renderTextAt(false, align, x, y-config.labelOffset,config.label(obj));
}
}
}
// bottom right point
path.push([x,setOffset(i-1,point1.y)]);
// lower border from the end to start
if(sIndex){
for(i=data.length-2; i > 0; i --){
x -= params.cellWidth ;
y = data[i].$startY;
if(y)
path.push([x,y]);
}
}
// go to start point
path.push([path[0][0],path[0][1]]);
// filling path
ctx.globalAlpha = this._settings.alpha.call(this,data[0]);
ctx.fillStyle = this._settings.color.call(this,data[0]);
ctx.beginPath();
this._path(ctx,path);
ctx.fill();
// set y positions of the next series
for(i=0; i < data.length;i ++){
y = yPos[i];
if(!y){
if(i == data.length-1){
y = data[i].$startY;
}
for(j =i+1; j< data.length; j++){
if(yPos[j]){
a0 = {x:point0.x,y:yPos[0]};
a1 = {x:(point0.x+params.cellWidth*j),y:yPos[j]};
y = solveEquation(point0.x+params.cellWidth*i,a0,a1);
break;
}
}
}
data[i].$startY = y;
}
}
}
};
/* DHX DEPEND FROM FILE 'ext/chart/chart_spline.js'*/
/*DHX:Depend ext/chart/chart_base.js*/
dhtmlx.chart.spline = {
/**
* renders a spline chart
* @param: ctx - canvas object
* @param: data - object those need to be displayed
* @param: width - the width of the container
* @param: height - the height of the container
* @param: sIndex - index of drawing chart
*/
pvt_render_spline:function(ctx, data, point0, point1, sIndex, map){
var config,i,items,j,params,sparam,x,x0,x1,x2,y,y1,y2;
params = this._calculateLineParams(ctx,data,point0,point1,sIndex);
config = this._settings;
this._mapStart = point0;
/*array of all points*/
items = [];
/*drawing all items*/
if (data.length) {
/*getting all points*/
x0 = (config.offset?point0.x+params.cellWidth*0.5:point0.x);
for(i=0; i < data.length;i ++){
y = this._getPointY(data[i],point0,point1,params);
if(y){
x = ((!i)?x0:params.cellWidth*i - 0.5 + x0);
items.push({x:x,y:y,index:i});
}
}
sparam = this._getSplineParameters(items);
for(i =0; i< items.length; i++){
x1 = items[i].x;
y1 = items[i].y;
if(i<items.length-1){
x2 = items[i+1].x;
y2 = items[i+1].y;
for(j = x1; j < x2; j++){
var sY1 = this._getSplineYPoint(j,x1,i,sparam.a,sparam.b,sparam.c,sparam.d);
if(sY1<point0.y)
sY1=point0.y;
if(sY1>point1.y)
sY1=point1.y;
var sY2 = this._getSplineYPoint(j+1,x1,i,sparam.a,sparam.b,sparam.c,sparam.d);
if(sY2<point0.y)
sY2=point0.y;
if(sY2>point1.y)
sY2=point1.y;
this._drawLine(ctx,j,sY1,j+1,sY2,config.line.color(data[i]),config.line.width);
}
this._drawLine(ctx,x2-1,this._getSplineYPoint(j,x1,i,sparam.a,sparam.b,sparam.c,sparam.d),x2,y2,config.line.color(data[i]),config.line.width);
}
this._drawItem(ctx,x1,y1,data[items[i].index],config.label(data[items[i].index]), sIndex, map);
/*creates map area*/
/*radius = (parseInt(config.item.radius.call(this,data[i-1]),10)||2);
areaPos = (config.eventRadius||radius+1);
map.addRect(data[i].id,[x1-areaPos,y1-areaPos,x1+areaPos,y1+areaPos],sIndex); */
}
//this._drawItemOfLineChart(ctx,x2,y2,data[i],config.label(data[i]));
}
},
/*gets spline parameter*/
_getSplineParameters:function(points){
var i,u,v,s,a,b,c,d,
h = [],
m = [],
n = points.length;
for(i =0; i<n-1;i++){
h[i] = points[i+1].x - points[i].x;
m[i] = (points[i+1].y - points[i].y)/h[i];
}
u = []; v = [];
u[0] = 0;
u[1] = 2*(h[0] + h[1]);
v[0] = 0;
v[1] = 6*(m[1] - m[0]);
for(i =2; i < n-1; i++){
u[i] = 2*(h[i-1]+h[i]) - h[i-1]*h[i-1]/u[i-1];
v[i] = 6*(m[i]-m[i-1]) - h[i-1]*v[i-1]/u[i-1];
}
s = [];
s[n-1] = s[0] = 0;
for(i = n -2; i>=1; i--)
s[i] = (v[i] - h[i]*s[i+1])/u[i];
a = []; b = []; c = []; d = [];
for(i =0; i<n-1;i++){
a[i] = points[i].y;
b[i] = - h[i]*s[i+1]/6 - h[i]*s[i]/3 + (points[i+1].y-points[i].y)/h[i];
c[i] = s[i]/2;
d[i] = (s[i+1] - s[i])/(6*h[i]);
}
return {a:a,b:b,c:c,d:d};
},
/*returns the y position of the spline point */
_getSplineYPoint:function(x,xi,i,a,b,c,d){
return a[i] + (x - xi)*(b[i] + (x-xi)*(c[i]+(x-xi)*d[i]));
}
};
/* DHX DEPEND FROM FILE 'ext/chart/chart_barh.js'*/
/*DHX:Depend ext/chart/chart_base.js*/
dhtmlx.chart.barH = {
/**
* renders a bar chart
* @param: ctx - canvas object
* @param: data - object those need to be displayed
* @param: x - the width of the container
* @param: y - the height of the container
* @param: sIndex - index of drawing chart
*/
pvt_render_barH:function(ctx, data, point0, point1, sIndex, map){
var barOffset, barWidth, cellWidth, color, gradient, i, limits, maxValue, minValue,
innerGradient, valueFactor, relValue, radius, relativeValues,
startValue, totalWidth,value, unit, x0, y0, yax;
/*an available width for one bar*/
cellWidth = (point1.y-point0.y)/data.length;
limits = this._getLimits("h");
maxValue = limits.max;
minValue = limits.min;
totalWidth = point1.x-point0.x;
yax = !!this._settings.yAxis;
/*draws x and y scales*/
if(!sIndex)
this._drawHScales(ctx,data,point0, point1,minValue,maxValue,cellWidth);
/*necessary for automatic scale*/
if(yax){
maxValue = parseFloat(this._settings.xAxis.end);
minValue = parseFloat(this._settings.xAxis.start);
}
/*unit calculation (bar_height = value*unit)*/
relativeValues = this._getRelativeValue(minValue,maxValue);
relValue = relativeValues[0];
valueFactor = relativeValues[1];
unit = (relValue?totalWidth/relValue:10);
if(!yax){
/*defines start value for better representation of small values*/
startValue = 10;
unit = (relValue?(totalWidth-startValue)/relValue:10);
}
/*a real bar width */
barWidth = parseInt(this._settings.width,10);
if((barWidth*this._series.length+4)>cellWidth) barWidth = cellWidth/this._series.length-4;
/*the half of distance between bars*/
barOffset = Math.floor((cellWidth - barWidth*this._series.length)/2);
/*the radius of rounding in the top part of each bar*/
radius = (typeof this._settings.radius!="undefined"?parseInt(this._settings.radius,10):Math.round(barWidth/5));
innerGradient = false;
gradient = this._settings.gradient;
if (gradient&&typeof(gradient) != "function"){
innerGradient = gradient;
gradient = false;
} else if (gradient){
gradient = ctx.createLinearGradient(point0.x,point0.y,point1.x,point0.y);
this._settings.gradient(gradient);
}
/*draws a black line if the horizontal scale isn't defined*/
if(!yax){
this._drawLine(ctx,point0.x-0.5,point0.y,point0.x-0.5,point1.y,"#000000",1); //hardcoded color!
}
for(i=0; i < data.length;i ++){
value = parseFloat(this._settings.value(data[i]||0));
if(value>maxValue) value = maxValue;
value -= minValue;
value *= valueFactor;
/*start point (bottom left)*/
x0 = point0.x;
y0 = point0.y+ barOffset + i*cellWidth+(barWidth+1)*sIndex;
if((value<0&&this._settings.origin=="auto")||(this._settings.xAxis&&value===0&&!(this._settings.origin!="auto"&&this._settings.origin>minValue))){
this.canvases[sIndex].renderTextAt("middle", "right", x0+10,y0+barWidth/2+barOffset,this._settings.label(data[i]));
continue;
}
if(value<0&&this._settings.origin!="auto"&&this._settings.origin>minValue){
value = 0;
}
/*takes start value into consideration*/
if(!yax) value += startValue/unit;
color = gradient||this._settings.color.call(this,data[i]);
/*drawing the gradient border of a bar*/
if(this._settings.border){
this._drawBarHBorder(ctx,x0,y0,barWidth,minValue,radius,unit,value,color);
}
/*drawing bar body*/
ctx.globalAlpha = this._settings.alpha.call(this,data[i]);
var points = this._drawBarH(ctx,point1,x0,y0,barWidth,minValue,radius,unit,value,color,gradient,innerGradient);
if (innerGradient!=false){
this._drawBarHGradient(ctx,x0,y0,barWidth,minValue,radius,unit,value,color,innerGradient);
}
ctx.globalAlpha = 1;
/*sets a bar label and map area*/
if(points[3]==y0){
this.canvases[sIndex].renderTextAt("middle", "left", points[0]-5,points[3]+Math.floor(barWidth/2),this._settings.label(data[i]));
map.addRect(data[i].id,[points[0]-point0.x,points[3]-point0.y,points[2]-point0.x,points[3]+barWidth-point0.y],sIndex);
}else{
this.canvases[sIndex].renderTextAt("middle", false, points[2]+5,points[1]+Math.floor(barWidth/2),this._settings.label(data[i]));
map.addRect(data[i].id,[points[0]-point0.x,y0-point0.y,points[2]-point0.x,points[3]-point0.y],sIndex);
}
}
},
/**
* sets points for bar and returns the position of the bottom right point
* @param: ctx - canvas object
* @param: x0 - the x position of start point
* @param: y0 - the y position of start point
* @param: barWidth - bar width
* @param: radius - the rounding radius of the top
* @param: unit - the value defines the correspondence between item value and bar height
* @param: value - item value
* @param: offset - the offset from expected bar edge (necessary for drawing border)
*/
_setBarHPoints:function(ctx,x0,y0,barWidth,radius,unit,value,offset,skipLeft){
/*correction for displaing small values (when rounding radius is bigger than bar height)*/
var angle_corr = 0;
if(radius>unit*value){
var sinA = (radius-unit*value)/radius;
angle_corr = -Math.asin(sinA)+Math.PI/2;
}
/*start*/
ctx.moveTo(x0,y0+offset);
/*start of left rounding*/
var x1 = x0 + unit*value - radius - (radius?0:offset);
if(radius<unit*value)
ctx.lineTo(x1,y0+offset);
/*left rounding*/
var y2 = y0 + radius;
if (radius&&radius>0)
ctx.arc(x1,y2,radius-offset,-Math.PI/2+angle_corr,0,false);
/*start of right rounding*/
var y3 = y0 + barWidth - radius - (radius?0:offset);
var x3 = x1 + radius - (radius?offset:0);
ctx.lineTo(x3,y3);
/*right rounding*/
if (radius&&radius>0)
ctx.arc(x1,y3,radius-offset,0,Math.PI/2-angle_corr,false);
/*bottom right point*/
var y5 = y0 + barWidth-offset;
ctx.lineTo(x0,y5);
/*line to the start point*/
if(!skipLeft){
ctx.lineTo(x0,y0+offset);
}
// ctx.lineTo(x0,0); //IE fix!
return [x3,y5];
},
_drawHScales:function(ctx,data,point0,point1,start,end,cellWidth){
var x = 0;
if(this._settings.xAxis){
if(!this.canvases["x"])
this.canvases["x"] = new dhtmlx.ui.Canvas(this._obj);
x = this._drawHXAxis(this.canvases["x"].getCanvas(),data,point0,point1,start,end);
}
if (this._settings.yAxis){
if(!this.canvases["y"])
this.canvases["y"] = new dhtmlx.ui.Canvas(this._obj);
this._drawHYAxis(this.canvases["y"].getCanvas(),data,point0,point1,cellWidth,x);
}
},
_drawHYAxis:function(ctx,data,point0,point1,cellWidth,yAxisX){
if (!this._settings.yAxis) return;
var unitPos;
var x0 = parseInt((yAxisX?yAxisX:point0.x),10)-0.5;
var y0 = point1.y+0.5;
var y1 = point0.y;
this._drawLine(ctx,x0,y0,x0,y1,this._settings.yAxis.color,1);
for(var i=0; i < data.length;i ++){
/*scale labels*/
var right = ((this._settings.origin!="auto")&&(this._settings.view=="barH")&&(parseFloat(this._settings.value(data[i]))<this._settings.origin));
unitPos = y1+cellWidth/2+i*cellWidth;
this.canvases["y"].renderTextAt("middle",(right?false:"left"),(right?x0+5:x0-5),unitPos,
this._settings.yAxis.template(data[i]),
"dhx_axis_item_y",(right?0:x0-10)
);
if(this._settings.yAxis.lines.call(this,data[i]))
this._drawLine(ctx,point0.x,unitPos,point1.x,unitPos,this._settings.yAxis.lineColor.call(this,data[i]),1);
}
this._drawLine(ctx,point0.x+0.5,y1+0.5,point1.x,y1+0.5,this._settings.yAxis.lineColor.call(this,{}),1);
this._setYAxisTitle(point0,point1);
},
_drawHXAxis:function(ctx,data,point0,point1,start,end){
var step;
var scaleParam= {};
var axis = this._settings.xAxis;
if (!axis) return;
var y0 = point1.y+0.5;
var x0 = point0.x-0.5;
var x1 = point1.x-0.5;
var yAxisStart = point0.x;
this._drawLine(ctx,x0,y0,x1,y0,axis.color,1);
if(axis.step)
step = parseFloat(axis.step);
if(typeof this._configXAxis.step =="undefined"||typeof this._configXAxis.start=="undefined"||typeof this._configXAxis.end =="undefined"){
scaleParam = this._calculateScale(start,end);
start = scaleParam.start;
end = scaleParam.end;
step = scaleParam.step;
this._settings.xAxis.end = end;
this._settings.xAxis.start = start;
this._settings.xAxis.step = step;
}
if(step===0) return;
var stepHeight = (x1-x0)*step/(end-start);
var c = 0;
for(var i = start; i<=end; i += step){
if(scaleParam.fixNum) i = parseFloat((new Number(i)).toFixed(scaleParam.fixNum));
var xi = Math.floor(x0+c*stepHeight)+ 0.5;/*canvas line fix*/
if(!(i==start&&this._settings.origin=="auto") &&axis.lines.call(this,i))
this._drawLine(ctx,xi,y0,xi,point0.y,this._settings.xAxis.lineColor.call(this,i),1);
if(i == this._settings.origin) yAxisStart = xi+1;
this.canvases["x"].renderTextAt(false, true,xi,y0+2,axis.template(i.toString()),"dhx_axis_item_x");
c++;
}
this.canvases["x"].renderTextAt(true, false, x0,point1.y+this._settings.padding.bottom-3,
this._settings.xAxis.title,
"dhx_axis_title_x",
point1.x - point0.x
);
/*the right border in lines in scale are enabled*/
if (!axis.lines.call(this,{})){
this._drawLine(ctx,x0,point0.y-0.5,x1,point0.y-0.5,this._settings.xAxis.color,0.2);
}
return yAxisStart;
},
_correctBarHParams:function(ctx,x,y,value,unit,barWidth,minValue){
var yax = this._settings.yAxis;
var axisStart = x;
if(!!yax&&this._settings.origin!="auto" && (this._settings.origin>minValue)){
x += (this._settings.origin-minValue)*unit;
axisStart = x;
value = value-(this._settings.origin-minValue);
if(value < 0){
value *= (-1);
ctx.translate(x,y+barWidth);
ctx.rotate(Math.PI);
x = 0.5;
y = 0;
}
x += 0.5;
}
return {value:value,x0:x,y0:y,start:axisStart}
},
_drawBarH:function(ctx,point1,x0,y0,barWidth,minValue,radius,unit,value,color,gradient,inner_gradient){
ctx.save();
var p = this._correctBarHParams(ctx,x0,y0,value,unit,barWidth,minValue);
ctx.fillStyle = color;
ctx.beginPath();
var points = this._setBarHPoints(ctx,p.x0,p.y0,barWidth,radius,unit,p.value,(this._settings.border?1:0));
if (gradient&&!inner_gradient) ctx.lineTo(point1.x,p.y0+(this._settings.border?1:0)); //fix gradient sphreading
ctx.fill();
ctx.restore();
var y1 = p.y0;
var y2 = (p.y0!=y0?y0:points[1]);
var x1 = (p.y0!=y0?(p.start-points[0]):p.start);
var x2 = (p.y0!=y0?p.start:points[0]);
return [x1,y1,x2,y2];
},
_drawBarHBorder:function(ctx,x0,y0,barWidth,minValue,radius,unit,value,color){
ctx.save();
var p = this._correctBarHParams(ctx,x0,y0,value,unit,barWidth,minValue);
ctx.beginPath();
this._setBorderStyles(ctx,color);
ctx.globalAlpha =0.9;
this._setBarHPoints(ctx,p.x0,p.y0,barWidth,radius,unit,p.value,ctx.lineWidth/2,1);
ctx.stroke();
ctx.restore();
},
_drawBarHGradient:function(ctx,x0,y0,barWidth,minValue,radius,unit,value,color,inner_gradient){
ctx.save();
//y0 -= (dhx.env.isIE?0:0.5);
var p = this._correctBarHParams(ctx,x0,y0,value,unit,barWidth,minValue);
var gradParam = this._setBarGradient(ctx,p.x0,p.y0+barWidth,p.x0+unit*p.value,p.y0,inner_gradient,color,"x");
ctx.fillStyle = gradParam.gradient;
ctx.beginPath();
this._setBarHPoints(ctx,p.x0,p.y0+gradParam.offset,barWidth-gradParam.offset*2,radius,unit,p.value,gradParam.offset);
ctx.fill();
ctx.globalAlpha = 1;
ctx.restore();
}
};
/* DHX DEPEND FROM FILE 'ext/chart/chart_stackedbarh.js'*/
/*DHX:Depend ext/chart/chart_base.js*/
/*DHX:Depend ext/chart/chart_barh.js*/
dhtmlx.assert(dhtmlx.chart.barH);
dhtmlx.chart.stackedBarH = {
/**
* renders a bar chart
* @param: ctx - canvas object
* @param: data - object those need to be displayed
* @param: x - the width of the container
* @param: y - the height of the container
* @param: sIndex - index of drawing chart
* @param: map - map object
*/
pvt_render_stackedBarH:function(ctx, data, point0, point1, sIndex, map){
var maxValue,minValue;
/*necessary if maxValue - minValue < 0*/
var valueFactor;
/*maxValue - minValue*/
var relValue;
var total_width = point1.x-point0.x;
var yax = !!this._settings.yAxis;
var limits = this._getStackedLimits(data);
maxValue = limits.max;
minValue = limits.min;
/*an available width for one bar*/
var cellWidth = Math.floor((point1.y-point0.y)/data.length);
/*draws x and y scales*/
if(!sIndex)
this._drawHScales(ctx,data,point0, point1,minValue,maxValue,cellWidth);
/*necessary for automatic scale*/
if(yax){
maxValue = parseFloat(this._settings.xAxis.end);
minValue = parseFloat(this._settings.xAxis.start);
}
/*unit calculation (bar_height = value*unit)*/
var relativeValues = this._getRelativeValue(minValue,maxValue);
relValue = relativeValues[0];
valueFactor = relativeValues[1];
var unit = (relValue?total_width/relValue:10);
if(!yax){
/*defines start value for better representation of small values*/
var startValue = 10;
unit = (relValue?(total_width-startValue)/relValue:10);
}
/*a real bar width */
var barWidth = parseInt(this._settings.width,10);
if((barWidth+4)>cellWidth) barWidth = cellWidth-4;
/*the half of distance between bars*/
var barOffset = (cellWidth - barWidth)/2;
/*the radius of rounding in the top part of each bar*/
var radius = 0;
var inner_gradient = false;
var gradient = this._settings.gradient;
if (gradient){
inner_gradient = true;
}
/*draws a black line if the horizontal scale isn't defined*/
if(!yax){
this._drawLine(ctx,point0.x-0.5,point0.y,point0.x-0.5,point1.y,"#000000",1); //hardcoded color!
}
var seriesNumber = 0;
var seriesIndex = 0;
for(i=0; i<this._series.length; i++ ){
if(i == sIndex){
seriesIndex = seriesNumber;
}
if(this._series[i].view == "stackedBarH")
seriesNumber++;
}
for(var i=0; i < data.length;i ++){
if(!seriesIndex)
data[i].$startX = point0.x;
var value = parseFloat(this._settings.value(data[i]||0));
if(value>maxValue) value = maxValue;
value -= minValue;
value *= valueFactor;
/*start point (bottom left)*/
var x0 = point0.x;
var y0 = point0.y+ barOffset + i*cellWidth;
if(!seriesIndex)
data[i].$startX = x0;
else
x0 = data[i].$startX;
if(value<0||(this._settings.yAxis&&value===0)){
this.canvases["y"].renderTextAt("middle", true, x0+10,y0+barWidth/2,this._settings.label(data[i]));
continue;
}
/*takes start value into consideration*/
if(!yax) value += startValue/unit;
var color = this._settings.color.call(this,data[i]);
/*drawing bar body*/
ctx.globalAlpha = this._settings.alpha.call(this,data[i]);
ctx.fillStyle = this._settings.color.call(this,data[i]);
ctx.beginPath();
var points = this._setBarHPoints(ctx,x0,y0,barWidth,radius,unit,value,(this._settings.border?1:0));
if (gradient&&!inner_gradient) ctx.lineTo(point0.x+total_width,y0+(this._settings.border?1:0)); //fix gradient sphreading
ctx.fill();
if (inner_gradient!=false){
var gradParam = this._setBarGradient(ctx,x0,y0+barWidth,x0,y0,inner_gradient,color,"x");
ctx.fillStyle = gradParam.gradient;
ctx.beginPath();
points = this._setBarHPoints(ctx,x0,y0, barWidth,radius,unit,value,0);
ctx.fill();
}
/*drawing the gradient border of a bar*/
if(this._settings.border){
this._drawBarHBorder(ctx,x0,y0,barWidth,minValue,radius,unit,value,color);
}
ctx.globalAlpha = 1;
/*sets a bar label*/
this.canvases[sIndex].renderTextAt("middle",true,data[i].$startX+(points[0]-data[i].$startX)/2-1, y0+(points[1]-y0)/2, this._settings.label(data[i]));
/*defines a map area for a bar*/
map.addRect(data[i].id,[data[i].$startX-point0.x,y0-point0.y,points[0]-point0.x,points[1]-point0.y],sIndex);
/*the start position for the next series*/
data[i].$startX = points[0];
}
}
};
/* DHX DEPEND FROM FILE 'ext/chart/chart_stackedbar.js'*/
/*DHX:Depend ext/chart/chart_base.js*/
dhtmlx.chart.stackedBar = {
/**
* renders a bar chart
* @param: ctx - canvas object
* @param: data - object those need to be displayed
* @param: x - the width of the container
* @param: y - the height of the container
* @param: sIndex - index of drawing chart
*/
pvt_render_stackedBar:function(ctx, data, point0, point1, sIndex, map){
var maxValue,minValue;
/*necessary if maxValue - minValue < 0*/
var valueFactor;
/*maxValue - minValue*/
var relValue;
var total_height = point1.y-point0.y;
var yax = !!this._settings.yAxis;
var xax = !!this._settings.xAxis;
var limits = this._getStackedLimits(data);
maxValue = limits.max;
minValue = limits.min;
/*an available width for one bar*/
var cellWidth = Math.floor((point1.x-point0.x)/data.length);
/*draws x and y scales*/
if(!sIndex)
this._drawScales(data,point0, point1,minValue,maxValue,cellWidth);
/*necessary for automatic scale*/
if(yax){
maxValue = parseFloat(this._settings.yAxis.end);
minValue = parseFloat(this._settings.yAxis.start);
}
/*unit calculation (bar_height = value*unit)*/
var relativeValues = this._getRelativeValue(minValue,maxValue);
relValue = relativeValues[0];
valueFactor = relativeValues[1];
var unit = (relValue?total_height/relValue:10);
/*a real bar width */
var barWidth = parseInt(this._settings.width,10);
if(barWidth+4 > cellWidth) barWidth = cellWidth-4;
/*the half of distance between bars*/
var barOffset = Math.floor((cellWidth - barWidth)/2);
var inner_gradient = (this._settings.gradient?this._settings.gradient:false);
/*draws a black line if the horizontal scale isn't defined*/
if(!xax){
//scaleY = y-bottomPadding;
this._drawLine(ctx,point0.x,point1.y+0.5,point1.x,point1.y+0.5,"#000000",1); //hardcoded color!
}
for(var i=0; i < data.length;i ++){
var value = parseFloat(this._settings.value(data[i]||0));
if(!value){
if(!sIndex||!data[i].$startY)
data[i].$startY = point1.y;
continue;
}
/*adjusts the first tab to the scale*/
if(!sIndex)
value -= minValue;
value *= valueFactor;
/*start point (bottom left)*/
var x0 = point0.x + barOffset + i*cellWidth;
var y0 = point1.y;
if(!sIndex)
data[i].$startY = y0;
else
y0 = data[i].$startY;
/*the max height limit*/
if(y0 < (point0.y+1)) continue;
if(value<0||(this._settings.yAxis&&value===0)){
this.canvases["y"].renderTextAt(true, true, x0+Math.floor(barWidth/2),y0,this._settings.label(data[i]));
continue;
}
var color = this._settings.color.call(this,data[i]);
/*drawing bar body*/
ctx.globalAlpha = this._settings.alpha.call(this,data[i]);
ctx.fillStyle = this._settings.color.call(this,data[i]);
ctx.beginPath();
var points = this._setStakedBarPoints(ctx,x0-(this._settings.border?0.5:0),y0,barWidth+(this._settings.border?0.5:0),unit,value,0,point0.y);
ctx.fill();
/*gradient*/
if (inner_gradient){
ctx.save();
var gradParam = this._setBarGradient(ctx,x0,y0,x0+barWidth,points[1],inner_gradient,color,"y");
ctx.fillStyle = gradParam.gradient;
ctx.beginPath();
points = this._setStakedBarPoints(ctx,x0+gradParam.offset,y0,barWidth-gradParam.offset*2,unit,value,(this._settings.border?1:0),point0.y);
ctx.fill();
ctx.restore()
}
/*drawing the gradient border of a bar*/
if(this._settings.border){
ctx.save();
this._setBorderStyles(ctx,color);
ctx.beginPath();
this._setStakedBarPoints(ctx,x0-0.5,y0,barWidth+1,unit,value,0,point0.y,1);
ctx.stroke();
ctx.restore();
}
ctx.globalAlpha = 1;
/*sets a bar label*/
this.canvases[sIndex].renderTextAt(false, true, x0+Math.floor(barWidth/2),(points[1]+(y0-points[1])/2)-7,this._settings.label(data[i]));
/*defines a map area for a bar*/
map.addRect(data[i].id,[x0-point0.x,points[1]-point0.y,points[0]-point0.x,(data[i].$startY||y0)-point0.y],sIndex);
/*the start position for the next series*/
data[i].$startY = (this._settings.border?(points[1]+1):points[1]);
}
},
/**
* sets points for bar and returns the position of the bottom right point
* @param: ctx - canvas object
* @param: x0 - the x position of start point
* @param: y0 - the y position of start point
* @param: barWidth - bar width
* @param: radius - the rounding radius of the top
* @param: unit - the value defines the correspondence between item value and bar height
* @param: value - item value
* @param: offset - the offset from expected bar edge (necessary for drawing border)
* @param: minY - the minimum y position for the bars ()
*/
_setStakedBarPoints:function(ctx,x0,y0,barWidth,unit,value,offset,minY,skipBottom){
/*start*/
ctx.moveTo(x0,y0);
/*start of left rounding*/
var y1 = y0 - unit*value+offset;
/*maximum height limit*/
if(y1<minY)
y1 = minY;
ctx.lineTo(x0,y1);
var x3 = x0 + barWidth;
var y3 = y1;
ctx.lineTo(x3,y3);
/*right rounding*/
/*bottom right point*/
var x5 = x0 + barWidth;
ctx.lineTo(x5,y0);
/*line to the start point*/
if(!skipBottom){
ctx.lineTo(x0,y0);
}
// ctx.lineTo(x0,0); //IE fix!
return [x5,y3-2*offset];
}
};
/* DHX DEPEND FROM FILE 'ext/chart/chart_line.js'*/
/*DHX:Depend ext/chart/chart_base.js*/
dhtmlx.chart.line = {
/**
* renders a graphic
* @param: ctx - canvas object
* @param: data - object those need to be displayed
* @param: width - the width of the container
* @param: height - the height of the container
* @param: sIndex - index of drawing chart
*/
pvt_render_line:function(ctx, data, point0, point1, sIndex, map){
var config,i,items,params,x0,x1,x2,y1,y2,y0,res1,res2;
params = this._calculateLineParams(ctx,data,point0,point1,sIndex);
config = this._settings;
if (data.length) {
x0 = (config.offset?point0.x+params.cellWidth*0.5:point0.x);
//finds items with data (excludes scale units)
items= [];
for(i=0; i < data.length;i++){
res2 = this._getPointY(data[i],point0,point1,params);
if(res2){
x2 = ((!i)?x0:params.cellWidth*i - 0.5 + x0);
y2 = (typeof res2 == "object"?res2.y0:res2);
if(i && this._settings.fixOverflow){
res1 = this._getPointY(data[i-1],point0,point1,params);
if(res1.out && res1.out == res2.out){
continue;
}
x1 = params.cellWidth*(i-1) - 0.5 + x0;
y1 = (typeof res1 == "object"?res1.y0:res1);
if(res1.out){
y0 = (res1.out == "min"?point1.y:point0.y);
items.push({x:this._calcOverflowX(x1,x2,y1,y2,y0),y:y0});
}
if(res2.out){
y0 = (res2.out == "min"?point1.y:point0.y);
items.push({x:this._calcOverflowX(x1,x2,y1,y2,y0),y:y0});
}
}
if(!res2.out)
items.push({x:x2, y: res2, index: i});
}
}
this._mapStart = point0;
for(i = 1; i <= items.length; i++){
//line start position
x1 = items[i-1].x;
y1 = items[i-1].y;
if(i<items.length){
//line end position
x2 = items[i].x;
y2 = items[i].y;
//line
this._drawLine(ctx,x1,y1,x2,y2,config.line.color.call(this,data[i-1]),config.line.width);
//line shadow
if(config.line&&config.line.shadow){
ctx.globalAlpha = 0.3;
this._drawLine(ctx,x1+2,y1+config.line.width+8,x2+2,y2+config.line.width+8,"#eeeeee",config.line.width+3);
ctx.globalAlpha = 1;
}
}
//item
if(typeof items[i-1].index != "undefined")
this._drawItem(ctx,x1,y1,data[items[i-1].index],config.label(data[items[i-1].index]), sIndex, map, point0);
}
}
},
_calcOverflowX: function(x1,x2,y1,y2,y){
return x1 + ( y - y1 )*( x2 - x1 )/( y2 - y1 );
},
/**
* draws an item and its label
* @param: ctx - canvas object
* @param: x0 - the x position of a circle
* @param: y0 - the y position of a circle
* @param: obj - data object
* @param: label - (boolean) defines wherether label needs being drawn
*/
_drawItem:function(ctx,x0,y0,obj,label,sIndex,map){
var config = this._settings.item;
var R = parseInt(config.radius.call(this,obj),10)||0;
var mapStart = this._mapStart;
if(R){
ctx.save();
if(config.shadow){
ctx.lineWidth = 1;
ctx.strokeStyle = "#bdbdbd";
ctx.fillStyle = "#bdbdbd";
var alphas = [0.1,0.2,0.3];
for(var i=(alphas.length-1);i>=0;i--){
ctx.globalAlpha = alphas[i];
ctx.strokeStyle = "#d0d0d0";
ctx.beginPath();
this._strokeChartItem(ctx,x0,y0+2*R/3,R+i+1,config.type);
ctx.stroke();
}
ctx.beginPath();
ctx.globalAlpha = 0.3;
ctx.fillStyle = "#bdbdbd";
this._strokeChartItem(ctx,x0,y0+2*R/3,R+1,config.type);
ctx.fill();
}
ctx.restore();
ctx.lineWidth = config.borderWidth;
ctx.fillStyle = config.color.call(this,obj);
ctx.strokeStyle = config.borderColor.call(this,obj);
ctx.globalAlpha = config.alpha.call(this,obj);
ctx.beginPath();
this._strokeChartItem(ctx,x0,y0,R+1,config.type);
ctx.fill();
ctx.stroke();
ctx.globalAlpha = 1;
}
/*item label*/
if(label)
this.canvases[sIndex].renderTextAt(false, true, x0,y0-R-this._settings.labelOffset,this._settings.label.call(this,obj));
var areaPos = (this._settings.eventRadius||R+1);
map.addRect(obj.id,[x0-areaPos-mapStart.x,y0-areaPos-mapStart.y,x0+areaPos-mapStart.x,y0+areaPos-mapStart.y],sIndex);
},
_strokeChartItem:function(ctx,x0,y0,R,type){
var p=[];
x0 = parseInt(x0,10);
y0 = parseInt(y0,10);
if(type && (type=="square" || type=="s")){
R *= Math.sqrt(2)/2;
p = [
[x0-R-ctx.lineWidth/2,y0-R],
[x0+R,y0-R],
[x0+R,y0+R],
[x0-R,y0+R],
[x0-R,y0-R]
];
}
else if(type && (type=="diamond" || type=="d")){
var corr = (ctx.lineWidth>1?ctx.lineWidth*Math.sqrt(2)/4:0);
p = [
[x0,y0-R],
[x0+R,y0],
[x0,y0+R],
[x0-R,y0],
[x0+corr,y0-R-corr]
];
}
else if(type && (type=="triangle" || type=="t")){
p = [
[x0,y0-R],
[x0+Math.sqrt(3)*R/2,y0+R/2],
[x0-Math.sqrt(3)*R/2,y0+R/2],
[x0,y0-R]
];
}
else
p = [
[x0,y0,R,0,Math.PI*2,true]
];
this._path(ctx,p);
},
/**
* gets the vertical position of the item
* @param: data - data object
* @param: y0 - the y position of chart start
* @param: y1 - the y position of chart end
* @param: params - the object with elements: minValue, maxValue, unit, valueFactor (the value multiple of 10)
*/
_getPointY: function(data,point0,point1,params){
var minValue = params.minValue;
var maxValue = params.maxValue;
var unit = params.unit;
var valueFactor = params.valueFactor;
/*the real value of an object*/
var value = this._settings.value(data);
/*a relative value*/
var v = (parseFloat(value||0) - minValue)*valueFactor;
if(!this._settings.yAxis)
v += params.startValue/unit;
/*a vertical coordinate*/
var y = point1.y - unit*v;
/*the limit of the max and min values*/
if(this._settings.fixOverflow && ( this._settings.view == "line" || this._settings.view == "area")){
if(value > maxValue)
y = {y: point0.y, y0: y, out: "max"};
else if(v<0 || value < minValue)
y = {y: point1.y, y0: y, out: "min"};
}
else{
if(value > maxValue)
y = point0.y;
if(v<0 || value < minValue)
y = point1.y;
}
return y;
},
_calculateLineParams: function(ctx,data,point0,point1,sIndex){
var params = {};
/*maxValue - minValue*/
var relValue;
/*available height*/
params.totalHeight = point1.y-point0.y;
/*a space available for a single item*/
//params.cellWidth = Math.round((point1.x-point0.x)/((!this._settings.offset&&this._settings.yAxis)?(data.length-1):data.length));
params.cellWidth = (point1.x-point0.x)/((!this._settings.offset)?(data.length-1):data.length);
/*scales*/
var yax = !!this._settings.yAxis;
var limits = (this._settings.view.indexOf("stacked")!=-1?this._getStackedLimits(data):this._getLimits());
params.maxValue = limits.max;
params.minValue = limits.min;
/*draws x and y scales*/
if(!sIndex)
this._drawScales(data, point0, point1,params.minValue,params.maxValue,params.cellWidth);
/*necessary for automatic scale*/
if(yax){
params.maxValue = parseFloat(this._settings.yAxis.end);
params.minValue = parseFloat(this._settings.yAxis.start);
}
/*unit calculation (y_position = value*unit)*/
var relativeValues = this._getRelativeValue(params.minValue,params.maxValue);
relValue = relativeValues[0];
params.valueFactor = relativeValues[1];
params.unit = (relValue?params.totalHeight/relValue:10);
params.startValue = 0;
if(!yax){
/*defines start value for better representation of small values*/
params.startValue = 10;
if(params.unit!=params.totalHeight)
params.unit = (relValue?(params.totalHeight - params.startValue)/relValue:10);
}
return params;
}
};
/* DHX DEPEND FROM FILE 'ext/chart/chart_bar.js'*/
/*DHX:Depend ext/chart/chart_base.js*/
dhtmlx.chart.bar = {
/**
* renders a bar chart
* @param: ctx - canvas object
* @param: data - object those need to be displayed
* @param: x - the width of the container
* @param: y - the height of the container
* @param: sIndex - index of drawing chart
*/
pvt_render_bar:function(ctx, data, point0, point1, sIndex, map){
var barWidth, cellWidth,
i,
limits, maxValue, minValue,
relValue, valueFactor, relativeValues,
startValue, unit,
xax, yax,
totalHeight = point1.y-point0.y;
yax = !!this._settings.yAxis;
xax = !!this._settings.xAxis;
limits = this._getLimits();
maxValue = limits.max;
minValue = limits.min;
/*an available width for one bar*/
cellWidth = (point1.x-point0.x)/data.length;
/*draws x and y scales*/
if(!sIndex&&!(this._settings.origin!="auto"&&!yax)){
this._drawScales(data,point0, point1,minValue,maxValue,cellWidth);
}
/*necessary for automatic scale*/
if(yax){
maxValue = parseFloat(this._settings.yAxis.end);
minValue = parseFloat(this._settings.yAxis.start);
}
/*unit calculation (bar_height = value*unit)*/
relativeValues = this._getRelativeValue(minValue,maxValue);
relValue = relativeValues[0];
valueFactor = relativeValues[1];
unit = (relValue?totalHeight/relValue:relValue);
if(!yax&&!(this._settings.origin!="auto"&&xax)){
/*defines start value for better representation of small values*/
startValue = 10;
unit = (relValue?(totalHeight-startValue)/relValue:startValue);
}
/*if yAxis isn't set, but with custom origin */
if(!sIndex&&(this._settings.origin!="auto"&&!yax)&&this._settings.origin>minValue){
this._drawXAxis(ctx,data,point0,point1,cellWidth,point1.y-unit*(this._settings.origin-minValue));
}
/*a real bar width */
barWidth = parseInt(this._settings.width,10);
var seriesNumber = 0;
var seriesIndex = 0;
for(i=0; i<this._series.length; i++ ){
if(i == sIndex){
seriesIndex = seriesNumber;
}
if(this._series[i].view == "bar")
seriesNumber++;
}
if(this._series&&(barWidth*seriesNumber+4)>cellWidth) barWidth = parseInt(cellWidth/seriesNumber-4,10);
/*the half of distance between bars*/
var barOffset = (cellWidth - barWidth*seriesNumber)/2;
/*the radius of rounding in the top part of each bar*/
var radius = (typeof this._settings.radius!="undefined"?parseInt(this._settings.radius,10):Math.round(barWidth/5));
var inner_gradient = false;
var gradient = this._settings.gradient;
if(gradient && typeof(gradient) != "function"){
inner_gradient = gradient;
gradient = false;
} else if (gradient){
gradient = ctx.createLinearGradient(0,point1.y,0,point0.y);
this._settings.gradient(gradient);
}
/*draws a black line if the horizontal scale isn't defined*/
if(!xax){
this._drawLine(ctx,point0.x,point1.y+0.5,point1.x,point1.y+0.5,"#000000",1); //hardcoded color!
}
for(i=0; i < data.length;i ++){
var value = parseFloat(this._settings.value(data[i])||0);
if(isNaN(value))
continue;
if(value>maxValue) value = maxValue;
value -= minValue;
value *= valueFactor;
/*start point (bottom left)*/
var x0 = point0.x + barOffset + parseInt(i*cellWidth,10)+(barWidth+1)*seriesIndex;
var y0 = point1.y;
if(value<0||(this._settings.yAxis&&value===0&&!(this._settings.origin!="auto"&&this._settings.origin>minValue))){
this.canvases[sIndex].renderTextAt(true, true, x0+Math.floor(barWidth/2),y0,this._settings.label(data[i]));
continue;
}
/*takes start value into consideration*/
if(!yax&&!(this._settings.origin!="auto"&&xax)) value += startValue/unit;
var color = gradient||this._settings.color.call(this,data[i]);
/*drawing bar body*/
ctx.globalAlpha = this._settings.alpha.call(this,data[i]);
var points = this._drawBar(ctx,point0,x0,y0,barWidth,minValue,radius,unit,value,color,gradient,inner_gradient);
if (inner_gradient){
this._drawBarGradient(ctx,x0,y0,barWidth,minValue,radius,unit,value,color,inner_gradient);
}
/*drawing the gradient border of a bar*/
if(this._settings.border)
this._drawBarBorder(ctx,x0,y0,barWidth,minValue,radius,unit,value,color);
ctx.globalAlpha = 1;
/*sets a bar label*/
if(points[0]!=x0)
this.canvases[sIndex].renderTextAt(false, true, x0+Math.floor(barWidth/2),points[1],this._settings.label(data[i]));
else
this.canvases[sIndex].renderTextAt(true, true, x0+Math.floor(barWidth/2),points[3],this._settings.label(data[i]));
/*defines a map area for a bar*/
map.addRect(data[i].id,[x0-point0.x,points[3]-point0.y,points[2]-point0.x,points[1]-point0.y],sIndex);
//this._addMapRect(map,data[i].id,[{x:x0,y:points[3]},{x:points[2],y:points[1]}],point0,sIndex);
}
},
_correctBarParams:function(ctx,x,y,value,unit,barWidth,minValue){
var xax = this._settings.xAxis;
var axisStart = y;
if(!!xax&&this._settings.origin!="auto" && (this._settings.origin>minValue)){
y -= (this._settings.origin-minValue)*unit;
axisStart = y;
value = value-(this._settings.origin-minValue);
if(value < 0){
value *= (-1);
ctx.translate(x+barWidth,y);
ctx.rotate(Math.PI);
x = 0;
y = 0;
}
y -= 0.5;
}
return {value:value,x0:x,y0:y,start:axisStart}
},
_drawBar:function(ctx,point0,x0,y0,barWidth,minValue,radius,unit,value,color,gradient,inner_gradient){
ctx.save();
ctx.fillStyle = color;
var p = this._correctBarParams(ctx,x0,y0,value,unit,barWidth,minValue);
var points = this._setBarPoints(ctx,p.x0,p.y0,barWidth,radius,unit,p.value,(this._settings.border?1:0));
if (gradient&&!inner_gradient) ctx.lineTo(p.x0+(this._settings.border?1:0),point0.y); //fix gradient sphreading
ctx.fill();
ctx.restore();
var x1 = p.x0;
var x2 = (p.x0!=x0?x0+points[0]:points[0]);
var y1 = (p.x0!=x0?(p.start-points[1]-p.y0):p.y0);
var y2 = (p.x0!=x0?p.start-p.y0:points[1]);
return [x1,y1,x2,y2];
},
_drawBarBorder:function(ctx,x0,y0,barWidth,minValue,radius,unit,value,color){
var p;
ctx.save();
p = this._correctBarParams(ctx,x0,y0,value,unit,barWidth,minValue);
this._setBorderStyles(ctx,color);
this._setBarPoints(ctx,p.x0,p.y0,barWidth,radius,unit,p.value,ctx.lineWidth/2,1);
ctx.stroke();
/*ctx.fillStyle = color;
this._setBarPoints(ctx,p.x0,p.y0,barWidth,radius,unit,p.value,0);
ctx.lineTo(p.x0,0);
ctx.fill()
ctx.fillStyle = "#000000";
ctx.globalAlpha = 0.37;
this._setBarPoints(ctx,p.x0,p.y0,barWidth,radius,unit,p.value,0);
ctx.fill()
*/
ctx.restore();
},
_drawBarGradient:function(ctx,x0,y0,barWidth,minValue,radius,unit,value,color,inner_gradient){
ctx.save();
//y0 -= (dhtmlx._isIE?0:0.5);
var p = this._correctBarParams(ctx,x0,y0,value,unit,barWidth,minValue);
var gradParam = this._setBarGradient(ctx,p.x0,p.y0,p.x0+barWidth,p.y0-unit*p.value+2,inner_gradient,color,"y");
var borderOffset = this._settings.border?1:0;
ctx.fillStyle = gradParam.gradient;
this._setBarPoints(ctx,p.x0+gradParam.offset,p.y0,barWidth-gradParam.offset*2,radius,unit,p.value,gradParam.offset+borderOffset);
ctx.fill();
ctx.restore();
},
/**
* sets points for bar and returns the position of the bottom right point
* @param: ctx - canvas object
* @param: x0 - the x position of start point
* @param: y0 - the y position of start point
* @param: barWidth - bar width
* @param: radius - the rounding radius of the top
* @param: unit - the value defines the correspondence between item value and bar height
* @param: value - item value
* @param: offset - the offset from expected bar edge (necessary for drawing border)
*/
_setBarPoints:function(ctx,x0,y0,barWidth,radius,unit,value,offset,skipBottom){
/*correction for displaing small values (when rounding radius is bigger than bar height)*/
ctx.beginPath();
//y0 = 0.5;
var angle_corr = 0;
if(radius>unit*value){
var cosA = (radius-unit*value)/radius;
if(cosA<=1&&cosA>=-1)
angle_corr = -Math.acos(cosA)+Math.PI/2;
}
/*start*/
ctx.moveTo(x0+offset,y0);
/*start of left rounding*/
var y1 = y0 - Math.floor(unit*value) + radius + (radius?0:offset);
if(radius<unit*value)
ctx.lineTo(x0+offset,y1);
/*left rounding*/
var x2 = x0 + radius;
if (radius&&radius>0)
ctx.arc(x2,y1,radius-offset,-Math.PI+angle_corr,-Math.PI/2,false);
/*start of right rounding*/
var x3 = x0 + barWidth - radius - offset;
var y3 = y1 - radius + (radius?offset:0);
ctx.lineTo(x3,y3);
/*right rounding*/
if (radius&&radius>0)
ctx.arc(x3,y1,radius-offset,-Math.PI/2,0-angle_corr,false);
/*bottom right point*/
var x5 = x0 + barWidth-offset;
ctx.lineTo(x5,y0);
/*line to the start point*/
if(!skipBottom){
ctx.lineTo(x0+offset,y0);
}
// ctx.lineTo(x0,0); //IE fix!
return [x5,y3];
}
};
/* DHX DEPEND FROM FILE 'ext/chart/chart_pie.js'*/
/*DHX:Depend ext/chart/chart_base.js*/
dhtmlx.chart.pie = {
pvt_render_pie:function(ctx,data,x,y,sIndex,map){
this._renderPie(ctx,data,x,y,1,map,sIndex);
},
/**
* renders a pie chart
* @param: ctx - canvas object
* @param: data - object those need to be displayed
* @param: x - the width of the container
* @param: y - the height of the container
* @param: ky - value from 0 to 1 that defines an angle of inclination (0<ky<1 - 3D chart)
*/
_renderPie:function(ctx,data,point0,point1,ky,map,sIndex){
if(!data.length)
return;
var coord = this._getPieParameters(point0,point1);
/*pie radius*/
var radius = (this._settings.radius?this._settings.radius:coord.radius);
if(radius<0)
return;
/*real values*/
var values = this._getValues(data);
var totalValue = this._getTotalValue(values);
/*weighed values (the ratio of object value to total value)*/
var ratios = this._getRatios(values,totalValue);
/*pie center*/
var x0 = (this._settings.x?this._settings.x:coord.x);
var y0 = (this._settings.y?this._settings.y:coord.y);
/*adds shadow to the 2D pie*/
if(ky==1&&this._settings.shadow)
this._addShadow(ctx,x0,y0,radius);
/*changes vertical position of the center according to 3Dpie cant*/
y0 = y0/ky;
/*the angle defines the 1st edge of the sector*/
var alpha0 = -Math.PI/2;
var angles = [];
/*changes Canvas vertical scale*/
ctx.scale(1,ky);
/*adds radial gradient to a pie*/
if (this._settings.gradient){
var x1 = (ky!=1?x0+radius/3:x0);
var y1 = (ky!=1?y0+radius/3:y0);
this._showRadialGradient(ctx,x0,y0,radius,x1,y1);
}
for(var i = 0; i < data.length;i++){
if (!values[i]) continue;
/*drawing sector*/
//ctx.lineWidth = 2;
ctx.strokeStyle = this._settings.lineColor.call(this,data[i]);
ctx.beginPath();
ctx.moveTo(x0,y0);
angles.push(alpha0);
/*the angle defines the 2nd edge of the sector*/
alpha1 = -Math.PI/2+ratios[i]-0.0001;
ctx.arc(x0,y0,radius,alpha0,alpha1,false);
ctx.lineTo(x0,y0);
var color = this._settings.color.call(this,data[i]);
ctx.fillStyle = color;
ctx.fill();
/*text that needs being displayed inside the sector*/
if(this._settings.pieInnerText)
this._drawSectorLabel(x0,y0,5*radius/6,alpha0,alpha1,ky,this._settings.pieInnerText(data[i],totalValue),true);
/*label outside the sector*/
if(this._settings.label)
this._drawSectorLabel(x0,y0,radius+this._settings.labelOffset,alpha0,alpha1,ky,this._settings.label(data[i]));
/*drawing lower part for 3D pie*/
if(ky!=1){
this._createLowerSector(ctx,x0,y0,alpha0,alpha1,radius,true);
ctx.fillStyle = "#000000";
ctx.globalAlpha = 0.2;
this._createLowerSector(ctx,x0,y0,alpha0,alpha1,radius,false);
ctx.globalAlpha = 1;
ctx.fillStyle = color;
}
/*creats map area (needed for events)*/
map.addSector(data[i].id,alpha0,alpha1,x0-point0.x,y0-point0.y/ky,radius,ky,sIndex);
alpha0 = alpha1;
}
/*renders radius lines and labels*/
ctx.globalAlpha = 0.8;
var p;
for(i=0;i< angles.length;i++){
p = this._getPositionByAngle(angles[i],x0,y0,radius);
this._drawLine(ctx,x0,y0,p.x,p.y,this._settings.lineColor.call(this,data[i]),2);
}
if(ky==1){
ctx.lineWidth = 2;
ctx.strokeStyle = "#ffffff";
ctx.beginPath();
ctx.arc(x0,y0,radius+1,0,2*Math.PI,false);
ctx.stroke();
}
ctx.globalAlpha =1;
ctx.scale(1,1/ky);
},
/**
* returns list of values
* @param: data array
*/
_getValues:function(data){
var v = [];
for(var i = 0; i < data.length;i++)
v.push(parseFloat(this._settings.value(data[i])||0));
return v;
},
/**
* returns total value
* @param: the array of values
*/
_getTotalValue:function(values){
var t=0;
for(var i = 0; i < values.length;i++)
t += values[i];
return t;
},
/**
* gets angles for all values
* @param: the array of values
* @param: total value (optional)
*/
_getRatios:function(values,totalValue){
var value;
var ratios = [];
var prevSum = 0;
totalValue = totalValue||this._getTotalValue(values);
for(var i = 0; i < values.length;i++){
value = values[i];
ratios[i] = Math.PI*2*(totalValue?((value+prevSum)/totalValue):(1/values.length));
prevSum += value;
}
return ratios;
},
/**
* returns calculated pie parameters: center position and radius
* @param: x - the width of a container
* @param: y - the height of a container
*/
_getPieParameters:function(point0,point1){
/*var offsetX = 0;
var offsetY = 0;
if(this._settings.legend &&this._settings.legend.layout!="x")
offsetX = this._settings.legend.width*(this._settings.legend.align=="right"?-1:1);
var x0 = (x + offsetX)/2;
if(this._settings.legend &&this._settings.legend.layout=="x")
offsetY = this._settings.legend.height*(this._settings.legend.valign=="bottom"?-1:1);
var y0 = (y+offsetY)/2;*/
var width = point1.x-point0.x;
var height = point1.y-point0.y;
var x0 = point0.x+width/2;
var y0 = point0.y+height/2;
var radius = Math.min(width/2,height/2);
return {"x":x0,"y":y0,"radius":radius};
},
/**
* creates lower part of sector in 3Dpie
* @param: ctx - canvas object
* @param: x0 - the horizontal position of the pie center
* @param: y0 - the vertical position of the pie center
* @param: a0 - the angle that defines the first edge of a sector
* @param: a1 - the angle that defines the second edge of a sector
* @param: R - pie radius
* @param: line (boolean) - if the sector needs a border
*/
_createLowerSector:function(ctx,x0,y0,a1,a2,R,line){
ctx.lineWidth = 1;
/*checks if the lower sector needs being displayed*/
if(!((a1<=0 && a2>=0)||(a1>=0 && a2<=Math.PI)||(Math.abs(a1-Math.PI)>0.003&&a1<=Math.PI && a2>=Math.PI))) return;
if(a1<=0 && a2>=0){
a1 = 0;
line = false;
this._drawSectorLine(ctx,x0,y0,R,a1,a2);
}
if(a1<=Math.PI && a2>=Math.PI){
a2 = Math.PI;
line = false;
this._drawSectorLine(ctx,x0,y0,R,a1,a2);
}
/*the height of 3D pie*/
var offset = (this._settings.height||Math.floor(R/4))/this._settings.cant;
ctx.beginPath();
ctx.arc(x0,y0,R,a1,a2,false);
ctx.lineTo(x0+R*Math.cos(a2),y0+R*Math.sin(a2)+offset);
ctx.arc(x0,y0+offset,R,a2,a1,true);
ctx.lineTo(x0+R*Math.cos(a1),y0+R*Math.sin(a1));
ctx.fill();
if(line)
ctx.stroke();
},
/**
* draws a serctor arc
*/
_drawSectorLine:function(ctx,x0,y0,R,a1,a2){
ctx.beginPath();
ctx.arc(x0,y0,R,a1,a2,false);
ctx.stroke();
},
/**
* adds a shadow to pie
* @param: ctx - canvas object
* @param: x - the horizontal position of the pie center
* @param: y - the vertical position of the pie center
* @param: R - pie radius
*/
_addShadow:function(ctx,x,y,R){
ctx.globalAlpha = 0.5;
var shadows = ["#c4c4c4","#c6c6c6","#cacaca","#dcdcdc","#dddddd","#e0e0e0","#eeeeee","#f5f5f5","#f8f8f8"];
for(var i = shadows.length-1;i>-1;i--){
ctx.beginPath();
ctx.fillStyle = shadows[i];
ctx.arc(x+1,y+1,R+i,0,Math.PI*2,true);
ctx.fill();
}
ctx.globalAlpha = 1
},
/**
* returns a gray gradient
* @param: gradient - gradient object
*/
_getGrayGradient:function(gradient){
gradient.addColorStop(0.0,"#ffffff");
gradient.addColorStop(0.7,"#7a7a7a");
gradient.addColorStop(1.0,"#000000");
return gradient;
},
/**
* adds gray radial gradient
* @param: ctx - canvas object
* @param: x - the horizontal position of the pie center
* @param: y - the vertical position of the pie center
* @param: radius - pie radius
* @param: x0 - the horizontal position of a gradient center
* @param: y0 - the vertical position of a gradient center
*/
_showRadialGradient:function(ctx,x,y,radius,x0,y0){
//ctx.globalAlpha = 0.3;
ctx.beginPath();
var gradient;
if(typeof this._settings.gradient!= "function"){
gradient = ctx.createRadialGradient(x0,y0,radius/4,x,y,radius);
gradient = this._getGrayGradient(gradient);
}
else gradient = this._settings.gradient(gradient);
ctx.fillStyle = gradient;
ctx.arc(x,y,radius,0,Math.PI*2,true);
ctx.fill();
//ctx.globalAlpha = 1;
ctx.globalAlpha = 0.7;
},
/**
* returns the calculates pie parameters: center position and radius
* @param: ctx - canvas object
* @param: x0 - the horizontal position of the pie center
* @param: y0 - the vertical position of the pie center
* @param: R - pie radius
* @param: alpha1 - the angle that defines the 1st edge of a sector
* @param: alpha2 - the angle that defines the 2nd edge of a sector
* @param: ky - the value that defines an angle of inclination
* @param: text - label text
* @param: in_width (boolean) - if label needs being displayed inside a pie
*/
_drawSectorLabel:function(x0,y0,R,alpha1,alpha2,ky,text,in_width){
var t = this.canvases[0].renderText(0,0,text,0,1);
if (!t) return;
//get existing width of text
var labelWidth = t.scrollWidth;
t.style.width = labelWidth+"px"; //adjust text label to fit all text
if (labelWidth>x0) labelWidth = x0; //the text can't be greater than half of view
//calculate expected correction based on default font metrics
var width = (alpha2-alpha1<0.2?4:8);
if (in_width) width = labelWidth/1.8;
var alpha = alpha1+(alpha2-alpha1)/2;
//position and its correction
R = R-(width-8)/2;
var corr_x = - width;
var corr_y = -8;
var align = "right";
//for items in left upper and lower sector
if(alpha>=Math.PI/2 && alpha<Math.PI || alpha<=3*Math.PI/2 && alpha>=Math.PI){
corr_x = -labelWidth-corr_x+1;/*correction for label width*/
align = "left";
}
//calculate position of text
//basically get point at center of pie sector
var offset = 0;
if(!in_width&&ky<1&&(alpha>0&&alpha<Math.PI))
offset = (this._settings.height||Math.floor(R/4))/ky;
var y = (y0+Math.floor((R+offset)*Math.sin(alpha)))*ky+corr_y;
var x = x0+Math.floor((R+width/2)*Math.cos(alpha))+corr_x;
//if pie sector starts in left of right part pie, related text
//must be placed to the left of to the right of pie as well
var left_end = (alpha2 < Math.PI/2+0.01);
var left_start = (alpha1 < Math.PI/2);
if (left_start && left_end){
x = Math.max(x,x0+3); //right part of pie
/*if(alpha2-alpha1<0.2)
x = x0;*/
}
else if (!left_start && !left_end)
x = Math.min(x,x0-labelWidth); //left part of pie
else if (!in_width&&(alpha>=Math.PI/2 && alpha<Math.PI || alpha<=3*Math.PI/2 && alpha>=Math.PI)){
x += labelWidth/3;
}
//we need to set position of text manually, based on above calculations
t.style.top = y+"px";
t.style.left = x+"px";
t.style.width = labelWidth+"px";
t.style.textAlign = align;
t.style.whiteSpace = "nowrap";
}
};
dhtmlx.chart.pie3D = {
pvt_render_pie3D:function(ctx,data,x,y,sIndex,map){
this._renderPie(ctx,data,x,y,this._settings.cant,map);
}
};
dhtmlx.chart.donut = {
pvt_render_donut:function(ctx,data,point0,point1,sIndex,map){
if(!data.length)
return;
this._renderPie(ctx,data,point0,point1,1,map);
var config = this._settings;
var coord = this._getPieParameters(point0,point1);
var pieRadius = (config.radius?config.radius:coord.radius);
var innerRadius = ((config.innerRadius&&(config.innerRadius<pieRadius))?config.innerRadius:pieRadius/3);
var x0 = (config.x?config.x:coord.x);
var y0 = (config.y?config.y:coord.y);
ctx.fillStyle = "#ffffff";
ctx.beginPath();
ctx.arc(x0,y0,innerRadius,0,Math.PI*2,true);
ctx.fill();
}
};
/* DHX DEPEND FROM FILE 'compatibility_grid.js'*/
/*
Compatibility hack for loading data from the grid.
Provides new type of datasource - dhtmlxgrid
*/
/*DHX:Depend load.js*/
dhtmlx.DataDriver.dhtmlxgrid={
_grid_getter:"_get_cell_value",
toObject:function(data){
this._grid = data;
return data;
},
getRecords:function(data){
return data.rowsBuffer;
},
getDetails:function(data){
var result = {};
for (var i=0; i < this._grid.getColumnsNum(); i++)
result["data"+i]=this._grid[this._grid_getter](data,i);
return result;
},
getInfo:function(data){
return {
_size:0,
_from:0
};
}
};
/* DHX DEPEND FROM FILE 'canvas.js'*/
/*DHX:Depend thirdparty/excanvas*/
/*DHX:Depend dhtmlx.js*/
dhtmlx.ui.Canvas = function(container,name,style) {
this._canvas_labels = [];
this._canvas_name = name;
this._obj = container;
var width = container.offsetWidth*(window.devicePixelRatio||1);
var height = container.offsetHeight*(window.devicePixelRatio||1);
var style = style||"";
style += ";width:"+container.offsetWidth+"px;height:"+container.offsetHeight+"px;";
this._prepareCanvas(name, style ,width, height);
};
dhtmlx.ui.Canvas.prototype = {
_prepareCanvas:function (name,style,width,height){
//canvas has the same size as master object
this._canvas = dhtmlx.html.create("canvas",{ width:width, height:height, canvas_id:name, style:(style||"") });
this._obj.appendChild(this._canvas);
//use excanvas in IE
if (!this._canvas.getContext){
if (dhtmlx._isIE){
dhtmlx.require("thirdparty/excanvas/excanvas.js"); //sync loading
G_vmlCanvasManager.init_(document);
G_vmlCanvasManager.initElement(this._canvas);
} else //some other not supported browser
dhtmlx.error("Canvas is not supported in the current browser");
}
return this._canvas;
},
getCanvas:function(context){
var ctx = (this._canvas||this._prepareCanvas()).getContext(context||"2d");
if(!this._webixDevicePixelRatio){
this._webixDevicePixelRatio = true;
ctx.scale(window.devicePixelRatio||1, window.devicePixelRatio||1);
}
return ctx;
},
_resizeCanvas:function(){
if (this._canvas){
var w = this._canvas.parentNode.offsetWidth;
var h = this._canvas.parentNode.offsetHeight;
this._canvas.setAttribute("width", w*(window.devicePixelRatio||1));
this._canvas.setAttribute("height", h*(window.devicePixelRatio||1));
this._canvas.style.width = w+"px";
this._canvas.style.height = h+"px";
this._webixDevicePixelRatio = false;
}
},
renderText:function(x,y,text,css,w){
if (!text) return; //ignore empty text
var t = dhtmlx.html.create("DIV",{
"class":"dhx_canvas_text"+(css?(" "+css):""),
"style":"left:"+x+"px; top:"+y+"px;"
},text);
this._obj.appendChild(t);
this._canvas_labels.push(t); //destructor?
if (w)
t.style.width = w+"px";
return t;
},
renderTextAt:function(valign,align, x,y,t,c,w){
var text=this.renderText.call(this,x,y,t,c,w);
if (text){
if (valign){
if(valign == "middle")
text.style.top = parseInt(y-text.offsetHeight/2,10) + "px";
else
text.style.top = y-text.offsetHeight + "px";
}
if (align){
if(align == "left")
text.style.left = x-text.offsetWidth + "px";
else
text.style.left = parseInt(x-text.offsetWidth/2,10) + "px";
}
}
return text;
},
clearCanvas:function(skipMap){
var areas=[], i;
for(i=0; i < this._canvas_labels.length;i++)
this._obj.removeChild(this._canvas_labels[i]);
this._canvas_labels = [];
if (!skipMap&&this._obj._htmlmap){
//areas that correspond this canvas layer
areas = this._getMapAreas();
//removes areas of this canvas
while(areas.length){
areas[0].parentNode.removeChild(areas[0]);
areas.splice(0,1);
}
areas = null;
//removes _htmlmap object if all its child nodes are removed
if(!this._obj._htmlmap.getElementsByTagName("AREA").length){
this._obj._htmlmap.parentNode.removeChild(this._obj._htmlmap);
this._obj._htmlmap = null;
}
}
//FF breaks, when we are using clear canvas and call clearRect without parameters
this.getCanvas().clearRect(0,0,this._obj.offsetWidth*(window.devicePixelRatio||1), this._obj.offsetWidth*(window.devicePixelRatio||1));
},
toggleCanvas:function(){
this._toggleCanvas(this._canvas.style.display=="none")
},
showCanvas:function(){
this._toggleCanvas(true);
},
hideCanvas:function(){
this._toggleCanvas(false);
},
_toggleCanvas:function(show){
var areas, i;
for(i=0; i < this._canvas_labels.length;i++)
this._canvas_labels[i].style.display = (show?"":"none");
if (this._obj._htmlmap){
areas = this._getMapAreas();
for( i = 0; i < areas.length; i++){
if(show)
areas[i].removeAttribute("disabled");
else
areas[i].setAttribute("disabled","true");
}
}
//FF breaks, when we are using clear canvas and call clearRect without parameters
this._canvas.style.display = (show?"":"none");
},
_getMapAreas:function(){
var res = [], areas, i;
areas = this._obj._htmlmap.getElementsByTagName("AREA");
for(i = 0; i < areas.length; i++){
if(areas[i].getAttribute("userdata") == this._canvas_name){
res.push(areas[i]);
}
}
return res;
}
};
/* DHX INITIAL FILE 'C:\http\legacy/dhtmlxCore/sources//chart.js'*/
/*DHX:Depend chart.css*/
/*DHX:Depend canvas.js*/
/*DHX:Depend load.js*/
/*DHX:Depend compatibility_grid.js*/
/*DHX:Depend compatibility_layout.js*/
/*DHX:Depend config.js*/
/*DHX:Depend destructor.js*/
/*DHX:Depend mouse.js*/
/*DHX:Depend key.js*/
/*DHX:Depend group.js*/
/*DHX:Depend autotooltip.js*/
/*DHX:Depend ext/chart/chart_base.js*/
/*DHX:Depend ext/chart/chart_pie.js*/ //+pie3d
/*DHX:Depend ext/chart/chart_bar.js*/
/*DHX:Depend ext/chart/chart_line.js*/
/*DHX:Depend ext/chart/chart_barh.js*/
/*DHX:Depend ext/chart/chart_stackedbar.js*/
/*DHX:Depend ext/chart/chart_stackedbarh.js*/
/*DHX:Depend ext/chart/chart_spline.js*/
/*DHX:Depend ext/chart/chart_area.js*/ //+stackedArea
/*DHX:Depend ext/chart/chart_radar.js*/
/*DHX:Depend ext/chart/chart_scatter.js*/
/*DHX:Depend ext/chart/presets.js*/
/*DHX:Depend math.js*/
/*DHX:Depend destructor.js*/
/*DHX:Depend dhtmlx.js*/
/*DHX:Depend date.js*/
dhtmlXChart = function(container){
this.name = "Chart";
this.version = "3.0";
if (dhtmlx.assert_enabled()) this._assert();
dhtmlx.extend(this, dhtmlx.Settings);
this._parseContainer(container,"dhx_chart");
dhtmlx.extend(this, dhtmlx.AtomDataLoader);
dhtmlx.extend(this, dhtmlx.DataLoader);
this.data.provideApi(this,true);
dhtmlx.extend(this, dhtmlx.EventSystem);
dhtmlx.extend(this, dhtmlx.MouseEvents);
dhtmlx.extend(this, dhtmlx.Destruction);
//dhtmlx.extend(this, dhtmlx.Canvas);
dhtmlx.extend(this, dhtmlx.Group);
dhtmlx.extend(this, dhtmlx.AutoTooltip);
for (var key in dhtmlx.chart)
dhtmlx.extend(this, dhtmlx.chart[key]);
if(container.preset){
this.definePreset(container);
}
this._parseSettings(container,this.defaults);
this._series = [this._settings];
this.data.attachEvent("onStoreUpdated",dhtmlx.bind(function(){
this.render();
},this));
this.attachEvent("onLocateData", this._switchSerie);
};
dhtmlXChart.prototype={
_id:"dhx_area_id",
on_click: {
dhx_chart_legend_item: function(e,id,obj){
var series = obj.getAttribute("series_id");
if(this.callEvent("onLegendClick",[e,series,obj])){
var config = this._settings;
var values = config.legend.values;
var toggle = (values&&(typeof values[series].toggle != "undefined"))?values[series].toggle:config.legend.toggle;
if((typeof series != "undefined")&&this._series.length>1){
// hide action
if(toggle){
if(obj.className.indexOf("hidden")!=-1){
this.showSeries(series);
}
else{
this.hideSeries(series);
}
}
}
}
}
},
on_dblclick:{
},
on_mouse_move:{
},
bind:function(){
dhx.BaseBind.legacyBind.apply(this, arguments);
},
sync:function(){
dhx.BaseBind.legacySync.apply(this, arguments);
},
resize:function(){
for(var c in this.canvases){
this.canvases[c]._resizeCanvas();
}
this.render();
},
view_setter:function( val){
if (!dhtmlx.chart[val])
dhtmlx.error("Chart type extension is not loaded: "+val);
//if you will need to add more such settings - move them ( and this one ) in a separate methods
if (typeof this._settings.offset == "undefined"){
this._settings.offset = !(val == "area" || val == "stackedArea");
}
if(val=="radar"&&!this._settings.yAxis)
this.define("yAxis",{});
if(val=="scatter"){
if(!this._settings.yAxis)
this.define("yAxis",{});
if(!this._settings.xAxis)
this.define("xAxis",{});
}
return val;
},
clearCanvas:function(){
if(this.canvases&&typeof this.canvases == "object")
for(var c in this.canvases){
this.canvases[c].clearCanvas();
}
},
render:function(){
var bounds, i, data, map, temp;
if (!this.callEvent("onBeforeRender",[this.data]))
return;
if(this.canvases&&typeof this.canvases == "object"){
for(i in this.canvases){
this.canvases[i].clearCanvas();
}
}
else
this.canvases = {};
if(this._settings.legend){
if(!this.canvases["legend"])
this.canvases["legend"] = new dhtmlx.ui.Canvas(this._obj,"legend");
this._drawLegend(
this.data.getRange(),
this._obj.offsetWidth
);
}
bounds = this._getChartBounds(this._obj.offsetWidth,this._obj.offsetHeight);
map = new dhtmlx.ui.Map(this._id);
temp = this._settings;
data = this._getChartData();
for(i=0; i < this._series.length;i++){
this._settings = this._series[i];
if(!this.canvases[i]){
this.canvases[i] = new dhtmlx.ui.Canvas(this._obj,i,"z-index:"+(2+i));
}
this["pvt_render_"+this._settings.view](
this.canvases[i].getCanvas(),
data,
bounds.start,
bounds.end,
i,
map
);
}
map.render(this._obj);
this._obj.lastChild.style.zIndex = 1000;
this._applyBounds(this._obj.lastChild,bounds);
this.callEvent("onAfterRender",[]);
this._settings = temp;
},
_applyBounds: function(elem,bounds){
var style = {};
style.left = bounds.start.x;
style.top = bounds.start.y;
style.width = bounds.end.x-bounds.start.x;
style.height = bounds.end.y - bounds.start.y;
for(var prop in style){
elem.style[prop] = style[prop]+"px";
}
},
_getChartData: function(){
var axis, axisConfig ,config, data, i, newData, start, units, value, valuesHash;
data = this.data.getRange();
axis = (this._settings.view.toLowerCase().indexOf("barh")!=-1?"yAxis":"xAxis");
axisConfig = this._settings[axis];
if(axisConfig&&axisConfig.units&&(typeof axisConfig.units == "object")){
config = axisConfig.units;
units = [];
if(typeof config.start != "undefined"&&typeof config.end != "undefined" && typeof config.next != "undefined"){
start = config.start;
while(start<=config.end){
units.push(start);
start = config.next.call(this,start);
}
}
else if(Object.prototype.toString.call(config) === '[object Array]'){
units = config;
}
newData = [];
if(units.length){
value = axisConfig.value;
valuesHash = {};
for(i=0;i < data.length;i++){
valuesHash[value(data[i])] = i;
}
for(i=0;i< units.length;i++){
if(typeof valuesHash[units[i]]!= "undefined"){
data[valuesHash[units[i]]].$unit = units[i];
newData.push(data[valuesHash[units[i]]]);
}
else{
newData.push({$unit:units[i]});
}
}
}
return newData;
}
return data;
},
value_setter:dhtmlx.Template.obj_setter,
xValue_setter:dhtmlx.Template.obj_setter,
yValue_setter:function(config){
this.define("value",config);
},
alpha_setter:dhtmlx.Template.obj_setter,
label_setter:dhtmlx.Template.obj_setter,
lineColor_setter:dhtmlx.Template.obj_setter,
borderColor_setter:dhtmlx.Template.obj_setter,
pieInnerText_setter:dhtmlx.Template.obj_setter,
gradient_setter:function(config){
if((typeof(config)!="function")&&config&&(config === true))
config = "light";
return config;
},
colormap:{
"RAINBOW":function(obj){
var pos = Math.floor(this.indexById(obj.id)/this.dataCount()*1536);
if (pos==1536) pos-=1;
return this._rainbow[Math.floor(pos/256)](pos%256);
}
},
color_setter:function(value){
return this.colormap[value]||dhtmlx.Template.obj_setter( value);
},
fill_setter:function(value){
return ((!value||value==0)?false:dhtmlx.Template.obj_setter( value));
},
definePreset:function(obj){
this.define("preset",obj.preset);
delete obj.preset;
},
preset_setter:function(value){
var a, b, preset;
this.defaults = dhtmlx.extend({},this.defaults);
if(typeof dhtmlx.presets.chart[value]=="object"){
preset = dhtmlx.presets.chart[value];
for(a in preset){
if(typeof preset[a]=="object"){
if(!this.defaults[a]||typeof this.defaults[a]!="object"){
this.defaults[a] = dhtmlx.extend({},preset[a]);
}
else{
this.defaults[a] = dhtmlx.extend({},this.defaults[a]);
for(b in preset[a]){
this.defaults[a][b] = preset[a][b];
}
}
}else{
this.defaults[a] = preset[a];
}
}
return value;
}
return false;
},
legend_setter:function( config){
if(!config){
if(this.legendObj){
this.legendObj.innerHTML = "";
this.legendObj = null;
}
return false;
}
if(typeof(config)!="object") //allow to use template string instead of object
config={template:config};
this._mergeSettings(config,{
width:150,
height:18,
layout:"y",
align:"left",
valign:"bottom",
template:"",
toggle:(this._settings.view.toLowerCase().indexOf("stacked")!=-1?"":"hide"),
marker:{
type:"square",
width:15,
height:15,
radius:3
},
margin: 4,
padding: 3
});
config.template = dhtmlx.Template.setter(config.template);
return config;
},
defaults:{
color:"RAINBOW",
alpha:"1",
label:false,
value:"{obj.value}",
padding:{},
view:"pie",
lineColor:"#ffffff",
cant:0.5,
width: 30,
labelWidth:100,
line:{
width:2,
color:"#1293f8"
},
item:{
radius:3,
borderColor:"#636363",
borderWidth:1,
color: "#ffffff",
alpha:1,
type:"r",
shadow:false
},
shadow:true,
gradient:false,
border:true,
labelOffset: 20,
origin:"auto"
},
item_setter:function( config){
if(typeof(config)!="object")
config={color:config, borderColor:config};
this._mergeSettings(config,dhtmlx.extend({},this.defaults.item));
var settings = ["alpha","borderColor","color","radius"];
for(var i=0; i< settings.length; i++)
config[settings[i]] = dhtmlx.Template.setter(config[settings[i]]);
/*config.alpha = dhtmlx.Template.setter(config.alpha);
config.borderColor = dhtmlx.Template.setter(config.borderColor);
config.color = dhtmlx.Template.setter(config.color);
config.radius = dhtmlx.Template.setter(config.radius);*/
return config;
},
line_setter:function( config){
if(typeof(config)!="object")
config={color:config};
dhtmlx.extend(this.defaults.line,config);
config = dhtmlx.extend({},this.defaults.line);
config.color = dhtmlx.Template.setter(config.color);
return config;
},
padding_setter:function( config){
if(typeof(config)!="object")
config={left:config, right:config, top:config, bottom:config};
this._mergeSettings(config,{
left:50,
right:20,
top:35,
bottom:40
});
return config;
},
xAxis_setter:function( config){
if(!config) return false;
if(typeof(config)!="object")
config={ template:config };
if(!config.value)
config.value = config.template;
this._mergeSettings(config,{
title:"",
color:"#000000",
lineColor:"#cfcfcf",
template:"{obj}",
value:"{obj}",
lines:true
});
var templates = ["lineColor","template","lines","value"];
this._converToTemplate(templates,config);
this._configXAxis = dhtmlx.extend({},config);
return config;
},
yAxis_setter:function( config){
this._mergeSettings(config,{
title:"",
color:"#000000",
lineColor:"#cfcfcf",
template:"{obj}",
lines:true,
bg:"#ffffff"
});
var templates = ["lineColor","template","lines","bg"];
this._converToTemplate(templates,config);
this._configYAxis = dhtmlx.extend({},config);
return config;
},
_converToTemplate:function(arr,config){
for(var i=0;i< arr.length;i++){
config[arr[i]] = dhtmlx.Template.setter(config[arr[i]]);
}
},
_drawScales:function(data,point0,point1,start,end,cellWidth){
var y = 0;
if(this._settings.yAxis){
if(! this.canvases["y"])
this.canvases["y"] = new dhtmlx.ui.Canvas(this._obj,"axis_y");
y = this._drawYAxis(this.canvases["y"].getCanvas(),data,point0,point1,start,end);
}
if (this._settings.xAxis){
if(! this.canvases["x"])
this.canvases["x"] = new dhtmlx.ui.Canvas(this._obj,"axis_x");
this._drawXAxis(this.canvases["x"].getCanvas(),data,point0,point1,cellWidth,y);
}
return y;
},
_drawXAxis:function(ctx,data,point0,point1,cellWidth,y){
var x0 = point0.x-0.5;
var y0 = parseInt((y?y:point1.y),10)+0.5;
var x1 = point1.x;
var unitPos;
var center = true;
for(var i=0; i < data.length;i ++){
if(this._settings.offset === true)
unitPos = x0+cellWidth/2+i*cellWidth;
else{
unitPos = (i==data.length-1)?point1.x:x0+i*cellWidth;
center = !!i;
}
unitPos = Math.ceil(unitPos)-0.5;
/*scale labels*/
var top = ((this._settings.origin!="auto")&&(this._settings.view=="bar")&&(parseFloat(this._settings.value(data[i]))<this._settings.origin));
this._drawXAxisLabel(unitPos,y0,data[i],center,top);
/*draws a vertical line for the horizontal scale*/
if((this._settings.offset||i)&&this._settings.xAxis.lines.call(this,data[i]))
this._drawXAxisLine(ctx,unitPos,point1.y,point0.y,data[i]);
}
this.canvases["x"].renderTextAt(true, false, x0,point1.y+this._settings.padding.bottom-3,
this._settings.xAxis.title,
"dhx_axis_title_x",
point1.x - point0.x
);
this._drawLine(ctx,x0,y0,x1,y0,this._settings.xAxis.color,1);
/*the right border in lines in scale are enabled*/
if (!this._settings.xAxis.lines.call(this,{}) || !this._settings.offset) return;
this._drawLine(ctx,x1+0.5,point1.y,x1+0.5,point0.y+0.5,this._settings.xAxis.color,0.2);
},
_drawYAxis:function(ctx,data,point0,point1,start,end){
var step;
var scaleParam= {};
if (!this._settings.yAxis) return;
var x0 = point0.x - 0.5;
var y0 = point1.y;
var y1 = point0.y;
var lineX = point1.y;
//this._drawLine(ctx,x0,y0,x0,y1,this._settings.yAxis.color,1);
if(this._settings.yAxis.step)
step = parseFloat(this._settings.yAxis.step);
if(typeof this._configYAxis.step =="undefined"||typeof this._configYAxis.start=="undefined"||typeof this._configYAxis.end =="undefined"){
scaleParam = this._calculateScale(start,end);
start = scaleParam.start;
end = scaleParam.end;
step = scaleParam.step;
this._settings.yAxis.end = end;
this._settings.yAxis.start = start;
}
this._setYAxisTitle(point0,point1);
/*if(step===0) return;
if(end==start){
return y0;
}
var stepHeight = (y0-y1)*step/(end-start);*/
if(step===0){
end = start;
step = 1;
}
var stepHeight = (end==start?y0-y1:(y0-y1)*step/(end-start));
var c = 0;
for(var i = start; i<=end; i += step){
if(scaleParam.fixNum) i = parseFloat((new Number(i)).toFixed(scaleParam.fixNum));
var yi = Math.floor(y0-c*stepHeight)+ 0.5;/*canvas line fix*/
if(!(i==start&&this._settings.origin=="auto") &&this._settings.yAxis.lines.call(this,i))
this._drawLine(ctx,x0,yi,point1.x,yi,this._settings.yAxis.lineColor.call(this,i),1);
if(i == this._settings.origin) lineX = yi;
/*correction for JS float calculation*/
var label = i;
if(step<1){
var power = Math.min(this._log10(step),(start<=0?0:this._log10(start)));
var corr = Math.pow(10,-power);
label = Math.round(i*corr)/corr;
i = label;
}
this.canvases["y"].renderText(0,yi-5,
this._settings.yAxis.template(label.toString()),
"dhx_axis_item_y",
point0.x-5
);
c++;
}
this._drawLine(ctx,x0,y0+1,x0,y1,this._settings.yAxis.color,1);
return lineX;
},
_setYAxisTitle:function(point0,point1){
var className = "dhx_axis_title_y"+(dhtmlx._isIE&&dhtmlx._isIE !=9?" dhx_ie_filter":"");
var text=this.canvases["y"].renderTextAt("middle",false,0,parseInt((point1.y-point0.y)/2+point0.y,10),this._settings.yAxis.title,className);
if (text)
text.style.left = (dhtmlx.env.transform?(text.offsetHeight-text.offsetWidth)/2:0)+"px";
/*var ctx = this.canvases["y"].getCanvas();
var metric = ctx.measureText(this._settings.yAxis.title);
var tx = 5 + (metric.width/2);
var ty = 5 +point0.y+ (point1.y-point0.y)/2+metric.width/2;
ctx.font = "bold 12pt sans-serif";
ctx.save();
ctx.translate(tx,ty);
ctx.rotate(Math.PI/2*3);
//ctx.translate(-tx,-ty);
ctx.fillText(this._settings.yAxis.title, 0,0)
ctx.restore();*/
},
_calculateScale:function(nmin,nmax){
if(this._settings.origin!="auto"&&this._settings.origin<nmin)
nmin = this._settings.origin;
var step,start,end;
step = ((nmax-nmin)/8)||1;
var power = Math.floor(this._log10(step));
var calculStep = Math.pow(10,power);
var stepVal = step/calculStep;
stepVal = (stepVal>5?10:5);
step = parseInt(stepVal,10)*calculStep;
if(step>Math.abs(nmin))
start = (nmin<0?-step:0);
else{
var absNmin = Math.abs(nmin);
var powerStart = Math.floor(this._log10(absNmin));
var nminVal = absNmin/Math.pow(10,powerStart);
start = Math.ceil(nminVal*10)/10*Math.pow(10,powerStart)-step;
if(absNmin>1&&step>0.1){
start = Math.ceil(start);
}
while(nmin<0?start<=nmin:start>=nmin)
start -= step;
if(nmin<0) start =-start-2*step;
}
end = start;
while(end<nmax){
end += step;
end = parseFloat((new Number(end)).toFixed(Math.abs(power)));
}
return { start:start,end:end,step:step,fixNum:Math.abs(power) };
},
_getLimits:function(orientation,value){
var maxValue,minValue;
var axis = ((arguments.length && orientation=="h")?this._configXAxis:this._configYAxis);
value = value||"value";
if(axis&&(typeof axis.end!="undefined")&&(typeof axis.start!="undefined")&&axis.step){
maxValue = parseFloat(axis.end);
minValue = parseFloat(axis.start);
}
else{
maxValue = this.max(this._series[0][value]);
minValue = (axis&&(typeof axis.start!="undefined"))?parseFloat(axis.start):this.min(this._series[0][value]);
if(this._series.length>1)
for(var i=1; i < this._series.length;i++){
var maxI = this.max(this._series[i][value]);
var minI = this.min(this._series[i][value]);
if (maxI > maxValue) maxValue = maxI;
if (minI < minValue) minValue = minI;
}
}
return {max:maxValue,min:minValue};
},
_log10:function(n){
var method_name="log";
return Math.floor((Math[method_name](n)/Math.LN10));
},
_drawXAxisLabel:function(x,y,obj,center,top){
if (!this._settings.xAxis) return;
var elem = this.canvases["x"].renderTextAt(top, center, x,y-(top?2:0),this._settings.xAxis.template(obj));
if (elem)
elem.className += " dhx_axis_item_x";
},
_drawXAxisLine:function(ctx,x,y1,y2,obj){
if (!this._settings.xAxis||!this._settings.xAxis.lines) return;
this._drawLine(ctx,x,y1,x,y2,this._settings.xAxis.lineColor.call(this,obj),1);
},
_drawLine:function(ctx,x1,y1,x2,y2,color,width){
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
ctx.lineWidth = 1;
},
_getRelativeValue:function(minValue,maxValue){
var relValue, origRelValue;
var valueFactor = 1;
if(maxValue != minValue){
relValue = maxValue - minValue;
/*if(Math.abs(relValue) < 1){
while(Math.abs(relValue)<1){
valueFactor *= 10;
relValue = origRelValue* valueFactor;
}
}
*/
}
else relValue = minValue;
return [relValue,valueFactor];
},
_rainbow : [
function(pos){ return "#FF"+dhtmlx.math.toHex(pos/2,2)+"00";},
function(pos){ return "#FF"+dhtmlx.math.toHex(pos/2+128,2)+"00";},
function(pos){ return "#"+dhtmlx.math.toHex(255-pos,2)+"FF00";},
function(pos){ return "#00FF"+dhtmlx.math.toHex(pos,2);},
function(pos){ return "#00"+dhtmlx.math.toHex(255-pos,2)+"FF";},
function(pos){ return "#"+dhtmlx.math.toHex(pos,2)+"00FF";}
],
/**
* adds series to the chart (value and color properties)
* @param: obj - obj with configuration properties
*/
addSeries:function(obj){
var temp = this._settings;
this._settings = dhtmlx.extend({},temp);
this._parseSettings(obj,{});
this._series.push(this._settings);
this._settings = temp;
},
/*switch global settings to serit in question*/
_switchSerie:function(id, tag){
var tip;
this._active_serie = tag.getAttribute("userdata");
if (!this._series[this._active_serie]) return;
for (var i=0; i < this._series.length; i++) {
tip = this._series[i].tooltip;
if (tip)
tip.disable();
}
if(!tag.getAttribute("disabled")){
tip = this._series[this._active_serie].tooltip;
if (tip)
tip.enable();
}
},
hideSeries:function(series){
this.canvases[series].hideCanvas();
if(this._settings.legend.values&&this._settings.legend.values[series])
this._settings.legend.values[series].$hidden = true;
this._drawLegend();
},
showSeries:function(series){
this.canvases[series].showCanvas();
if(this._settings.legend.values&&this._settings.legend.values[series])
delete this._settings.legend.values[series].$hidden;
this._drawLegend();
},
_setBorderStyles:function(ctx,color){
var hsv,rgb;
rgb = dhtmlx.math.toRgb(color);
hsv = dhtmlx.math.rgbToHsv(rgb[0],rgb[1],rgb[2]);
hsv[2] /= 2;
color = "rgb("+dhtmlx.math.hsvToRgb(hsv[0],hsv[1],hsv[2])+")";
ctx.strokeStyle = color;
if(ctx.globalAlpha==1)
ctx.globalAlpha = 0.9;
},
/**
* renders legend block
* @param: ctx - canvas object
* @param: data - object those need to be displayed
* @param: width - the width of the container
* @param: height - the height of the container
*/
_drawLegend:function(data,width){
var i, legend, legendContainer, legendHeight, legendItems, legendWidth, style, x=0, y= 0, ctx, itemColor, disabled, item;
data = data||[];
width = width||this._obj.offsetWidth;
ctx = this.canvases["legend"].getCanvas();
/*legend config*/
legend = this._settings.legend;
style = (this._settings.legend.layout!="x"?"width:"+legend.width+"px":"");
/*creation of legend container*/
if(this.legendObj){
this.legendObj.innerHTML = "";
this.legendObj.parentNode.removeChild(this.legendObj);
}
this.canvases["legend"].clearCanvas(true);
legendContainer = dhtmlx.html.create("DIV",{
"class":"dhx_chart_legend",
"style":"left:"+x+"px; top:"+y+"px;"+style
},"");
if(legend.padding){
legendContainer.style.padding = legend.padding+"px";
}
this.legendObj = legendContainer;
this._obj.appendChild(legendContainer);
/*rendering legend text items*/
legendItems = [];
if(!legend.values)
for(i = 0; i < data.length; i++){
legendItems.push(this._drawLegendText(legendContainer,legend.template(data[i])));
}
else
for(i = 0; i < legend.values.length; i++){
legendItems.push(this._drawLegendText(legendContainer,legend.values[i].text,(typeof legend.values[i].id!="undefined"?typeof legend.values[i].id:i),legend.values[i].$hidden));
}
legendWidth = legendContainer.offsetWidth;
legendHeight = legendContainer.offsetHeight;
/*this._settings.legend.width = legendWidth;
this._settings.legend.height = legendHeight;*/
/*setting legend position*/
if(legendWidth<this._obj.offsetWidth){
if(legend.layout == "x"&&legend.align == "center"){
x = (this._obj.offsetWidth-legendWidth)/2;
}
if(legend.align == "right"){
x = this._obj.offsetWidth-legendWidth;
}
if(legend.margin&&legend.align != "center"){
x += (legend.align == "left"?1:-1)*legend.margin;
}
}
if(legendHeight<this._obj.offsetHeight){
if(legend.valign == "middle"&&legend.align != "center"&&legend.layout != "x")
y = (this._obj.offsetHeight-legendHeight)/2;
else if(legend.valign == "bottom")
y = this._obj.offsetHeight-legendHeight;
if(legend.margin&&legend.valign != "middle"){
y += (legend.valign == "top"?1:-1)*legend.margin;
}
}
legendContainer.style.left = x+"px";
legendContainer.style.top = y+"px";
/*drawing colorful markers*/
ctx.save();
for(i = 0; i < legendItems.length; i++){
item = legendItems[i];
if(legend.values&&legend.values[i].$hidden){
disabled = true;
itemColor = (legend.values[i].disableColor?legend.values[i].disableColor:"#d9d9d9");
}
else{
disabled = false;
itemColor = (legend.values?legend.values[i].color:this._settings.color.call(this,data[i]));
}
this._drawLegendMarker(ctx,item.offsetLeft+x,item.offsetTop+y,itemColor,item.offsetHeight,disabled,i);
}
ctx.restore();
legendItems = null;
},
/**
* appends legend item to legend block
* @param: ctx - canvas object
* @param: obj - data object that needs being represented
*/
_drawLegendText:function(cont,value,series,disabled){
var style = "";
if(this._settings.legend.layout=="x")
style = "float:left;";
/*the text of the legend item*/
var text = dhtmlx.html.create("DIV",{
"style":style+"padding-left:"+(10+this._settings.legend.marker.width)+"px",
"class":"dhx_chart_legend_item"+(disabled?" hidden":"")
},value);
if(arguments.length>2)
text.setAttribute("series_id",series);
cont.appendChild(text);
return text;
},
/**
* draw legend colorful marder
* @param: ctx - canvas object
* @param: x - the horizontal position of the marker
* @param: y - the vertical position of the marker
* @param: color - marker color
* @param: height - item height
* @param: disabled - disabled staet
* @param: i - index of legend item
*/
_drawLegendMarker:function(ctx,x,y,color,height,disabled,i){
var p = [];
var marker = this._settings.legend.marker;
var values = this._settings.legend.values;
var type = (values&&values[i].markerType?values[i].markerType:marker.type);
if(color){
ctx.fillStyle = color;
ctx.strokeStyle = this._getDarkenColor(color,0.75);
}
ctx.beginPath();
if(type=="round"||!marker.radius){
ctx.lineWidth = marker.height;
ctx.lineCap = type;
/*start of marker*/
x += ctx.lineWidth/2+5;
y += height/2;
ctx.moveTo(x,y);
var x1 = x + marker.width-marker.height +1;
ctx.lineTo(x1,y);
}else if(type=="item"){
/*copy of line*/
if(this._settings.line&&this._settings.view != "scatter" && !this._settings.disableLines){
ctx.beginPath();
ctx.lineWidth = this._series[i].line.width;
ctx.strokeStyle = disabled?color:this._series[i].line.color.call(this,{});
var x0 = x + 5;
var y0 = y + height/2;
ctx.moveTo(x0,y0);
var x1 = x0 + marker.width;
ctx.lineTo(x1,y0);
ctx.stroke();
}
/*item copy*/
var config = this._series[i].item;
var radius = parseInt(config.radius.call(this,{}),10)||0;
if(radius){
ctx.beginPath();
if(disabled){
ctx.lineWidth = config.borderWidth;
ctx.strokeStyle = color;
ctx.fillStyle = color;
}
else{
ctx.lineWidth = config.borderWidth;
ctx.fillStyle = config.color.call(this,{});
ctx.strokeStyle = config.borderColor.call(this,{});
ctx.globalAlpha = config.alpha.call(this,{});
}
ctx.beginPath();
x += marker.width/2+5;
y += height/2;
this._strokeChartItem(ctx,x,y,radius+1,config.type);
ctx.fill();
ctx.stroke();
}
ctx.globalAlpha = 1;
}else{
ctx.lineWidth = 1;
x += 5;
y += parseInt(height/2-marker.height/2,10);
p = [
[x+marker.radius,y+marker.radius,marker.radius,Math.PI,3*Math.PI/2,false],
[x+marker.width-marker.radius,y],
[x+marker.width-marker.radius,y+marker.radius,marker.radius,-Math.PI/2,0,false],
[x+marker.width,y+marker.height-marker.radius],
[x+marker.width-marker.radius,y+marker.height-marker.radius,marker.radius,0,Math.PI/2,false],
[x+marker.radius,y+marker.height],
[x+marker.radius,y+marker.height-marker.radius,marker.radius,Math.PI/2,Math.PI,false],
[x,y+marker.radius]
];
this._path(ctx,p);
}
ctx.stroke();
ctx.fill();
},
_getDarkenColor:function(color,darken){
var hsv,rgb;
rgb = dhtmlx.math.toRgb(color);
hsv = dhtmlx.math.rgbToHsv(rgb[0],rgb[1],rgb[2]);
hsv[2] = hsv[2]*darken;
return "rgb("+dhtmlx.math.hsvToRgb(hsv[0],hsv[1],hsv[2])+")";
},
/**
* gets the points those represent chart left top and right bottom bounds
* @param: width - the width of the chart container
* @param: height - the height of the chart container
*/
_getChartBounds:function(width,height){
var chartX0, chartY0, chartX1, chartY1;
chartX0 = this._settings.padding.left;
chartY0 = this._settings.padding.top;
chartX1 = width - this._settings.padding.right;
chartY1 = height - this._settings.padding.bottom;
if(this._settings.legend){
var legend = this._settings.legend;
/*legend size*/
var legendWidth = this._settings.legend.width;
var legendHeight = this._settings.legend.height;
/*if legend is horizontal*/
if(legend.layout == "x"){
if(legend.valign == "center"){
if(legend.align == "right")
chartX1 -= legendWidth;
else if(legend.align == "left")
chartX0 += legendWidth;
}
else if(legend.valign == "bottom"){
chartY1 -= legendHeight;
}
else{
chartY0 += legendHeight;
}
}
/*vertical scale*/
else{
if(legend.align == "right")
chartX1 -= legendWidth;
else if(legend.align == "left")
chartX0 += legendWidth;
}
}
return {start:{x:chartX0,y:chartY0},end:{x:chartX1,y:chartY1}};
},
/**
* gets the maximum and minimum values for the stacked chart
* @param: data - data set
*/
_getStackedLimits:function(data){
var i, j, maxValue, minValue, value;
if(this._settings.yAxis&&(typeof this._settings.yAxis.end!="undefined")&&(typeof this._settings.yAxis.start!="undefined")&&this._settings.yAxis.step){
maxValue = parseFloat(this._settings.yAxis.end);
minValue = parseFloat(this._settings.yAxis.start);
}
else{
for(i=0; i < data.length; i++){
data[i].$sum = 0 ;
data[i].$min = Infinity;
for(j =0; j < this._series.length;j++){
value = parseFloat(this._series[j].value(data[i])||0);
if(isNaN(value)) continue;
if(this._series[j].view.toLowerCase().indexOf("stacked")!=-1)
data[i].$sum += value;
if(value < data[i].$min) data[i].$min = value;
}
}
maxValue = -Infinity;
minValue = Infinity;
for(i=0; i < data.length; i++){
if (data[i].$sum > maxValue) maxValue = data[i].$sum ;
if (data[i].$min < minValue) minValue = data[i].$min ;
}
if(minValue>0) minValue =0;
}
return {max: maxValue, min: minValue};
},
/*adds colors to the gradient object*/
_setBarGradient:function(ctx,x1,y1,x2,y2,type,color,axis){
var gradient, offset, rgb, hsv, color0, stops;
if(type == "light"){
if(axis == "x")
gradient = ctx.createLinearGradient(x1,y1,x2,y1);
else
gradient = ctx.createLinearGradient(x1,y1,x1,y2);
stops = [[0,"#FFFFFF"],[0.9,color],[1,color]];
offset = 2;
}
else if(type == "falling"||type == "rising"){
if(axis == "x")
gradient = ctx.createLinearGradient(x1,y1,x2,y1);
else
gradient = ctx.createLinearGradient(x1,y1,x1,y2);
rgb = dhtmlx.math.toRgb(color);
hsv = dhtmlx.math.rgbToHsv(rgb[0],rgb[1],rgb[2]);
hsv[1] *= 1/2;
color0 = "rgb("+dhtmlx.math.hsvToRgb(hsv[0],hsv[1],hsv[2])+")";
if(type == "falling"){
stops = [[0,color0],[0.7,color],[1,color]];
}
else if(type == "rising"){
stops = [[0,color],[0.3,color],[1,color0]];
}
offset = 0;
}
else{
ctx.globalAlpha = 0.37;
offset = 0;
if(axis == "x")
gradient = ctx.createLinearGradient(x1,y2,x1,y1);
else
gradient = ctx.createLinearGradient(x1,y1,x2,y1);
stops = [[0,"#9d9d9d"],[0.3,"#e8e8e8"],[0.45,"#ffffff"],[0.55,"#ffffff"],[0.7,"#e8e8e8"],[1,"#9d9d9d"]];
}
this._gradient(gradient,stops);
return {gradient:gradient,offset:offset};
},
/**
* returns the x and y position
* @param: a - angle
* @param: x - start x position
* @param: y - start y position
* @param: r - destination to the point
*/
_getPositionByAngle:function(a,x,y,r){
a *= (-1);
x = x+Math.cos(a)*r;
y = y-Math.sin(a)*r;
return {x:x,y:y};
},
_gradient:function(gradient,stops){
for(var i=0; i< stops.length; i++){
gradient.addColorStop(stops[i][0],stops[i][1]);
}
},
_path: function(ctx,points){
var i, method;
for(i = 0; i< points.length; i++){
method = (i?"lineTo":"moveTo");
if(points[i].length>2)
method = "arc";
ctx[method].apply(ctx,points[i]);
}
},
_circle: function(ctx,x,y,r){
ctx.arc(x,y,r,Math.PI*2,true);
},
_addMapRect:function(map,id,points,bounds,sIndex){
map.addRect(id,[points[0].x-bounds.x,points[0].y-bounds.y,points[1].x-bounds.x,points[1].y-bounds.y],sIndex);
}
};
dhtmlx.compat("layout");