From 20c75c45d8888e44b9b58b8ba67c6b5b2e8e7876 Mon Sep 17 00:00:00 2001 From: "Kunal Chavda (OpenERP)" Date: Fri, 8 Apr 2011 14:20:05 +0530 Subject: [IMP]Initialy show bar chart with data. bzr revid: kch@tinyerp.com-20110408085005-hv9jv2wcfopnxrgm --- .../lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js | 4737 ++++++++++++++++++++ 1 file changed, 4737 insertions(+) create mode 100644 addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js (limited to 'addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js') diff --git a/addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js b/addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js new file mode 100644 index 00000000000..57e5b5d5b0d --- /dev/null +++ b/addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js @@ -0,0 +1,4737 @@ +/* +Copyright DHTMLX LTD. http://www.dhtmlx.com +You allowed to use this component or parts of it under GPL terms +To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com +*/ +/* +2010 September 30 +*/ + + + +/* DHX DEPEND FROM FILE 'assert.js'*/ + + +if (!window.dhtmlx) + dhtmlx={}; + +//check some rule, show message as error if rule is not correct +dhtmlx.assert = function(test, message){ + if (!test) dhtmlx.error(message); +}; +dhtmlx.assert_enabled=function(){ return false; }; + +//register names of event, which can be triggered by the object +dhtmlx.assert_event = function(obj, evs){ + if (!obj._event_check){ + obj._event_check = {}; + obj._event_check_size = {}; + } + + for (var a in evs){ + obj._event_check[a.toLowerCase()]=evs[a]; + var count=-1; for (var t in evs[a]) count++; + obj._event_check_size[a.toLowerCase()]=count; + } +}; +dhtmlx.assert_method_info=function(obj, name, descr, rules){ + var args = []; + for (var i=0; i < rules.length; i++) { + args.push(rules[i][0]+" : "+rules[i][1]+"\n "+rules[i][2].describe()+(rules[i][3]?"; optional":"")); + } + return obj.name+"."+name+"\n"+descr+"\n Arguments:\n - "+args.join("\n - "); +}; +dhtmlx.assert_method = function(obj, config){ + for (var key in config) + dhtmlx.assert_method_process(obj, key, config[key].descr, config[key].args, (config[key].min||99), config[key].skip); +}; +dhtmlx.assert_method_process = function (obj, name, descr, rules, min, skip){ + var old = obj[name]; + if (!skip) + obj[name] = function(){ + if (arguments.length != rules.length && arguments.length < min) + dhtmlx.log("warn","Incorrect count of parameters\n"+obj[name].describe()+"\n\nExpecting "+rules.length+" but have only "+arguments.length); + else + for (var i=0; i= 0) return true; + return false; + }; + dhtmlx.assert_rule_dimension.describe=function(){ + return "{Integer} value must be a positive number"; + }; + + dhtmlx.assert_rule_number=function(check){ + if (typeof check == "number") return true; + return false; + }; + dhtmlx.assert_rule_number.describe=function(){ + return "{Integer} value must be a number"; + }; + + dhtmlx.assert_rule_function=function(check){ + if (typeof check == "function") return true; + return false; + }; + dhtmlx.assert_rule_function.describe=function(){ + return "{Function} value must be a custom function"; + }; + + dhtmlx.assert_rule_any=function(check){ + return true; + }; + dhtmlx.assert_rule_any.describe=function(){ + return "Any value"; + }; + + dhtmlx.assert_rule_mix=function(a,b){ + var t = function(check){ + if (a(check)||b(check)) return true; + return false; + }; + t.describe = function(){ + return a.describe(); + }; + return t; + }; + +} + + +/* DHX DEPEND FROM FILE 'dhtmlx.js'*/ + + +/*DHX:Depend assert.js*/ + +/* + Common helpers +*/ +dhtmlx.version="3.0"; +dhtmlx.codebase="./"; + +//coding helpers + +//copies methods and properties from source to the target +dhtmlx.extend = function(target, source){ + for (var method in source) + target[method] = source[method]; + + //applying asserts + if (dhtmlx.assert_enabled() && source._assert){ + target._assert(); + target._assert=null; + } + + dhtmlx.assert(target,"Invalid nesting target"); + dhtmlx.assert(source,"Invalid nesting source"); + //if source object has init code - call init against target + if (source._init) + target._init(); + + return target; +}; +dhtmlx.proto_extend = function(){ + var origins = arguments; + var compilation = origins[0]; + var construct = []; + + for (var i=origins.length-1; i>0; i--) { + if (typeof origins[i]== "function") + origins[i]=origins[i].prototype; + for (var key in origins[i]){ + if (key == "_init") + construct.push(origins[i][key]); + else if (!compilation[key]) + compilation[key] = origins[i][key]; + } + }; + + if (origins[0]._init) + construct.push(origins[0]._init); + + compilation._init = function(){ + for (var i=0; i handler + this._handlers = {}; //hash of event handlers, ID => handler + this._map = {}; + }, + //temporary block event triggering + block : function(){ + this._events._block = true; + }, + //re-enable event triggering + unblock : function(){ + this._events._block = false; + }, + mapEvent:function(map){ + dhtmlx.extend(this._map, map); + }, + //trigger event + callEvent:function(type,params){ + if (this._events._block) return true; + + type = type.toLowerCase(); + dhtmlx.assert_event_call(this, type, params); + + var event_stack =this._events[type.toLowerCase()]; //all events for provided name + var return_value = true; + + if (dhtmlx.debug) //can slowdown a lot + dhtmlx.log("info","["+this.name+"] event:"+type,params); + + if (event_stack) + for(var i=0; i=0) this.splice(pos,(len||1)); + }, + //find element in collection and remove it + remove:function(value){ + this.removeAt(this.find(value)); + }, + //add element to collection at specific position + insertAt:function(data,pos){ + if (!pos && pos!==0) //add to the end by default + this.push(data); + else { + var b = this.splice(pos,(this.length-pos)); + this[pos] = data; + this.push.apply(this,b); //reconstruct array without loosing this pointer + } + }, + //return index of element, -1 if it doesn't exists + find:function(data){ + for (i=0; i0){ + str=this._toHex[number%16]+str; + number=Math.floor(number/16); + } + while (str.length "); + }, + addSector:function(id,alpha0,alpha1,x,y,R,ky){ + 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); + }, + 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=""+this._map.join("\n")+""; + + 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_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 params = this._calculateParametersOfLineChart(ctx,data,point0,point1,sIndex); + + /*the value that defines the map area position*/ + var areaPos = Math.floor(params.cellWidth/2); + + /*drawing all items*/ + if (data.length) { + + ctx.globalAlpha = this._settings.alpha.call(this,data[0]); + ctx.fillStyle = this._settings.color.call(this,data[0]); + + /*the position of the first item*/ + var y0 = this._getYPointOfLineChart(data[0],point0,point1,params); + var x0 = (this._settings.offset?point0.x+params.cellWidth*0.5:point0.x); + ctx.beginPath(); + ctx.moveTo(x0,point1.y); + ctx.lineTo(x0,y0); + + /*creates map area*/ + map.addRect(data[0].id,[x0-areaPos,y0-areaPos,x0+areaPos,y0+areaPos]); + /*item label*/ + if(!this._settings.yAxis) + this.renderTextAt(false, (!this._settings.offset?false:true), x0, y0-this._settings.labelOffset, this._settings.label(data[0])); + + /*drawing the previous item and the line between to items*/ + for(var i=1; i < data.length;i ++){ + /*horizontal positions of the previous and current items (0.5 - the fix for line width)*/ + var xi = x0+ Math.floor(params.cellWidth*i) - 0.5; + var yi = this._getYPointOfLineChart(data[i],point0,point1,params); + ctx.lineTo(xi,yi); + /*creates map area*/ + map.addRect(data[i].id,[xi-areaPos,yi-areaPos,xi+areaPos,yi+areaPos]); + /*item label*/ + if(!this._settings.yAxis) + this.renderTextAt(false, (!this._settings.offset&&i==(data.length-1)?"left":"center"), xi, yi-this._settings.labelOffset, this._settings.label(data[i])); + } + ctx.lineTo(x0+Math.floor(params.cellWidth*[data.length-1]),point1.y); + ctx.lineTo(x0,point1.y); + ctx.fill(); + } + } +}; +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 params = this._calculateParametersOfLineChart(ctx,data,point0,point1,sIndex); + + /*the value that defines the map area position*/ + var areaPos = Math.floor(params.cellWidth/2); + + var y1 = []; + + /*drawing all items*/ + if (data.length) { + + ctx.globalAlpha = this._settings.alpha.call(this,data[0]); + ctx.fillStyle = this._settings.color.call(this,data[0]); + + /*for the 2nd, 3rd, etc. series*/ + var y01 = (sIndex?data[0].$startY:point1.y); + + /*the position of the first item*/ + var x0 = (this._settings.offset?point0.x+params.cellWidth*0.5:point0.x); + var y02 = this._getYPointOfLineChart(data[0],point0,point1,params)-(sIndex?(point1.y-y01):0); + + y1[0] = y02; + + ctx.beginPath(); + ctx.moveTo(x0,y01); + ctx.lineTo(x0,y02); + + /*creates map area*/ + map.addRect(data[0].id,[x0-areaPos,y02-areaPos,x0+areaPos,y02+areaPos]); + /*item label*/ + if(!this._settings.yAxis) + this.renderTextAt(false, true, x0, y02-this._settings.labelOffset, this._settings.label(data[0])); + + /*drawing the previous item and the line between to items*/ + for(var i=1; i < data.length;i ++){ + /*horizontal positions of the previous and current items (0.5 - the fix for line width)*/ + var xi = x0+ Math.floor(params.cellWidth*i) - 0.5; + var yi2 = this._getYPointOfLineChart(data[i],point0,point1,params)-(sIndex?(point1.y-data[i].$startY):0); + + y1[i] = yi2; + + ctx.lineTo(xi,yi2); + /*creates map area*/ + map.addRect(data[i].id,[xi-areaPos,yi2-areaPos,xi+areaPos,yi2+areaPos]); + /*item label*/ + if(!this._settings.yAxis) + this.renderTextAt(false, true, xi, yi2-this._settings.labelOffset, this._settings.label(data[i])); + } + ctx.lineTo(x0+Math.floor(params.cellWidth*[data.length-1]),y01); + /*drawing lines of the lower part*/ + if(sIndex){ + for(var i=data.length-1; i >=0 ;i--){ + var xi = x0+ Math.floor(params.cellWidth*i) - 0.5; + var yi1 = data[i].$startY; + ctx.lineTo(xi,yi1); + } + } + else ctx.lineTo(x0+ Math.floor(params.cellWidth*(length-1)) - 0.5,y01); + ctx.lineTo(x0,y01); + ctx.fill(); + for(var i=0; i < data.length;i ++){ + data[i].$startY = y1[i]; + } + } + } +}; + + + +/* 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 params = this._calculateParametersOfLineChart(ctx,data,point0,point1,sIndex); + + /*the value that defines the map area position*/ + var areaPos = Math.floor(params.cellWidth/2); + + /*array of all points*/ + var items = []; + + /*drawing all items*/ + if (data.length) { + + /*getting all points*/ + var x0 = (this._settings.offset?point0.x+params.cellWidth*0.5:point0.x); + for(var i=0; i < data.length;i ++){ + var x = ((!i)?x0:Math.floor(params.cellWidth*i) - 0.5 + x0); + var y = this._getYPointOfLineChart(data[i],point0,point1,params); + items.push({x:x,y:y}); + } + var sparam = this._getSplineParameters(items); + + for(var i =0; i< items.length-1; i++){ + var x1 = items[i].x; + var y1 = items[i].y; + var x2 = items[i+1].x; + var y2 = items[i+1].y; + + + for(var j = x1; j < x2; j++) + this._drawLine(ctx,j,this._getSplineYPoint(j,x1,i,sparam.a,sparam.b,sparam.c,sparam.d),j+1,this._getSplineYPoint(j+1,x1,i,sparam.a,sparam.b,sparam.c,sparam.d),this._settings.line.color(data[i]),this._settings.line.width); + this._drawLine(ctx,x2-1,this._getSplineYPoint(j,x1,i,sparam.a,sparam.b,sparam.c,sparam.d),x2,y2,this._settings.line.color(data[i]),this._settings.line.width); + this._drawItemOfLineChart(ctx,x1,y1,data[i],this._settings.label(data[i])); + } + this._drawItemOfLineChart(ctx,x2,y2,data[i],this._settings.label(data[i])); + } + }, + /*gets spline parameter*/ + _getSplineParameters:function(points){ + var h,u,v,s,a,b,c,d,n; + h = []; m = []; + n = points.length; + + for(var i =0; i=1; i--) + s[i] = (v[i] - h[i]*s[i+1])/u[i]; + + a = []; b = []; c = []; d = []; + + for(var i =0; icellWidth) barWidth = cellWidth/this._series.length-4; + /*the half of distance between bars*/ + var barOffset = Math.floor((cellWidth - barWidth*this._series.length)/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(point0.x,point0.y,point1.x,point0.y); + this._settings.gradient(gradient); + } + var scaleY = 0; + /*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(var i=0; i < data.length;i ++){ + + + var value = parseFloat(this._settings.value(data[i])); + if(value>maxValue) value = maxValue; + value -= minValue; + value *= valueFactor; + + /*start point (bottom left)*/ + var x0 = point0.x; + var y0 = point0.y+ barOffset + i*cellWidth+(barWidth+1)*sIndex; + + if(value<0||(this._settings.yAxis&&value===0)){ + this.renderTextAt(true, true, x0+Math.floor(barWidth/2),y0,this._settings.label(data[i])); + continue; + } + + /*takes start value into consideration*/ + if(!yax) value += startValue/unit; + var color = gradient||this._settings.color.call(this,data[i]); + + /*drawing the gradient border of a bar*/ + if(this._settings.border){ + ctx.beginPath(); + ctx.fillStyle = color; + this._setBarHPoints(ctx,x0,y0,barWidth,radius,unit,value,0); + ctx.lineTo(x0,0); + ctx.fill(); + + ctx.fillStyle = "#000000"; + ctx.globalAlpha = 0.37; + ctx.beginPath(); + this._setBarHPoints(ctx,x0,y0,barWidth,radius,unit,value,0); + ctx.fill(); + } + + /*drawing bar body*/ + ctx.globalAlpha = this._settings.alpha.call(this,data[i]); + ctx.fillStyle = (gradient||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(); + ctx.globalAlpha = 1; + + if (inner_gradient!=false){ + var gradParam = this._setBarGradient(ctx,point0.x,y0+barWidth,point0.x+unit*value+2,y0,inner_gradient,color,"x"); + ctx.fillStyle = gradParam.gradient; + ctx.beginPath(); + var points = this._setBarHPoints(ctx,x0,y0+gradParam.offset,barWidth-gradParam.offset*2,radius,unit,value,gradParam.offset); + ctx.fill(); + ctx.globalAlpha = 1; + } + + + /*sets a bar label*/ + this.renderTextAt("middle",false,points[0]+3, parseInt(y0+(points[1]-y0)/2,10), this._settings.label(data[i])); + /*defines a map area for a bar*/ + map.addRect(data[i].id,[x0,y0,points[0],points[1]],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){ + /*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(radiuscellWidth) barWidth = cellWidth-4; + /*the half of distance between bars*/ + var barOffset = Math.floor((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; + + var inner_gradient = false; + var gradient = this._settings.gradient; + if (gradient){ + inner_gradient = true; + } + var scaleY = 0; + /*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(var i=0; i < data.length;i ++){ + + if(!sIndex) + data[i].$startX = point0.x; + + var value = parseFloat(this._settings.value(data[i])); + if(value>maxValue) value = maxValue; + value -= minValue; + value *= valueFactor; + + /*start point (bottom left)*/ + var x0 = point0.x; + var y0 = point0.y+ barOffset + i*cellWidth; + + /*for the 2nd, 3rd, etc. series*/ + if(sIndex) + x0 = data[i].$startX; + + if(value<0||(this._settings.yAxis&&value===0)){ + this.renderTextAt(true, true, x0+Math.floor(barWidth/2),y0,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 the gradient border of a bar*/ + if(this._settings.border){ + ctx.beginPath(); + ctx.fillStyle = color; + this._setBarHPoints(ctx,x0,y0,barWidth,radius,unit,value,0); + ctx.lineTo(x0,0); + ctx.fill(); + + ctx.fillStyle = "#000000"; + ctx.globalAlpha = 0.37; + ctx.beginPath(); + this._setBarHPoints(ctx,x0,y0,barWidth,radius,unit,value,0); + ctx.fill(); + } + ctx.globalAlpha = 1; + /*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(); + var points = this._setBarHPoints(ctx,x0,y0, barWidth,radius,unit,value,0); + ctx.fill(); + ctx.globalAlpha = 1; + } + + /*sets a bar label*/ + this.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,y0,points[0],points[1]],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(ctx,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); + + var scaleY = 0; + /*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])); + if(!value) 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; + + /*for the 2nd, 3rd, etc. series*/ + if(sIndex) + y0 = data[i].$startY; + + /*the max height limit*/ + if(y0 < (point0.y+1)) continue; + + if(value<0||(this._settings.yAxis&&value===0)){ + this.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 the gradient border of a bar*/ + if(this._settings.border){ + ctx.beginPath(); + ctx.fillStyle = color; + this._setStakedBarPoints(ctx,x0-1,y0,barWidth+2,unit,value,0,point0.y); + ctx.lineTo(x0,y0); + ctx.fill(); + + ctx.fillStyle = "#000000"; + ctx.globalAlpha = 0.37; + ctx.beginPath(); + this._setStakedBarPoints(ctx,x0-1,y0,barWidth+2,unit,value,0,point0.y); + ctx.fill(); + } + + /*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,y0,barWidth,unit,value,(this._settings.border?1:0),point0.y); + ctx.fill(); + ctx.globalAlpha = 1; + + /*gradient*/ + if (inner_gradient){ + var gradParam = this._setBarGradient(ctx,x0,y0,x0+barWidth,points[1],inner_gradient,color,"y"); + ctx.fillStyle = gradParam.gradient; + ctx.beginPath(); + var points = this._setStakedBarPoints(ctx,x0+gradParam.offset,y0,barWidth-gradParam.offset*2,unit,value,(this._settings.border?1:0),point0.y); + ctx.fill(); + ctx.globalAlpha = 1; + } + + /*sets a bar label*/ + this.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,points[1],points[0],(data[i].$startY||y0)],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){ + /*start*/ + ctx.moveTo(x0,y0); + /*start of left rounding*/ + var y1 = y0 - unit*value+offset; + /*maximum height limit*/ + if(y1 maxValue) + y = point0.y; + /*the limit of the minimum value*/ + if(value < minValue) + y = point1.y; + return y; + }, + _calculateParametersOfLineChart: 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 = Math.round((point1.x-point0.x)/((!this._settings.offset)?(data.length-1):data.length)); + + /*scales*/ + var yax = !!this._settings.yAxis; + var xax = !!this._settings.xAxis; + + 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(ctx,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 = (params.unit>10?params.unit:10); + 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 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._getLimits(); + 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._settings.origin!="auto"&&!yax)){ + this._drawScales(ctx,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:relValue); + if(!yax&&!(this._settings.origin!="auto"&&xax)){ + /*defines start value for better representation of small values*/ + var startValue = 10; + unit = (relValue?(total_height-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 */ + var barWidth = parseInt(this._settings.width,10); + if(this._series&&(barWidth*this._series.length+4)>cellWidth) barWidth = cellWidth/this._series.length-4; + /*the half of distance between bars*/ + var barOffset = Math.floor((cellWidth - barWidth*this._series.length)/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); + } + var scaleY = 0; + /*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(var i=0; i < data.length;i ++){ + + var value = parseFloat(this._settings.value(data[i])); + if(value>maxValue) value = maxValue; + value -= minValue; + value *= valueFactor; + + /*start point (bottom left)*/ + var x0 = point0.x + barOffset + i*cellWidth+(barWidth+1)*sIndex; + var y0 = point1.y; + + if(value<0||(this._settings.yAxis&&value===0&&!(this._settings.origin!="auto"&&this._settings.origin>minValue))){ + this.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 the gradient border of a bar*/ + if(this._settings.border) + this._drawBarBorder(ctx,x0,y0,barWidth,minValue,radius,unit,value,color); + + /*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); + ctx.globalAlpha = 1; + + if (inner_gradient){ + this._drawBarGradient(ctx,x0,y0,barWidth,minValue,radius,unit,value,color,inner_gradient); + } + /*sets a bar label*/ + if(points[0]!=x0) + this.renderTextAt(false, true, x0+Math.floor(barWidth/2),points[1],this._settings.label(data[i])); + else + this.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,points[3],points[2],points[1]],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]):y0); + var y2 = (p.x0!=x0?p.start:points[1]); + return [x1,y1,x2,y2]; + }, + _drawBarBorder:function(ctx,x0,y0,barWidth,minValue,radius,unit,value,color){ + ctx.save(); + var p = this._correctBarParams(ctx,x0,y0,value,unit,barWidth,minValue); + + 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"); + ctx.fillStyle = gradParam.gradient; + this._setBarPoints(ctx,p.x0+gradParam.offset,p.y0,barWidth-gradParam.offset*2,radius,unit,p.value,gradParam.offset); + 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){ + /*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; + 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=0)||(a1>=0 && a2<=Math.PI)||(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){ + var shadows = ["#676767","#7b7b7b","#a0a0a0","#bcbcbc","#d1d1d1","#d6d6d6"]; + for(var i = shadows.length-1;i>-1;i--){ + ctx.beginPath(); + ctx.fillStyle = shadows[i]; + ctx.arc(x+2,y+2,R+i,0,Math.PI*2,true); + ctx.fill(); + } + }, + /** + * 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; + }, + /** + * 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.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 = 8; + if (in_width) width = labelWidth/1.8; + var alpha = alpha1+(alpha2-alpha1)/2; + + //calcualteion position and correction + R = R-(width-8)/2; + var corr_x = - width; + var corr_y = -8; + var align = "left"; + + //for items in right upper sector + if(alpha>=Math.PI/2 && alpha=Math.PI){ + corr_x = -labelWidth-corr_x+1; + align = "right"; + } + + //calculate position of text + //basically get point at center of pie sector + var y = (y0+Math.floor(R*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 = (alpha < Math.PI/2); + if (left_start && left_end) + x = Math.max(x,x0+3); //right part of pie + else if (!left_start && !left_end) + x = Math.min(x,x0-labelWidth); //left part of pie + + /*correction for the lower sector of the 3D pie*/ + if (!in_width && ky<1 && y > y0*ky){ + y+= (this._settings.height||Math.floor(R/4)); + } + + //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); + } +} + + +/* DHX DEPEND FROM FILE 'template.js'*/ + + +/* + Template - handles html templates +*/ + +/*DHX:Depend dhtmlx.js*/ + +dhtmlx.Template={ + _cache:{ + }, + empty:function(){ + return ""; + }, + setter:function(name, value){ + return dhtmlx.Template.fromHTML(value); + }, + obj_setter:function(name,value){ + var f = dhtmlx.Template.setter(name,value); + var obj = this; + return function(){ + return f.apply(obj, arguments); + }; + }, + fromHTML:function(str){ + if (typeof str == "function") return str; + if (this._cache[str]) + return this._cache[str]; + + //supported idioms + // {obj} => value + // {obj.attr} => named attribute or value of sub-tag in case of xml + // {obj.attr?some:other} conditional output + // {-obj => sub-template + str=(str||"").toString(); + str=str.replace(/[\r\n]+/g,"\\n"); + str=str.replace(/\{obj\.([^}?]+)\?([^:]*):([^}]*)\}/g,"\"+(obj.$1?\"$2\":\"$3\")+\""); + str=str.replace(/\{common\.([^}\(]*)\}/g,"\"+common.$1+\""); + str=str.replace(/\{common\.([^\}\(]*)\(\)\}/g,"\"+(common.$1?common.$1(obj):\"\")+\""); + str=str.replace(/\{obj\.([^}]*)\}/g,"\"+obj.$1+\""); + str=str.replace(/#([a-z0-9_]+)#/gi,"\"+obj.$1+\""); + str=str.replace(/\{obj\}/g,"\"+obj+\""); + str=str.replace(/\{-obj/g,"{obj"); + str=str.replace(/\{-common/g,"{common"); + str="return \""+str+"\";"; + return this._cache[str]= Function("obj","common",str); + } +}; + +dhtmlx.Type={ + /* + adds new template-type + obj - object to which template will be added + data - properties of template + */ + add:function(obj, data){ + //auto switch to prototype, if name of class was provided + if (!obj.types && obj.prototype.types) + obj = obj.prototype; + //if (typeof data == "string") + // data = { template:data }; + + if (dhtmlx.assert_enabled()) + this.assert_event(data); + + var name = data.name||"default"; + + //predefined templates - autoprocessing + this._template(data); + this._template(data,"edit"); + this._template(data,"loading"); + + obj.types[name]=dhtmlx.extend(dhtmlx.extend({},(obj.types[name]||this._default)),data); + return name; + }, + //default template value - basically empty box with 5px margin + _default:{ + css:"default", + template:function(){ return ""; }, + template_edit:function(){ return ""; }, + template_loading:function(){ return "..."; }, + width:150, + height:80, + margin:5, + padding:0 + }, + //template creation helper + _template:function(obj,name){ + name = "template"+(name?("_"+name):""); + var data = obj[name]; + //if template is a string - check is it plain string or reference to external content + if (data && (typeof data == "string")){ + if (data.indexOf("->")!=-1){ + data = data.split("->"); + switch(data[0]){ + case "html": //load from some container on the page + data = dhtmlx.html.getValue(data[1]).replace(/\"/g,"\\\""); + break; + case "http": //load from external file + data = new dhtmlx.ajax().sync().get(data[1],{uid:(new Date()).valueOf()}).responseText; + break; + default: + //do nothing, will use template as is + break; + } + } + obj[name] = dhtmlx.Template.fromHTML(data); + } + } +}; + + + +/* DHX DEPEND FROM FILE 'single_render.js'*/ + + +/* + REnders single item. + Can be used for elements without datastore, or with complex custom rendering logic + + @export + render +*/ + +/*DHX:Depend template.js*/ + +dhtmlx.SingleRender={ + _init:function(){ + }, + //convert item to the HTML text + _toHTML:function(obj){ + /* + this one doesn't support per-item-$template + it has not sense, because we have only single item per object + */ + return this.type._item_start(obj,this.type)+this.type.template(obj,this.type)+this.type._item_end; + }, + //render self, by templating data object + render:function(){ + if (!this.callEvent || this.callEvent("onBeforeRender",[this.data])){ + if (this.data) + this._dataobj.innerHTML = this._toHTML(this.data); + if (this.callEvent) this.callEvent("onAfterRender",[]); + } + } +}; + + +/* DHX DEPEND FROM FILE 'tooltip.js'*/ + + +/* + UI: Tooltip + + @export + show + hide +*/ + +/*DHX:Depend tooltip.css*/ +/*DHX:Depend template.js*/ +/*DHX:Depend single_render.js*/ + +dhtmlx.ui.Tooltip=function(container){ + this.name = "Tooltip"; + this.version = "3.0"; + + if (dhtmlx.assert_enabled()) this._assert(); + + if (typeof container == "string"){ + container = { template:container }; + } + + dhtmlx.extend(this, dhtmlx.Settings); + dhtmlx.extend(this, dhtmlx.SingleRender); + this._parseSettings(container,{ + type:"default", + dy:0, + dx:20 + }); + + //create container for future tooltip + this._dataobj = this._obj = document.createElement("DIV"); + this._obj.className="dhx_tooltip"; + dhtmlx.html.insertBefore(this._obj,document.body.firstChild); +}; +dhtmlx.ui.Tooltip.prototype = { + //show tooptip + //pos - object, pos.x - left, pox.y - top + show:function(data,pos){ + if (this._disabled) return; + //render sefl only if new data was provided + if (this.data!=data){ + this.data=data; + this.render(data); + } + //show at specified position + this._obj.style.top = pos.y+this._settings.dy+"px"; + this._obj.style.left = pos.x+this._settings.dx+"px"; + this._obj.style.display="block"; + }, + //hide tooltip + hide:function(){ + this.data=null; //nulify, to be sure that on next show it will be fresh-rendered + this._obj.style.display="none"; + }, + disable:function(){ + this._disabled = true; + }, + enable:function(){ + this._disabled = false; + }, + types:{ + "default":dhtmlx.Template.fromHTML("{obj.id}") + }, + template_item_start:dhtmlx.Template.empty, + template_item_end:dhtmlx.Template.empty +}; + + + +/* DHX DEPEND FROM FILE 'autotooltip.js'*/ + + +/* + Behavior: AutoTooltip - links tooltip to data driven item +*/ + +/*DHX:Depend tooltip.js*/ + +dhtmlx.AutoTooltip = { + tooltip_setter:function(mode,value){ + var t = new dhtmlx.ui.Tooltip(value); + this.attachEvent("onMouseMove",function(id,e){ //show tooltip on mousemove + t.show(this.get(id),dhtmlx.html.pos(e)); + }); + this.attachEvent("onMouseOut",function(id,e){ //hide tooltip on mouseout + t.hide(); + }); + this.attachEvent("onMouseMoving",function(id,e){ //hide tooltip just after moving start + t.hide(); + }); + return t; + } +}; + + +/* DHX DEPEND FROM FILE 'datastore.js'*/ + + +/*DHX:Depend dhtmlx.js*/ + +/* + DataStore is not a behavior, it standalone object, which represents collection of data. + Call provideAPI to map data API + + @export + exists + idByIndex + indexById + get + set + refresh + dataCount + sort + filter + next + previous + clearAll + first + last +*/ +dhtmlx.DataStore = function(){ + this.name = "DataStore"; + + dhtmlx.extend(this, dhtmlx.EventSystem); + + this.setDriver("xml"); //default data source is an XML + this.pull = {}; //hash of IDs + this.order = dhtmlx.toArray(); //order of IDs + this._tree_store = false; +}; + +dhtmlx.DataStore.prototype={ + //defines type of used data driver + //data driver is an abstraction other different data formats - xml, json, csv, etc. + setDriver:function(type){ + dhtmlx.assert(dhtmlx.DataDriver[type],"incorrect DataDriver"); + this.driver = dhtmlx.DataDriver[type]; + }, + _tree_parse:function(data){ + if (data.item){ //FIXME + if (!(data.item instanceof Array)) + data.item=[data.item]; + for (var i=0; i < data.item.length; i++) { + var item = data.item[i]; + var id = this.id(item); + + data.item[i]=id; + this.pull[id]=item; + item.parent = data.id; + item.level = data.level+1; + this._tree_parse(item); + }; + } + }, + //process incoming raw data + _parse:function(data){ + //get size and position of data + var info = this.driver.getInfo(data); + //get array of records + + var recs = this.driver.getRecords(data); + var from = (info._from||0)*1; + var j=0; + for (var i=0; ito){ //can be in case of backward shift-selection + var a=to; to=from; from=a; + } + } + return this.getIndexRange(from,to); + }, + //converts range of indexes to array of all IDs between them + getIndexRange:function(from,to){ + to=Math.min(to,this.dataCount()-1); + + var ret=dhtmlx.toArray(); //result of method is rich-array + for (var i=from; i <= to; i++) + ret.push(this.get(this.order[i])); + return ret; + }, + //returns total count of elements + dataCount:function(){ + return this.order.length; + }, + //returns truy if item with such ID exists + exists:function(id){ + return !!(this.pull[id]); + }, + //nextmethod is not visible on component level, check DataMove.move + //moves item from source index to the target index + move:function(sindex,tindex){ + if (sindex<0 || tindex<0){ + dhtmlx.error("DataStore::move","Incorrect indexes"); + return; + } + + var id = this.idByIndex(sindex); + var obj = this.get(id); + + this.order.removeAt(sindex); //remove at old position + //if (sindex data_size){ + dhtmlx.log("Warning","DataStore:add","Index of out of bounds"); + index = Math.min(this.order.length,index); + } + + if (!this.callEvent("onbeforeAdd",[id,index])) return; + + if (this.exists(id)) return dhtmlx.error("Not unique ID"); + + this.pull[id]=obj; + this.order.insertAt(id,index); + if (this._filter_order){ //adding during filtering + //we can't know the location of new item in full dataset, making suggestion + //put at end by default + var original_index = this._filter_order.length; + //put at start only if adding to the start and some data exists + if (!index && this.order.length) + original_index = 0; + + this._filter_order.insertAt(id,original_index); + } + + this.callEvent("onafterAdd",[id,index]); + //repaint signal + this.callEvent("onStoreUpdated",[id,obj,"add"]); + return id; + }, + + //removes element from datastore + remove:function(id){ + //id can be an array of IDs - result of getSelect, for example + if (id instanceof Array){ + for (var i=0; i < id.length; i++) + this.remove(id[i]); + return; + } + if (!this.callEvent("onbeforedelete",[id])) return; + if (!this.exists(id)) return dhtmlx.error("Not existing ID",id); + var obj = this.get(id); //save for later event + //clear from collections + this.order.remove(id); + if (this._filter_order) + this._filter_order.remove(id); + + delete this.pull[id]; + this.callEvent("onafterdelete",[id]); + //repaint signal + this.callEvent("onStoreUpdated",[id,obj,"delete"]); + }, + //deletes all records in datastore + clearAll:function(){ + //instead of deleting one by one - just reset inner collections + this.pull = {}; + this.order = dhtmlx.toArray(); + this._filter_order = null; + this.callEvent("onClearAll",[]); + this.refresh(); + }, + //converts id to index + idByIndex:function(index){ + if (index>=this.order.length || index<0) + dhtmlx.log("Warning","DataStore::idByIndex Incorrect index"); + + return this.order[index]; + }, + //converts index to id + indexById:function(id){ + var res = this.order.find(id); //slower than idByIndex + + if (res == -1) + dhtmlx.log("Warning","DataStore::indexById Non-existing ID: "+ id); + + return res; + }, + //returns ID of next element + next:function(id,step){ + return this.order[this.indexById(id)+(step||1)]; + }, + //returns ID of first element + first:function(){ + return this.order[0]; + }, + //returns ID of last element + last:function(){ + return this.order[this.order.length-1]; + }, + //returns ID of previous element + previous:function(id,step){ + return this.order[this.indexById(id)-(step||1)]; + }, + /* + sort data in collection + by - settings of sorting + + or + + by - sorting function + dir - "asc" or "desc" + + or + + by - property + dir - "asc" or "desc" + as - type of sortings + + Sorting function will accept 2 parameters and must return 1,0,-1, based on desired order + */ + sort:function(by, dir, as){ + var sort = by; + if (typeof by == "function") + sort = {as:by, dir:dir}; + else if (typeof by == "string") + sort = {by:by, dir:dir, as:as}; + + + var parameters = [sort.by, sort.dir, sort.as]; + if (!this.callEvent("onbeforesort",parameters)) return; + + if (this.order.length){ + var sorter = dhtmlx.sort.create(sort); + //get array of IDs + var neworder = this.getRange(this.first(), this.last()); + neworder.sort(sorter); + this.order = neworder.map(function(obj){ return this.id(obj); },this); + } + + //repaint self + this.refresh(); + + this.callEvent("onaftersort",parameters); + }, + /* + Filter datasource + + text - property, by which filter + value - filter mask + + or + + text - filter method + + Filter method will receive data object and must return true or false + */ + filter:function(text,value){ + //remove previous filtering , if any + if (this._filter_order){ + this.order = this._filter_order; + delete this._filter_order; + } + //if text not define -just unfilter previous state and exit + if (text){ + var filter = text; + if (typeof text == "string"){ + text = dhtmlx.Template.setter(0,text); + filter = function(obj,value){ //default filter - string start from, case in-sensitive + return text(obj).toLowerCase().indexOf(value)!=-1; + }; + } + + value = (value||"").toString().toLowerCase(); + var neworder = dhtmlx.toArray(); + this.order.each(function(id){ + if (filter(this.get(id),value)) + neworder.push(id); + },this); + //set new order of items, store original + this._filter_order = this.order; + this.order = neworder; + } + //repaint self + this.refresh(); + }, + /* + Iterate through collection + */ + each:function(method,master){ + for (var i=0; ib?1:(ab?1:(ab?1:(a max) max = property(obj)*1; + }); + return max; + }, + _split_data_by:function(stats){ + var any=function(property, data){ + property = dhtmlx.Template.setter(0,property); + return property(data[0]); + }; + var key = dhtmlx.Template.setter(0,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(name, 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(name, config){ + if (typeof config != "object") + config = { by:config }; + + this._mergeSettings(config,{ + as:"string", + dir:"asc" + }); + return config; + } +}; + + +/* DHX DEPEND FROM FILE 'key.js'*/ + + +/* + Behavior:KeyEvents - hears keyboard +*/ +dhtmlx.KeyEvents = { + _init:function(){ + //attach handler to the main container + dhtmlx.event(this._obj,"keypress",this._onKeyPress,this); + }, + //called on each key press , when focus is inside of related component + _onKeyPress:function(e){ + e=e||event; + var code = e.which||e.keyCode; //FIXME better solution is required + this.callEvent((this._edit_id?"onEditKeyPress":"onKeyPress"),[code,e.ctrlKey,e.shiftKey,e]); + } +}; + + +/* DHX DEPEND FROM FILE 'mouse.js'*/ + + +/* + Behavior:MouseEvents - provides inner evnets for mouse actions +*/ +dhtmlx.MouseEvents={ + _init: function(){ + //attach dom events if related collection is defined + if (this.on_click){ + dhtmlx.event(this._obj,"click",this._onClick,this); + dhtmlx.event(this._obj,"contextmenu",this._onContext,this); + } + if (this.on_dblclick) + dhtmlx.event(this._obj,"dblclick",this._onDblClick,this); + if (this.on_mouse_move){ + dhtmlx.event(this._obj,"mousemove",this._onMouse,this); + dhtmlx.event(this._obj,(dhtmlx._isIE?"mouseleave":"mouseout"),this._onMouse,this); + } + + }, + //inner onclick object handler + _onClick: function(e) { + return this._mouseEvent(e,this.on_click,"ItemClick"); + }, + //inner ondblclick object handler + _onDblClick: function(e) { + return this._mouseEvent(e,this.on_dblclick,"ItemDblClick"); + }, + //process oncontextmenu events + _onContext: function(e) { + var id = dhtmlx.html.locate(e, this._id); + if (id && !this.callEvent("onBeforeContextMenu", [id,e])) + return dhtmlx.html.preventEvent(e); + }, + /* + event throttler - ignore events which occurs too fast + during mouse moving there are a lot of event firing - we need no so much + also, mouseout can fire when moving inside the same html container - we need to ignore such fake calls + */ + _onMouse:function(e){ + if (dhtmlx._isIE) //make a copy of event, will be used in timed call + e = document.createEventObject(event); + + if (this._mouse_move_timer) //clear old event timer + window.clearTimeout(this._mouse_move_timer); + + //this event just inform about moving operation, we don't care about details + this.callEvent("onMouseMoving",[e]); + //set new event timer + this._mouse_move_timer = window.setTimeout(dhtmlx.bind(function(){ + //called only when we have at least 100ms after previous event + if (e.type == "mousemove") + this._onMouseMove(e); + else + this._onMouseOut(e); + },this),500); + }, + //inner mousemove object handler + _onMouseMove: function(e) { + if (!this._mouseEvent(e,this.on_mouse_move,"MouseMove")) + this.callEvent("onMouseOut",[e||event]); + }, + //inner mouseout object handler + _onMouseOut: function(e) { + this.callEvent("onMouseOut",[e||event]); + }, + //common logic for click and dbl-click processing + _mouseEvent:function(e,hash,name){ + e=e||event; + var trg=e.target||e.srcElement; + var css = ""; + var id = null; + var found = false; + //loop through all parents + while (trg && trg.parentNode){ + if (!found && trg.getAttribute){ //if element with ID mark is not detected yet + id = trg.getAttribute(this._id); //check id of current one + if (id){ + if (trg.getAttribute("userdata")) + this.callEvent("onLocateData",[id,trg]); + if (!this.callEvent("on"+name,[id,e,trg])) return; //it will be triggered only for first detected ID, in case of nested elements + found = true; //set found flag + } + } + css=trg.className; + if (css){ //check if pre-defined reaction for element's css name exists + css = css.split(" "); + css = css[0]||css[1]; //FIXME:bad solution, workaround css classes which are starting from whitespace + if (hash[css]) + return hash[css].call(this,e,id,trg); + } + trg=trg.parentNode; + } + return found; //returns true if item was located and event was triggered + } +}; + + +/* DHX DEPEND FROM FILE 'config.js'*/ + + +/* + Behavior:Settings + + @export + customize + config +*/ + +/*DHX:Depend template.js*/ +/*DHX:Depend dhtmlx.js*/ + +dhtmlx.Settings={ + _init:function(){ + /* + property can be accessed as this.config.some + in same time for inner call it have sense to use _settings + because it will be minified in final version + */ + this._settings = this.config= {}; + }, + define:function(property, value){ + if (typeof property == "object") + return this._parseSeetingColl(property); + return this._define(property, value); + }, + _define:function(property,value){ + dhtmlx.assert_settings.call(this,property,value); + + //method with name {prop}_setter will be used as property setter + //setter is optional + var setter = this[property+"_setter"]; + return this._settings[property]=setter?setter.call(this,property,value):value; + }, + //process configuration object + _parseSeetingColl:function(coll){ + if (coll){ + for (var a in coll) //for each setting + this._define(a,coll[a]); //set value through config + } + }, + //helper for object initialization + _parseSettings:function(obj,initial){ + //initial - set of default values + var settings = dhtmlx.extend({},initial); + //code below will copy all properties over default one + if (typeof obj == "object" && !obj.tagName) + dhtmlx.extend(settings,obj); + //call config for each setting + this._parseSeetingColl(settings); + }, + _mergeSettings:function(config, defaults){ + for (var key in defaults) + switch(typeof config[key]){ + case "object": + config[key] = this._mergeSettings((config[key]||{}), defaults[key]); + break; + case "undefined": + config[key] = defaults[key]; + break; + default: //do nothing + break; + } + return config; + }, + //helper for html container init + _parseContainer:function(obj,name,fallback){ + /* + parameter can be a config object, in such case real container will be obj.container + or it can be html object or ID of html object + */ + if (typeof obj == "object" && !obj.tagName) + obj=obj.container; + this._obj = dhtmlx.toNode(obj); + if (!this._obj && fallback) + this._obj = fallback(obj); + + dhtmlx.assert(this._obj, "Incorrect html container"); + + this._obj.className+=" "+name; + this._obj.onselectstart=function(){return false;}; //block selection by default + this._dataobj = this._obj;//separate reference for rendering modules + }, + //apply template-type + _set_type:function(name){ + //parameter can be a hash of settings + if (typeof name == "object") + return this.type_setter("type",name); + + dhtmlx.assert(this.types, "RenderStack :: Types are not defined"); + dhtmlx.assert(this.types[name],"RenderStack :: Inccorect type name",name); + //or parameter can be a name of existing template-type + this.type=dhtmlx.extend({},this.types[name]); + this.customize(); //init configs + }, + customize:function(obj){ + //apply new properties + if (obj) dhtmlx.extend(this.type,obj); + + //init tempaltes for item start and item end + this.type._item_start = dhtmlx.Template.fromHTML(this.template_item_start(this.type)); + this.type._item_end = this.template_item_end(this.type); + + //repaint self + this.render(); + }, + //config.type - creates new template-type, based on configuration object + type_setter:function(mode,value){ + this._set_type(typeof value == "object"?dhtmlx.Type.add(this,value):value); + return value; + }, + //config.template - creates new template-type with defined template string + template_setter:function(mode,value){ + return this.type_setter("type",{template:value}); + }, + //config.css - css name for top level container + css_setter:function(mode,value){ + this._obj.className += " "+value; + return value; + } +}; + + +/* DHX DEPEND FROM FILE 'compatibility.js'*/ + + +/* + Collection of compatibility hacks +*/ + +/*DHX:Depend dhtmlx.js*/ + +dhtmlx.compat=function(name, obj){ + //check if name hash present, and applies it when necessary + if (dhtmlx.compat[name]) + dhtmlx.compat[name](obj); +}; + + +(function(){ + if (!window.dhtmlxError){ + //dhtmlxcommon is not included + + //create fake error tracker for connectors + var dummy = function(){}; + window.dhtmlxError={ catchError:dummy, throwError:dummy }; + //helpers instead of ones from dhtmlxcommon + window.convertStringToBoolean=function(value){ + return !!value; + }; + window.dhtmlxEventable = function(node){ + dhtmlx.extend(node,dhtmlx.EventSystem); + }; + //imitate ajax layer of dhtmlxcommon + var loader = { + getXMLTopNode:function(name){ + + }, + doXPath:function(path){ + return dhtmlx.DataDriver.xml.xpath(this.xml,path); + }, + xmlDoc:{ + responseXML:true + } + }; + //wrap ajax methods of dataprocessor + dhtmlx.compat.dataProcessor=function(obj){ + //FIXME + //this is pretty ugly solution - we replace whole method , so changes in dataprocessor need to be reflected here + + var sendData = "_sendData"; + var in_progress = "_in_progress"; + var tMode = "_tMode"; + var waitMode = "_waitMode"; + + obj[sendData]=function(a1,rowId){ + if (!a1) return; //nothing to send + if (rowId) + this[in_progress][rowId]=(new Date()).valueOf(); + + if (!this.callEvent("onBeforeDataSending",rowId?[rowId,this.getState(rowId)]:[])) return false; + + var a2 = this; + var a3=this.serverProcessor; + if (this[tMode]!="POST") + //use dhtmlx.ajax instead of old ajax layer + dhtmlx.ajax().get(a3+((a3.indexOf("?")!=-1)?"&":"?")+this.serialize(a1,rowId),"",function(t,x,xml){ + loader.xml = dhtmlx.DataDriver.xml.checkResponse(t,x); + a2.afterUpdate(a2, null, null, null, loader); + }); + else + dhtmlx.ajax().post(a3,this.serialize(a1,rowId),function(t,x,xml){ + loader.xml = dhtmlx.DataDriver.xml.checkResponse(t,x); + a2.afterUpdate(a2, null, null, null, loader); + }); + + this[waitMode]++; + }; + }; + } + +})(); + + +/* DHX DEPEND FROM FILE 'compatibility_layout.js'*/ + + +/*DHX:Depend dhtmlx.js*/ +/*DHX:Depend compatibility.js*/ + +if (!dhtmlx.attaches) + dhtmlx.attaches = {}; + +dhtmlx.attaches.attachAbstract=function(name, conf){ + var obj = document.createElement("DIV"); + obj.id = "CustomObject_"+dhtmlx.uid(); + obj.style.width = "100%"; + obj.style.height = "100%"; + obj.cmp = "grid"; + document.body.appendChild(obj); + this.attachObject(obj.id); + + conf.container = obj.id; + + var that = this.vs[this.av]; + that.grid = new window[name](conf); + + that.gridId = obj.id; + that.gridObj = obj; + + + that.grid.setSizes = function(){ + if (this.resize) this.resize(); + else this.render(); + }; + + var method_name="_viewRestore"; + return this.vs[this[method_name]()].grid; +}; +dhtmlx.attaches.attachDataView = function(conf){ + return this.attachAbstract("dhtmlXDataView",conf); +}; +dhtmlx.attaches.attachChart = function(conf){ + return this.attachAbstract("dhtmlXChart",conf); +}; + +dhtmlx.compat.layout = function(){}; + + + +/* DHX DEPEND FROM FILE 'load.js'*/ + + +/* + ajax operations + + can be used for direct loading as + dhtmlx.ajax(ulr, callback) + or + dhtmlx.ajax().get(url) + dhtmlx.ajax().post(url) + +*/ + +/*DHX:Depend datastore.js*/ +/*DHX:Depend dhtmlx.js*/ + +dhtmlx.ajax = function(url,call,master){ + //if parameters was provided - made fast call + if (arguments.length!==0){ + var http_request = new dhtmlx.ajax(); + if (master) http_request.master=master; + http_request.get(url,null,call); + } + if (!this.getXHR) return new dhtmlx.ajax(); //allow to create new instance without direct new declaration + + return this; +}; +dhtmlx.ajax.prototype={ + //creates xmlHTTP object + getXHR:function(){ + if (dhtmlx._isIE) + return new ActiveXObject("Microsoft.xmlHTTP"); + else + return new XMLHttpRequest(); + }, + /* + send data to the server + params - hash of properties which will be added to the url + call - callback, can be an array of functions + */ + send:function(url,params,call){ + var x=this.getXHR(); + if (typeof call == "function") + call = [call]; + //add extra params to the url + if (typeof params == "object"){ + var t=[]; + for (var a in params) + t.push(a+"="+encodeURIComponent(params[a]));// utf-8 escaping + params=t.join("&"); + } + if (params && !this.post){ + url=url+(url.indexOf("?")!=-1 ? "&" : "?")+params; + params=null; + } + + x.open(this.post?"POST":"GET",url,!this._sync); + if (this.post) + x.setRequestHeader('Content-type','application/x-www-form-urlencoded'); + + //async mode, define loading callback + if (!this._sync){ + var self=this; + x.onreadystatechange= function(){ + if (!x.readyState || x.readyState == 4){ + dhtmlx.log_full_time("data_loading"); //log rendering time + if (call && self) + for (var i=0; i < call.length; i++) //there can be multiple callbacks + if (call[i]) + call[i].call((self.master||self),x.responseText,x.responseXML,x); + self.master=null; + call=x=self=null; //anti-leak + } + }; + } + + x.send(params||null); + return x; //return XHR, which can be used in case of sync. mode + }, + //GET request + get:function(url,params,call){ + this.post=false; + return this.send(url,params,call); + }, + //POST request + post:function(url,params,call){ + this.post=true; + return this.send(url,params,call); + }, + sync:function(){ + this._sync = true; + return this; + } +}; + + +/* + Behavior:DataLoader - load data in the component + + @export + load + parse +*/ +dhtmlx.DataLoader={ + _init:function(){ + //prepare data store + this.data = new dhtmlx.DataStore(); + }, + //loads data from external URL + load:function(url,call){ + this.callEvent("onXLS",[]); + if (typeof call == "string"){ //second parameter can be a loading type or callback + this.data.setDriver(call); + call = arguments[2]; + } + //prepare data feed for dyn. loading + if (!this.data.feed) + this.data.feed = function(from,count){ + //allow only single request at same time + if (this._load_count) + return this._load_count=[from,count]; //save last ignored request + else + this._load_count=true; + + this.load(url+((url.indexOf("?")==-1)?"?":"&")+"posStart="+from+"&count="+count,function(){ + //after loading check if we have some ignored requests + var temp = this._load_count; + this._load_count = false; + if (typeof temp =="object") + this.data.feed.apply(this, temp); //load last ignored request + }); + }; + //load data by async ajax call + dhtmlx.ajax(url,[this._onLoad,call],this); + }, + //loads data from object + parse:function(data,type){ + this.callEvent("onXLS",[]); + if (type) + this.data.setDriver(type); + this._onLoad(data,null); + }, + //default after loading callback + _onLoad:function(text,xml,loader){ + this.data._parse(this.data.driver.toObject(text,xml)); + this.callEvent("onXLE",[]); + } +}; + +/* + Abstraction layer for different data types +*/ + +dhtmlx.DataDriver={}; +dhtmlx.DataDriver.json={ + //convert json string to json object if necessary + toObject:function(data){ + if (typeof data == "string"){ + eval ("dhtmlx.temp="+data); + return dhtmlx.temp; + } + return data; + }, + //get array of records + getRecords:function(data){ + if (data && !(data instanceof Array)) + return [data]; + return data; + }, + //get hash of properties for single record + getDetails:function(data){ + return data; + }, + //get count of data and position at which new data need to be inserted + getInfo:function(data){ + return { + _size:(data.total_count||0), + _from:(data.pos||0) + }; + } +}; + +dhtmlx.DataDriver.html={ + /* + incoming data can be + - collection of nodes + - ID of parent container + - HTML text + */ + toObject:function(data){ + if (typeof data == "string"){ + var t=null; + if (data.indexOf("<")==-1) //if no tags inside - probably its an ID + t = dhtmlx.toNode(data); + if (!t){ + t=document.createElement("DIV"); + t.innerHTML = data; + } + + return t.getElementsByTagName(this.tag); + } + return data; + }, + //get array of records + getRecords:function(data){ + if (data.tagName) + return data.childNodes; + return data; + }, + //get hash of properties for single record + getDetails:function(data){ + return dhtmlx.DataDriver.xml.tagToObject(data); + }, + //dyn loading is not supported by HTML data source + getInfo:function(data){ + return { + _size:0, + _from:0 + }; + }, + tag: "LI" +}; + +dhtmlx.DataDriver.jsarray={ + //eval jsarray string to jsarray object if necessary + toObject:function(data){ + if (typeof data == "string"){ + eval ("dhtmlx.temp="+data); + return dhtmlx.temp; + } + return data; + }, + //get array of records + getRecords:function(data){ + return data; + }, + //get hash of properties for single record, in case of array they will have names as "data{index}" + getDetails:function(data){ + var result = {}; + for (var i=0; i < data.length; i++) + result["data"+i]=data[i]; + + return result; + }, + //dyn loading is not supported by js-array data source + getInfo:function(data){ + return { + _size:0, + _from:0 + }; + } +}; + +dhtmlx.DataDriver.csv={ + //incoming data always a string + toObject:function(data){ + return data; + }, + //get array of records + getRecords:function(data){ + return data.split(this.row); + }, + //get hash of properties for single record, data named as "data{index}" + getDetails:function(data){ + data = this.stringToArray(data); + var result = {}; + for (var i=0; i < data.length; i++) + result["data"+i]=data[i]; + + return result; + }, + //dyn loading is not supported by csv data source + getInfo:function(data){ + return { + _size:0, + _from:0 + }; + }, + //split string in array, takes string surrounding quotes in account + stringToArray:function(data){ + data = data.split(this.cell); + for (var i=0; i < data.length; i++) + data[i] = data[i].replace(/^[ \t\n\r]*(\"|)/g,"").replace(/(\"|)[ \t\n\r]*$/g,""); + return data; + }, + row:"\n", //default row separator + cell:"," //default cell separator +}; + +dhtmlx.DataDriver.xml={ + //convert xml string to xml object if necessary + toObject:function(text,xml){ + if (xml && (xml=this.checkResponse(text,xml))) //checkResponse - fix incorrect content type and extra whitespaces errors + return xml; + if (typeof text == "string"){ + return this.fromString(text); + } + return text; + }, + //get array of records + getRecords:function(data){ + return this.xpath(data,this.records); + }, + records:"/*/item", + userdata:"/*/userdata", + //get hash of properties for single record + getDetails:function(data){ + return this.tagToObject(data,{}); + }, + getUserData:function(data,col){ + col = col || {}; + var ud = this.xpath(data,this.userdata); + for (var i=0; i < ud.length; i++) { + var udx = this.tagToObject(ud[i]); + col[udx.name] = udx.value; + } + return col; + }, + //get count of data and position at which new data_loading need to be inserted + getInfo:function(data){ + return { + _size:(data.documentElement.getAttribute("total_count")||0), + _from:(data.documentElement.getAttribute("pos")||0) + }; + }, + //xpath helper + xpath:function(xml,path){ + if (window.XPathResult){ //FF, KHTML, Opera + var node=xml; + if(xml.nodeName.indexOf("document")==-1) + xml=xml.ownerDocument; + var res = []; + var col = xml.evaluate(path, node, null, XPathResult.ANY_TYPE, null); + var temp = col.iterateNext(); + while (temp){ + res.push(temp); + temp = col.iterateNext(); + } + return res; + } //IE + return xml.selectNodes(path); + }, + //convert xml tag to js object, all subtags and attributes are mapped to the properties of result object + tagToObject:function(tag,z){ + z=z||{}; + //map attributes + var a=tag.attributes; + for (var i=0; i5?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(nmin<0) start =-start-2*step; + } + var end = start; + while(end1) + 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.renderTextAt(top, center, x,y,this._settings.xAxis.template(obj)); + }, + _drawXAxisLine:function(ctx,x,y1,y2){ + if (!this._settings.xAxis||!this._settings.xAxis.lines) return; + this._drawLine(ctx,x,y1,x,y2,this._settings.xAxis.color,0.2); + }, + _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(); + }, + _getRelativeValue:function(minValue,maxValue){ + var relValue; + var valueFactor = 1; + if(maxValue != minValue){ + relValue = maxValue - minValue; + if(Math.abs(relValue) < 1){ + while(Math.abs(relValue)<1){ + valueFactor *= 10; + relValue *= 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){ + this._active_serie = tag.getAttribute("userdata"); + for (var i=0; i < this._series.length; i++) { + var tip = this._series[i].tooltip; + if (tip) + tip.disable(); + } + var tip = this._series[this._active_serie].tooltip; + if (tip) + tip.enable(); + }, + /** + * 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(ctx,data,width,height){ + /*position of the legend block*/ + var x=0,y=0; + /*legend config*/ + var legend = this._settings.legend; + /*the legend sizes*/ + var legendHeight,legendWidth; + + var style = (this._settings.legend.layout!="x"?"width:"+legend.width+"px":""); + /*creation of legend container*/ + var legendContainer = dhtmlx.html.create("DIV",{ + "class":"dhx_chart_legend", + "style":"left:"+x+"px; top:"+y+"px;"+style + },""); + this._obj.appendChild(legendContainer); + /*rendering legend text items*/ + var legendItems = []; + if(!legend.values) + for(var i = 0; i < data.length; i++){ + legendItems.push(this._drawLegendText(legendContainer,legend.template(data[i]))); + } + else + for(var i = 0; i < legend.values.length; i++){ + legendItems.push(this._drawLegendText(legendContainer,legend.values[i].text)); + } + legendWidth = legendContainer.offsetWidth; + legendHeight = legendContainer.offsetHeight; + this._settings.legend.width = legendWidth; + this._settings.legend.height = legendHeight; + /*setting legend position*/ + if(legendWidth 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; + if(type == "light"){ + if(axis == "x") + gradient = ctx.createLinearGradient(x1,y1,x2,y1); + else + gradient = ctx.createLinearGradient(x1,y1,x1,y2); + gradient.addColorStop(0,"#FFFFFF"); + gradient.addColorStop(0.9,color); + gradient.addColorStop(1,color); + offset = 2; + } + 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); + gradient.addColorStop(0,"#000000"); + gradient.addColorStop(0.5,"#FFFFFF"); + gradient.addColorStop(0.6,"#FFFFFF"); + gradient.addColorStop(1,"#000000"); + } + return {gradient:gradient,offset:offset}; + } +}; + +dhtmlx.compat("layout"); \ No newline at end of file -- cgit v1.2.3 From fd89c4d708af3147bf0c67452090ac77963f172f Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 20 Jun 2011 15:04:27 +0200 Subject: [FIX] bug in dhtmlxChart in case of stacked bar chart where the first series contains a value of 0 bzr revid: xmo@openerp.com-20110620130427-kghvj8gbjth4z1aw --- .../base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js') diff --git a/addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js b/addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js index 57e5b5d5b0d..b2179c6f9f7 100644 --- a/addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js +++ b/addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js @@ -1487,7 +1487,7 @@ dhtmlx.chart.stackedBarH = { /*for the 2nd, 3rd, etc. series*/ if(sIndex) - x0 = data[i].$startX; + x0 = data[i].$startX || x0; if(value<0||(this._settings.yAxis&&value===0)){ this.renderTextAt(true, true, x0+Math.floor(barWidth/2),y0,this._settings.label(data[i])); @@ -1622,8 +1622,8 @@ dhtmlx.chart.stackedBar = { /*for the 2nd, 3rd, etc. series*/ if(sIndex) - y0 = data[i].$startY; - + y0 = data[i].$startY || y0; + /*the max height limit*/ if(y0 < (point0.y+1)) continue; -- cgit v1.2.3 From 2397a86d19ad4517b9cb70c2ab07f6348dfc2577 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 20 Jun 2011 15:04:57 +0200 Subject: [MEH] whitespace changes PyCharm insists on making when I open dhtmlxChart bzr revid: xmo@openerp.com-20110620130457-2eooal5w8opt3pn7 --- .../lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js | 358 ++++++++++----------- 1 file changed, 179 insertions(+), 179 deletions(-) (limited to 'addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js') diff --git a/addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js b/addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js index b2179c6f9f7..af9b4437b31 100644 --- a/addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js +++ b/addons/base_graph/static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js @@ -3,15 +3,15 @@ Copyright DHTMLX LTD. http://www.dhtmlx.com You allowed to use this component or parts of it under GPL terms To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com */ -/* -2010 September 30 -*/ - - - -/* DHX DEPEND FROM FILE 'assert.js'*/ - - +/* +2010 September 30 +*/ + + + +/* DHX DEPEND FROM FILE 'assert.js'*/ + + if (!window.dhtmlx) dhtmlx={}; @@ -250,12 +250,12 @@ if (dhtmlx.assert_enabled()){ return t; }; -} - - -/* DHX DEPEND FROM FILE 'dhtmlx.js'*/ - - +} + + +/* DHX DEPEND FROM FILE 'dhtmlx.js'*/ + + /*DHX:Depend assert.js*/ /* @@ -760,12 +760,12 @@ dhtmlx.html={ } })(); -dhtmlx.ui={}; - - -/* DHX DEPEND FROM FILE 'destructor.js'*/ - - +dhtmlx.ui={}; + + +/* DHX DEPEND FROM FILE 'destructor.js'*/ + + /* Behavior:Destruction @@ -820,12 +820,12 @@ dhtmlx.event(window,"unload",function(){ ev[0].detachEvent("on"+ev[1],ev[2]); delete dhtmlx._events[a]; } -}); - - -/* DHX DEPEND FROM FILE 'math.js'*/ - - +}); + + +/* 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){ @@ -841,12 +841,12 @@ dhtmlx.math.toHex = function(number, length){ }; - - - -/* DHX DEPEND FROM FILE 'map.js'*/ - - + + + +/* DHX DEPEND FROM FILE 'map.js'*/ + + /*DHX:Depend dhtmlx.js*/ dhtmlx.ui.Map = function(key){ @@ -894,19 +894,19 @@ dhtmlx.ui.Map.prototype = { this._map = []; } -}; - - -/* DHX DEPEND FROM FILE 'ext/chart/chart_base.js'*/ - - +}; + + +/* DHX DEPEND FROM FILE 'ext/chart/chart_base.js'*/ + + /*DHX:Depend map.js*/ -dhtmlx.chart = {}; - - -/* DHX DEPEND FROM FILE 'ext/chart/chart_area.js'*/ - - +dhtmlx.chart = {}; + + +/* DHX DEPEND FROM FILE 'ext/chart/chart_area.js'*/ + + /*DHX:Depend ext/chart/chart_base.js*/ dhtmlx.chart.area = { /** @@ -984,7 +984,7 @@ dhtmlx.chart.stackedArea ={ ctx.globalAlpha = this._settings.alpha.call(this,data[0]); ctx.fillStyle = this._settings.color.call(this,data[0]); - + /*for the 2nd, 3rd, etc. series*/ var y01 = (sIndex?data[0].$startY:point1.y); @@ -1037,12 +1037,12 @@ dhtmlx.chart.stackedArea ={ } } }; - - - -/* DHX DEPEND FROM FILE 'ext/chart/chart_spline.js'*/ - - + + + +/* DHX DEPEND FROM FILE 'ext/chart/chart_spline.js'*/ + + /*DHX:Depend ext/chart/chart_base.js*/ dhtmlx.chart.spline = { /** @@ -1129,12 +1129,12 @@ dhtmlx.chart.spline = { _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 FROM FILE 'ext/chart/chart_barh.js'*/ + + /*DHX:Depend ext/chart/chart_base.js*/ dhtmlx.chart.barH = { /** @@ -1388,12 +1388,12 @@ dhtmlx.chart.barH = { } }; - - - -/* DHX DEPEND FROM FILE 'ext/chart/chart_stackedbarh.js'*/ - - + + + +/* DHX DEPEND FROM FILE 'ext/chart/chart_stackedbarh.js'*/ + + /*DHX:Depend ext/chart/chart_base.js*/ /*DHX:Depend ext/chart/chart_barh.js*/ @@ -1538,12 +1538,12 @@ dhtmlx.chart.stackedBarH = { data[i].$startX = points[0]; } } -} - - -/* DHX DEPEND FROM FILE 'ext/chart/chart_stackedbar.js'*/ - - +} + + +/* DHX DEPEND FROM FILE 'ext/chart/chart_stackedbar.js'*/ + + /*DHX:Depend ext/chart/chart_base.js*/ dhtmlx.chart.stackedBar = { /** @@ -1711,12 +1711,12 @@ dhtmlx.chart.stackedBar = { return [x5,y3-2*offset]; } }; - - - -/* DHX DEPEND FROM FILE 'ext/chart/chart_line.js'*/ - - + + + +/* DHX DEPEND FROM FILE 'ext/chart/chart_line.js'*/ + + /*DHX:Depend ext/chart/chart_base.js*/ dhtmlx.chart.line = { @@ -1865,12 +1865,12 @@ dhtmlx.chart.line = { return params; } }; - - - -/* DHX DEPEND FROM FILE 'ext/chart/chart_bar.js'*/ - - + + + +/* DHX DEPEND FROM FILE 'ext/chart/chart_bar.js'*/ + + /*DHX:Depend ext/chart/chart_base.js*/ dhtmlx.chart.bar = { /** @@ -2099,12 +2099,12 @@ dhtmlx.chart.bar = { // ctx.lineTo(x0,0); //IE fix! return [x5,y3]; } -}; - - -/* DHX DEPEND FROM FILE 'ext/chart/chart_pie.js'*/ - - +}; + + +/* 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){ @@ -2395,12 +2395,12 @@ dhtmlx.chart.pie3D = { pvt_render_pie3D:function(ctx,data,x,y,sIndex,map){ this._renderPie(ctx,data,x,y,this._settings.cant,map); } -} - - -/* DHX DEPEND FROM FILE 'template.js'*/ - - +} + + +/* DHX DEPEND FROM FILE 'template.js'*/ + + /* Template - handles html templates */ @@ -2509,12 +2509,12 @@ dhtmlx.Type={ } } }; - - - -/* DHX DEPEND FROM FILE 'single_render.js'*/ - - + + + +/* DHX DEPEND FROM FILE 'single_render.js'*/ + + /* REnders single item. Can be used for elements without datastore, or with complex custom rendering logic @@ -2544,12 +2544,12 @@ dhtmlx.SingleRender={ if (this.callEvent) this.callEvent("onAfterRender",[]); } } -}; - - -/* DHX DEPEND FROM FILE 'tooltip.js'*/ - - +}; + + +/* DHX DEPEND FROM FILE 'tooltip.js'*/ + + /* UI: Tooltip @@ -2617,12 +2617,12 @@ dhtmlx.ui.Tooltip.prototype = { template_item_start:dhtmlx.Template.empty, template_item_end:dhtmlx.Template.empty }; - - - -/* DHX DEPEND FROM FILE 'autotooltip.js'*/ - - + + + +/* DHX DEPEND FROM FILE 'autotooltip.js'*/ + + /* Behavior: AutoTooltip - links tooltip to data driven item */ @@ -2643,12 +2643,12 @@ dhtmlx.AutoTooltip = { }); return t; } -}; - - -/* DHX DEPEND FROM FILE 'datastore.js'*/ - - +}; + + +/* DHX DEPEND FROM FILE 'datastore.js'*/ + + /*DHX:Depend dhtmlx.js*/ /* @@ -3057,12 +3057,12 @@ dhtmlx.sort = { return method(a,b)*-1; }; } -}; - - -/* DHX DEPEND FROM FILE 'group.js'*/ - - +}; + + +/* DHX DEPEND FROM FILE 'group.js'*/ + + /*DHX:Depend datastore.js*/ /*DHX:Depend dhtmlx.js*/ @@ -3187,12 +3187,12 @@ dhtmlx.Group = { }); return config; } -}; - - -/* DHX DEPEND FROM FILE 'key.js'*/ - - +}; + + +/* DHX DEPEND FROM FILE 'key.js'*/ + + /* Behavior:KeyEvents - hears keyboard */ @@ -3207,12 +3207,12 @@ dhtmlx.KeyEvents = { var code = e.which||e.keyCode; //FIXME better solution is required this.callEvent((this._edit_id?"onEditKeyPress":"onKeyPress"),[code,e.ctrlKey,e.shiftKey,e]); } -}; - - -/* DHX DEPEND FROM FILE 'mouse.js'*/ - - +}; + + +/* DHX DEPEND FROM FILE 'mouse.js'*/ + + /* Behavior:MouseEvents - provides inner evnets for mouse actions */ @@ -3306,12 +3306,12 @@ dhtmlx.MouseEvents={ } return found; //returns true if item was located and event was triggered } -}; - - -/* DHX DEPEND FROM FILE 'config.js'*/ - - +}; + + +/* DHX DEPEND FROM FILE 'config.js'*/ + + /* Behavior:Settings @@ -3431,12 +3431,12 @@ dhtmlx.Settings={ this._obj.className += " "+value; return value; } -}; - - -/* DHX DEPEND FROM FILE 'compatibility.js'*/ - - +}; + + +/* DHX DEPEND FROM FILE 'compatibility.js'*/ + + /* Collection of compatibility hacks */ @@ -3512,12 +3512,12 @@ dhtmlx.compat=function(name, obj){ }; } -})(); - - -/* DHX DEPEND FROM FILE 'compatibility_layout.js'*/ - - +})(); + + +/* DHX DEPEND FROM FILE 'compatibility_layout.js'*/ + + /*DHX:Depend dhtmlx.js*/ /*DHX:Depend compatibility.js*/ @@ -3558,12 +3558,12 @@ dhtmlx.attaches.attachChart = function(conf){ }; dhtmlx.compat.layout = function(){}; - - - -/* DHX DEPEND FROM FILE 'load.js'*/ - - + + + +/* DHX DEPEND FROM FILE 'load.js'*/ + + /* ajax operations @@ -3965,12 +3965,12 @@ dhtmlx.DataDriver.xml={ } }; - - - -/* DHX DEPEND FROM FILE 'compatibility_grid.js'*/ - - + + + +/* DHX DEPEND FROM FILE 'compatibility_grid.js'*/ + + /* Compatibility hack for loading data from the grid. Provides new type of datasource - dhtmlxgrid @@ -4001,12 +4001,12 @@ dhtmlx.DataDriver.dhtmlxgrid={ _from:0 }; } -}; - - -/* DHX DEPEND FROM FILE 'canvas.js'*/ - - +}; + + +/* DHX DEPEND FROM FILE 'canvas.js'*/ + + /*DHX:Depend thirdparty\excanvas*/ /*DHX:Depend dhtmlx.js*/ @@ -4080,12 +4080,12 @@ dhtmlx.Canvas = { //FF breaks, when we are using clear canvas and call clearRect without parameters this.getCanvas().clearRect(0,0,this._canvas.offsetWidth, this._canvas.offsetHeight); } -}; - - -/* DHX INITIAL FILE 'D:\dev\xampp\htdocs\temp\chart\dhtmlxCore/sources//chart.js'*/ - - +}; + + +/* DHX INITIAL FILE 'D:\dev\xampp\htdocs\temp\chart\dhtmlxCore/sources//chart.js'*/ + + /*DHX:Depend chart.css*/ /*DHX:Depend canvas.js*/ /*DHX:Depend load.js*/ @@ -4734,4 +4734,4 @@ dhtmlXChart.prototype={ } }; -dhtmlx.compat("layout"); \ No newline at end of file +dhtmlx.compat("layout"); -- cgit v1.2.3