Вход Регистрация
Файл: templates/backend/default/assets/plugins/jquery-harry-ploter/harry.js
Строк: 1031
<?php
// harry plotter 0.9
// ~L~ nikomomo@gmail.com 2009-2013
// https://github.com/nikopol/Harry-Plotter

/*

//everything in the constructor is optional
//if data are provided, the graph is directly drawn

var h=harry({

    //datas can be provided in these formats :
    
    datas: [v1,v2,v3,...],        //simple dataset values
    datas: {l1:v1,l2:v2,l3:v3,..},//simple dataset labels/values
    datas: [[v1,v2],[w1,w2],...], //multiple dataset values
    datas: {                      //simple dataset with optionaly labels, color and title
        values: [v1,v2,...],      //  excepting values, all keys are
        labels: [l1,l2,...],      //  optionals in this format
        title: "my dataset #1",   //  values can also be an hash {label:value,...}
        color: "#fc0"
    },
    datas: [                      //multiple dataset with label,color and title
        { values:[...],labels:[...],title:"...",color:"..." },
        { values:[...],labels:[...],title:"...",color:"..." }
    ],

    //context

    id: "str",                    //canvas's id, by default "harry"+count++
    container: "str/elem",          //container where create canvas, default=body
    canvas: "str/elem",           //canvas element, default=create it into container
    width: int,                   //canvas's width, default=container.width or 300
    height: int,                  //canvas's height, default=container.height or 150
    
    //rendering

    background: "rgba(0,0,0,0.5)" //background color, default=transparent
    mode: "curve:stack",          //draw mode, can be:
                                  //  pie          cheesecake
                                  //  chart        histogram, side by side
                                  //  chart:stack  stacked histograms
                                  //  chart:vertical  vert. histograms
                                  //  chart:stack:vertical  vert. stacked histograms
                                  //  line         lines (default)
                                  //  line:stack   stacked lines
                                  //  curve        curved lines
                                  //  curve:stack  stacked curved lines
    barspace: int,                //space between bars for mode chart only, default=auto
    linewidth: int,               //line width, default=1
    linejoin: "round",            //line join, can be round|bevel|miter default=miter
    fill: "vertical",             //fill style (only first letter matter), can be:
                                  //  none         without fills
                                  //  solid        uniform fill (default)
                                  //  light        lighten color
                                  //  dark         darken color
                                  //  vertical     vertical gradient fill
                                  //  horizontal   horizontal gradient fill
                                  //  radial       radial gradient fill
    opacity: 0.8,                 //fill opacity, between 0 and 1
    margins:[top,right,bot,left], //margin size (for labels), default=auto
    autoscale: "top+bottom",      //auto round top and/or bottom y scale, default=none
    pointradius: int,             //radius point size in mode line/curve only, default=none
    anim: int,                    //initial animation duration in seconds, default=disabled

    title: {                      //title options
        text: "title",            //  clear enough
        font:'9px "Trebuchet MS"',//  font size & family, default=bold 12px "Sans Serif"
        color: "rgba(4,4,4,0.3)", //  font color, default=rgba(4,4,4,0.3)
        shadow: "x,y,blur,#col",  //  text shadow, default=none
        x: 5,                     //  title position left position
        y: 10,                    //  title position top position
        z: "background"           //  behind or on top of the graph, default=top
    },

    labels: {                     //axis labels options
        font: "9px Trebuchet MS", //  font size & family, important:use px size,
                                  //    default=normal 9px "Sans Serif"
        color: "#a0a0a0",         //  font color, default=a0a0a0
        shadow: "x,y,blur,#col",  //  label text shadow, default=none
        y: [0,50,100],            //  y axis, numbers are %, default=none
        ypos: "left+right",       //  y labels position, default=right
        x: int,                   //  x axis, display 1/int labels, 1=all..., default=none
        marks: int                //  graduation's marks size, default=0
    },

    legends: {                    //set to false to disable legends box, default=auto
        x: int,                   //  left corner position, default=5
        y: int,                   //  top corner position,  default=5
        background: "rgba(180,180,180,0.5)",//background color, default=rgba(255,255,255,0.5)
        border: "#fff",           //  legends border color, default=none
        shadowbox: "x,y,b,#col",  //  legends box shadow, default=none
        border2: "#fff",          //  color box border color, default=none
        color: "#000",            //  text color, default, #666
        shadow: "x,y,blur,#col",  //  legends text shadow, default=none
        font:'9px "Trebuchet MS"' //  font size & family, default=normal 10px "Sans Serif"
        layout: 'h'               //  legends layout h(orizontal) or v(ertical) default=v
    },

    grid: {                       //grid options
        color:"#a0a0a0",          //  grid color, default=#a0a0a0
        linewidth: int            //  grid linewidth default=1
        y: [0,50,100],            //  y axis, numbers are %, default=[0,25,50,75,100]
        x: "left|right|all|int"   //  x axis, int=display 1/n, default="left+right"
    },

    //interaction

    mouseover: {,                 //set to false to disable mouseover, default=enabled
        sort: true,               //  sort values, default=false
        bullet: "rgba(0,0,0,0.5)",//  bullet background color, default=rgba(99,99,99,0.8)
        border: "#fc0",           //  bullet border color, default=none,
        shadowbox: "x,y,b,#col",  //  bullet box shadow, default=none
        font: "9px Trebuchet MS", //  bullet text font, default=normal 9px "Sans Serif"
        color: "#666",            //  bullet text color, default=#fff
        shadow: "x,y,blur,#col",  //  bullet text shadow, default=none
        radius: int,              //  spot radius, default=5
        linewidth: int,           //  spot linewidth, default=linewidth below,0=fill
        circle: "#888888",        //  spot color, default=#888
        border2: "#fff",          //  spot color, default=none
        axis: "xy|x|y",           //  draw spot axis, default=none
        text: "%v",               //  text in the bullet (%v=value %l=label %n=index %t=title)
        text: callback(obj)       //  or text can trigger a callback
                                  //     if it returns a string, it'll be displayed
        header: {                 //  header in the bullet 
            text: "%v",               //  text in the bullet (same var than mouseover.text)
            font: "9px Trebuchet MS", //  bullet header font, default=mouveover.font
            color: "#666",            //  bullet text color, default=mouseover.color
            shadow: "x,y,blur,#col",  //  bullet text shadow, default=none
        }
    }
});

//or (same effect)
var h=plotter({...});


h.clear()             //delete all datasets
 .load(data)          //add a dataset (see contructor)
 .draw();             //draw all datasets
 .draw(mode);         //draw all datasets in a given mode (see constructor)

*/

var
harry=(function(o){
    
"use strict";
    var

//CONSTS ======================================================================

    
COLORS=["#88a4d7","#d685c9","#86d685","#ffc34f","#93c2ea","#f28989","#f9eb8a"],

//TOOLS LIB ===================================================================

    
getRGB=function(color) {
        var 
r;
        if(
color && color.constructor==Array && color.length==3) return color;
        if(
r=/rgb(s*([0-9]{1,3})s*,s*([0-9]{1,3})s*,s*([0-9]{1,3})s*)/.exec(color)) return [parseInt(r[1],10), parseInt(r[2],10), parseInt(r[3],10)];
        if(
r=/rgb(s*([0-9]+(?:.[0-9]+)?)%s*,s*([0-9]+(?:.[0-9]+)?)%s*,s*([0-9]+(?:.[0-9]+)?)%s*)/.exec(color)) return [parseFloat(r[1])*2.55parseFloat(r[2])*2.55parseFloat(r[3])*2.55];
        if(
r=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) return [parseInt(r[1],16), parseInt(r[2],16), parseInt(r[3],16)];
        
if(r=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) return [parseInt(r[1]+r[1],16), parseInt(r[2]+r[2],16), parseInt(r[3]+r[3],16)];
        
return [0,0,0];
    },

    
calcColor=function(color,delta,alpha) {
        var 
rgb=getRGB(color),i;
        if(
typeof delta!="array"delta=[delta,delta,delta];
        for(
i=0;i<3;++irgb[i]=Math.max(Math.min(rgb[i]+delta[i],255),0);
        return (
alpha!=undefined)?
            
"rgba("+rgb.join(',')+","+alpha+")":
            
"rgb("+rgb.join(',')+")";
    },

    
fontPixSize=function(f) {
        var 
p=f.match(/d+px/i);
        if(
p) return parseInt(p,10);
        
p=f.match(/[0-9.]+em/i);
        if(
p) return Math.floor(16.0*parseFloat(p));
        
p=f.match(/d+pt/i);
        if(
p) return Math.floor(1.3333*parseInt(p,10));
        return 
10;
    },

    
scaleUp=function(n) {
        var 
s=Math.floor(n).toString(),
            
d=parseInt(s.substr(0,1),10),
            
m=d*parseFloat("1E"+(s.length-1));
        return 
m==: (d+1)*parseFloat("1E"+(s.length-1));
    },

    
merge=function(a,b) {
        if(
typeof(b)=='object')
            for(var 
k in b)
                
a[k]=b[k];
        return 
a;
    },

    
mouseXY=function(e) {
        
e=e||window.event;
        if(
'offsetX' in e) return {x:e.offsetX,y:e.offsetY};
        var 
o=e.target,p={x:e.pageX,y:e.pageY};
        while(
o.offsetParent){
            
p.x-=o.offsetLeft;
            
p.y-=o.offsetTop;
            
o=o.offsetParent;
        }
        return 
p;
    },

    
buildCanvas=function(o,w,h) {
        var 
c=document.createElement('canvas'),p;
        
c.setAttribute('width',w+'px');
        
c.setAttribute('height',h+'px');
        if(
o) {
            
p=typeof(o)=='string'?document.getElementById(o):o;
            if(!
p) return;
        } else
            
p=document.body;
        
p.appendChild(c);
        return 
c;
    },

    
calcMargins=function(flag,l,mo) {
        var 
m=fontPixSize(l.font);
        if(
flag.pie) {
            
m=l.m*: (mo===false 15);
            return [
m,m,m,m];
        }
        var
        
ll=/l/i.test(l.ypos),
        
lr=/r/i.test(l.ypos),
        
f=Math.floor(m/2),
        
k=l.marks;
        return 
flag.vertical ? [
        
/*top*/    l.&& ll m+: (l.x?m:0),
        
/*right*/  l.1,
        
/*bottom*/ l.&& lr m+: (l.x?m:1),
        
/*left*/   l.4+l.xwidth : (l.y?m:0)
        ] : [
        
/*top*/    l.0,
        
/*right*/  l.&& lr 4+l.ywidth : (l.x?m:1),
        
/*bottom*/ l.3+m+: (l.y?m:1),
        
/*left*/   l.&& ll 4+l.ywidth : (l.x?f:0)
        ];
    },

    
getMode=function(m) {
        return (
m||'line').split(':')[0];
    },

    
getFlag=function(m) {
        var 
o={},l=(m||'line').split(':');
        while(
l.lengtho[l.pop()]=true;
        return 
o;
    },

    
percent=function(v,m) {
        return 
? (Math.round(1000*v/m)/10)+'%' '0%';
    },

    
strf=function(t,v) {
        var 
k,s="";
        if(
t){
            
typeof(t)=="function" t(v) : t;
            if(
v) for(k in vs=s.replace('%'+k,v[k]);
        }
        return 
s;
    },

    
textBox=function(gc,t,v,m,b) {
        var 
n,w;
        if(!
bb={};
        if(!
mm=0;
        
b.lines=strf(t,v).split(/n|\n/);
        
b.lh=fontPixSize(gc.font)+m,
        
b.h=b.lines.length*b.lh,
        
b.w=0;
        for(
n in b.lines) if((w=gc.measureText(b.lines[n]).width+m*2)>b.wb.w=w;
        return 
b;
    },

//PRIVATE VARS ================================================================

    
canvas=o.canvas
        
? (o.canvas.constructor == HTMLCanvasElement o.canvas document.getElementById(o.canvas))
        : 
buildCanvas(o.container,o.width||300,o.height||150),
    
w=canvas.width,
    
h=canvas.height,
    
gc=canvas.getContext("2d"),
    
imgdata,
    
bg=o.background,
    
flag=getFlag(o.mode),
    
mode=getMode(o.mode),
    
fill=(o.fill||"s")[0].toLowerCase().replace(/[^nsvhrdl]/g,"s"),
    
opacity=parseFloat(o.opacity)||1,
    
linewidth=o.linewidth==undefined?1:parseInt(o.linewidth,10),
    
linejoin=o.linejoin||"miter",
    
barspace=o.barspace==undefined?'a':parseInt(o.barspace,10),
    
radiuspoint=parseInt(o.radiuspoint,10)||0,
    
scaletop=o.autoscale && /top/i.test(o.autoscale),
    
scalebot=o.autoscale && /bot/i.test(o.autoscale),
    
labels=merge({
        
color"#a0a0a0",
        
font'normal 9px "Sans Serif"',
        
marks0,
        
xwidth0,
        
ywidth0,
        
ypos'right'
    
},o.labels),
    
mo=o.mouseover===false
        
false
        
merge({
            
radius5,
            
linewidthlinewidth*2,
            
circle"#888",
            
font'normal 10px "Sans Serif"',
            
color"#fff",
            
bullet"rgba(99,99,99,0.8)",
            
axisfalse,
            
text"%v"
        
},o.mouseover),
    
mousepos,
    
overpts=[],
    
overpie={n:false},
    
automargins=o.margins false true,
    
margins=o.margins||[0,0,0,0],
    
grid=merge({
        
color"#a0a0a0",
        
linewidth1,
        
x'lr',
        
y: [0,25,50,75,100]
    },
o.grid),
    
title=o.title
        
merge({
            
font'bold 12px "Sans Serif"',
            
color'rgba(4,4,4,0.5)',
            
z'top'
        
},    o.title)
        : 
false,
    
leg=o.legends===false
        
false
        
merge({
            
color"#666",
            
font'10px "Sans Serif"',
            
layout'v'
        
},o.legends),
    
data=[], dmindmaxdlen=0dsumdrngdinc,
    
rxryrwrhrx2ry2lxlacf=1,

//PRIVATE METHODS =============================================================

    
draw,

    
//setup precalc vars
    
setup=function() {
        var 
i,j,l,d,s;
        
//datasets vars
        
dlen=data.length;
        
dmin=dmax=false;
        
drng=dsum=dinc=0;
        
labels.xwidth=0;
        
gc.font=labels.font;
        if(
dlen) {
            for(
i=0;i<dlen;i++) {
                
d=data[i];
                
dmin=dmin===false?d.min:Math.min(d.min,dmin);
                
dmax=dmax===false?d.max:Math.max(d.max,dmax);
                if(
d.maxlablabels.xwidth=Math.max(labels.xwidth,gc.measureText(d.maxlab).width);
            }
            if(
scaletopdmax=scaleUp(dmax);
            if(
flag.stack) {
                for(
i=0,l=data[0].len;i<l;++i) {
                    
s=0;
                    for(
j=0;j<dlen;++js+=(data[j].val[i]||0);
                    if(
s>dsumdsum=scaletop scaleUp(s) : s;
                }
                
drng=scalebot dsum-dmin dsum;
            } else {
                
dsum=dmax;
                
drng=scalebot dmax-dmin dmax;
            }
            
dinc=scalebot dmin 0;
            
labels.ywidth=gc.measureText(dsum||'0').width;
        }
        
//misc
        
labels.fontpx=fontPixSize(labels.font);
        if(
labels.x=='auto'){
            
labels.x=1;
            
labels.xauto=true;
        }
        if(/
none|false/.test(grid.y)) grid.y=[];
        
//plot zone
        
if(automarginsmargins=calcMargins(flag,labels,mo);
        
rx=margins[3];
        
ry=margins[0];
        
rw=Math.max(w-margins[1]-margins[3],0);
        
rh=Math.max(h-margins[0]-margins[2],0);
        
rx2=rx+rw;
        
ry2=ry+rh;
    },

    
//load a dataset
    
load=function(d) { 
        var 
t,v,k,vals=d.values||d,labs=d.labels||[],l,
        
ds={
            
val:[], lab:[], len:0sum:0avg:0max:0min:0xffffffffffff,
            
tit:d.title || "dataset#"+(data.length+1), maxlab'',
            
col:d.color || COLORS[data.length%COLORS.length]
        };
        for(
k in vals) {
            
v=parseFloat(vals[k]);
            if(
isNaN(v)) v=null;
            
ds.val.push(v);
            
l=labs[k]||k;
            if(
l.length>ds.maxlab.lengthds.maxlab=l;
            
ds.lab.push(l);
            
ds.sum+=v;
            if(
v>ds.maxds.max=v;
            if(
&& v<ds.minds.min=v;
        }
        
ds.len=ds.val.length;
        
ds.avg=ds.len ds.sum/ds.len 0;
        
data.push(ds);
    },

    
//load datasets
    
loads=function(datas) {
        if(
datas instanceof Array && typeof(datas[0])=='object')
            for(var 
i=0,l=datas.length;i<l;++i)
                
load(datas[i]);
        else
            
load(datas);
        
setup();
    },

    
//set and return a fillstyle
    
setGradient=function(c) {
        var 
g;
        switch(
fill) {
        case 
"s"//solid
            
g=calcColor(c,0,opacity);
            break;
        case 
"l"//light
            
g=calcColor(c,0x15,opacity);
            break;
        case 
"d"//dark
            
g=calcColor(c,-0x15,opacity);
            break;
        case 
"v"//vertical
            
g=gc.createLinearGradient(0,ry2,0,ry);
            
g.addColorStop(0,calcColor(c,-0x30,opacity));
            
g.addColorStop(1,calcColor(c,0x30,opacity));
            break;
        case 
"h"//horizontal
            
g=gc.createLinearGradient(rx,0,rx2,0);
            
g.addColorStop(0,calcColor(c,-0x30,opacity));
            
g.addColorStop(1,calcColor(c,0x30,opacity));
            break;
        case 
"r"//radial
            
var cx=rx+rw/2,cy=ry+rh/2;
            
g=gc.createRadialGradient(cx,cy,0,cx,cy,rh/2);
            
g.addColorStop(0,calcColor(c,-0x30,opacity));
            
g.addColorStop(1,calcColor(c,0x30,opacity));
            break;
        }
        return 
gc.fillStyle=false;
    },

    
stroke=function(s){
        if(
linewidth) {
            
gc.lineWidth=linewidth;
            
gc.lineJoin=linejoin;
            
gc.strokeStyle=s;
            
gc.stroke();
        }
    },
    
    
fillstroke=function(s){
        
gc.closePath();
        
setGradient(s) && gc.fill();
        
stroke(s);
    },

    
//set shadow
    
setShadow=function(s) {
        if(
&& gc.hasOwnProperty('shadowBlur')) {
            var 
p=s.split(/[ ,;:-]/);
            
gc.shadowOffsetX parseInt(p[0]||1,10);
            
gc.shadowOffsetY parseInt(p[1]||1,10);
            
gc.shadowBlur    parseInt(p[2]||1,10);
            
gc.shadowColor   p[3]||'#000';
        }
    },

    
//unset shadow
    
unsetShadow=function() {
        if(
gc.hasOwnProperty('clearShadow')) gc.clearShadow();
        else if(
gc.hasOwnProperty('shadowBlur')) {
            
gc.shadowOffsetX 0;
            
gc.shadowOffsetY 0;
            
gc.shadowBlur    0;
        }
    },

    
//erase canvas
    
cls=function() {
        
gc.clearRect(-1,-1,w+1,h+1);
        if(
bg) {
            
gc.fillStyle=bg;
            
gc.fillRect(-1,-1,w+1,h+1);
        }
    },

    
drawTitle=function() {
        if(
title) {
            
setShadow(title.shadow);
            
gc.font=title.font;
            
gc.textAlign='left';
            
gc.textBaseline='top';
            
gc.fillStyle=title.color;
            
gc.fillText(
                
title.text,
                
title.x==undefined?margins[3]+2:title.x,
                
title.y==undefined?margins[0]+2:title.y
            
);
            
unsetShadow();
        }
    },
    
    
//draw the background grid Y axis
    
drawYGrid=function() {
        if(!
flag.pie && grid.y) {
            var 
i,l,x,y;
            
gc.lineWidth=grid.linewidth;
            
gc.strokeStyle=grid.color;
            
//console.log("[harry] grid x("+grid.x+") y("+grid.y.join(",")+")"); 
            
for(i=0,l=grid.y.length;i<l;++i) {
                
gc.beginPath();
                if(
flag.vertical) {
                    
x=rx+Math.round(rw*grid.y[i]/100);
                    
gc.moveTo(x,ry);
                    
gc.lineTo(x,ry2);
                } else {
                    
y=ry2-Math.round(rh*grid.y[i]/100);
                    
gc.moveTo(rx,y);
                    
gc.lineTo(rx2,y);
                }
                
gc.stroke();
            }
        }
    },

    
//draw the background grid on X axis
    
drawXGrid=function(x) {
        var 
i,y,
        
l=x.length,
        
gx=grid.x,
        
ga=/a/i.test(gx),
        
gl=/l/i.test(gx),
        
gr=/r/i.test(gx),
        
n=parseInt(gx,10);
        if(
gx) {
            
gc.lineWidth=grid.linewidth;
            
gc.strokeStyle=grid.color;
            for(
i=0;gx && i<l;++i
                if(
ga || (&& i%n==0) || (i==&& gl) || (i==l-&& gr)) {
                    
gc.beginPath();
                    if(
flag.vertical) {
                        
gc.moveTo(rx,x[i]);
                        
gc.lineTo(rx2,x[i]);
                    } else {
                        
gc.moveTo(x[i],ry);
                        
gc.lineTo(x[i],ry2);
                    }
                    
gc.stroke();
                }
        }
    },

    
//draw labels on Y axis
    
drawYLabels=function() {
        if(
dlen && labels.y) {
            
//console.log("[harry] labels y("+labels.y.join(",")+") "+labels.font);
            
if(!flag.pie) {
                var 
i,l,x,y,w,v,dec=drng<10?100:(drng<100?10:1);
                
setShadow(labels.shadow);
                
gc.font=labels.font;
                
gc.fillStyle=labels.color;
                if(
flag.vertical) {
                    
gc.textAlign='center';
                    for(
i=0,l=labels.y.length;i<l;++i) {
                        
x=rx+Math.round(rw*labels.y[i]/100);
                        
v=dinc+drng*labels.y[i]/100;
                        
v=Math.round(dec*v)/dec;
                        if(/
r/i.test(labels.ypos)) {
                            
y=ry2+1;
                            
gc.textBaseline='top';
                            
gc.fillText(v,x,y);
                        }
                        if(/
l/i.test(labels.ypos)) {
                            
y=ry-2;
                            
gc.textBaseline='bottom';
                            
gc.fillText(v,x,y);
                        }
                    }
                } else {
                    
gc.textBaseline='middle';
                    for(
i=0,l=labels.y.length;i<l;++i) {
                        
y=ry2-Math.round(rh*labels.y[i]/100);
                        
v=dinc+drng*labels.y[i]/100;
                        
v=Math.round(dec*v)/dec;
                        if(/
r/i.test(labels.ypos)){
                            
x=rx2+1;
                            
gc.textAlign='left';
                            
gc.fillText(v,x,y);
                        }
                        if(/
l/i.test(labels.ypos)) {
                            
x=rx-2;
                            
gc.textAlign='right';
                            
gc.fillText(v,x,y);
                        }
                    }
                }
                
unsetShadow();
            }
        }
    },

    
//draw labels on X axis
    
drawXLabel=function(n,x,y,ta,tb,chk) {
        
gc.save();
        
x=Math.round(x);
        
y=Math.round(y);
        if(
labels.&& (n%labels.x)==0) {
            var
            
ok=true,
            
l=data[0].lab[n]||n,
            
w=0;
            
gc.font=labels.font;
            if(
labels.xauto && chk) {
                
w=gc.measureText(l).width;
                
ok=!((chk=='h' && ta=='center' && x-w/2<lxl) || (chk=='v' && y<lxl));
            }
            if(
ok) {
                
setShadow(labels.shadow);
                
gc.fillStyle=labels.color;
                
gc.textAlign=ta;
                
gc.textBaseline=tb;
                
gc.fillText(l,x,y);
                
unsetShadow();
                
lxl=ta=='center'?x+w/2:y+labels.fontpx;
            }
        }
        if(
labels.marks) {
            
gc.lineWidth=1;
            
gc.beginPath();
            
gc.moveTo(x,ry2);
            
gc.lineTo(x,ry2+labels.marks);
            
gc.strokeStyle=labels.color;
            
gc.stroke();
        }
        
gc.restore();
    },

    
drawLegends=function() {
        if(
leg!==false && dlen>1) {
            
gc.save();
            
gc.font=leg.font;
            var 
i,w,g,px,py,d,lw=[],
                
hor=leg.layout=='h',
                
mw=0,
                
tw=0,
                
s=3,
                
lh=fontPixSize(leg.font)+s,
                
nl=dlen,
                
bs=lh-s,
                
tx=s*2+bs,
                
h=hor?s+lh:s+lh*nl,
                
x=leg.x!=undefined?leg.x:margins[3]+2,
                
y=leg.y!=undefined?leg.y:margins[0]+2+(title && !title.x?2+fontPixSize(title.font):0);
            for(
i=0;i<nl;++i) {
                
w=gc.measureText(data[i].tit).width;
                if(
w>mwmw=w;
                
lw.push(w);
                
tw+=w;
            }
            
w=hor?(tx+s*2)*nl+tw:s*3+bs+mw;
            
//draw background
            
gc.lineWidth=1;
            if((
g=leg.background)) {
                
setShadow(leg.shadowbox);
                
gc.fillStyle=g;
                
gc.fillRect(x,y,w,h);
                
unsetShadow();
            }
            if((
g=leg.border)) {
                
gc.strokeStyle=g;
                
gc.strokeRect(x,y,w,h);
            }
            for(
i=0,py=y+s,px=x+s;i<nl;++i) {
                
d=data[i];
                
//draw color box
                
setShadow(leg.shadow);
                
gc.fillStyle=d.col;
                
gc.fillRect(px,py,bs,bs);
                
unsetShadow();
                if((
g=leg.border2)) {
                    
gc.strokeStyle=g;
                    
gc.strokeRect(px,py,bs,bs);
                }
                
//draw text
                
setShadow(leg.shadow);
                
gc.textAlign='left';
                
gc.textBaseline='top';
                
gc.fillStyle=leg.color;
                
gc.fillText(d.tit,px+s+bs,py);
                
unsetShadow();
                if(
horpx+=s*4+bs+lw[i]; else py+=lh;
            }
            
gc.restore();
        }
    },

    
drawBullets=function(bs,center) { //[{x,y,r,v,n,nds}]
        
gc.save();
        
gc.font=mo.font;
        var 
i,n,m,l=bs.length,b,txt,bh=0,bw=0,s=3,
            
pt=fontPixSize(mo.font),
            
pr=Math.floor(pt/2),lh=pt+s,x,y,x1,y1,x2,y2,
            
xl=w,xr=0,yt=h,yb=0,mx=0,v,head;
        if(
mo.sortbs.sort(function(a,b){return parseFloat(b.v)-parseFloat(a.v)});
        
//calc max for pct if needed
        
for(n=0;n<l;n++) mx+=bs[n].v;
        
//calc texts sizes
        
for(n=0;n<l;n++){
            
b=bs[n];
            
v={
                
vb.v,
                
ldata[b.nds].lab[b.n],
                
nb.n,
                
tdata[b.nds].tit,
                
pb.pct||percent(b.v,mx)
            };
            
b=textBox(gc,mo.text,v,s,b);
            if(
b.w) {
                
b.h2=Math.floor(b.h/2);
                if(
b.w>bwbw=b.w;
                
bh+=b.h;
                
b.r++;
                if(
xl>b.x-b.rxl=b.x-b.r;
                if(
xr<b.x+b.rxr=b.x+b.r;
                if(
yt>b.yyt=b.y;
                if(
yb<b.yyb=b.y;
            }
        }
        if(
l>1bw+=s*2+pt;
        if(
bh) {
            if(
mo.header) {
                if(
mo.header.fontgc.font=mo.header.font;
                
head=textBox(gc,mo.header.text,v,s);
                if(
head.w>bwbw=head.w;
                
bh+=head.h;
            }
            
bh+=s;
            
//calc position
            
if(center) {
                
x=xl+(xr-xl)/2;
                
x1=x-(bw/2);
                if(
x1+bw>wx1=w-1-bw;
                if(
x1<1x1=1;
            } else {
                
x1=xr;
                if(
x1+bw>=wx1=xl-bw;
                if(
x1<1x1=1;
            }
            
x1=Math.floor(x1);
            
x2=x1+bw;
            
y=yt+bh/2;
            
y1=y+(bh/2);
            if(
y1>ry2y1=ry2-1;
            
y1=Math.floor(y1);
            
y2=y1-bh;
            
//draw bullet
            
gc.beginPath();
            
gc.moveTo(x1,y1);
            
gc.lineTo(x2,y1);
            
gc.lineTo(x2,y2);
            
gc.lineTo(x1,y2);
            
gc.closePath();
            if(
mo.bullet) {
                
setShadow(mo.shadowbox);
                
gc.strokStyle='';
                
gc.fillStyle=mo.bullet;
                
gc.fill();
                
unsetShadow();
            }
            if(
mo.border) {
                
gc.lineWidth=1;
                
gc.lineJoin='round';
                
gc.strokeStyle=mo.border;
                
gc.stroke();
            }
            
//draw texts
            
gc.textAlign='left';
            
gc.textBaseline='top';
            
y=y2+s;
            if(
head) {
                
x=x1+s;
                
setShadow(mo.header.shadow);
                
gc.fillStyle=mo.header.color||mo.color;
                for(
i=0;i<head.lines.length;++i,y+=head.lh)
                    
gc.fillText(head.lines[i],x,y);
                
unsetShadow();
                
gc.font=mo.font;
            }
            for(
n=0;n<l;n++) {
                
b=bs[n];
                
x=x1+s;
                if(
l>1) {
                    
gc.beginPath();
                    
gc.arc(x+pr,y+pr,pr,0,2*Math.PI);
                    
gc.fillStyle=data[b.nds].col;
                    
gc.fill();
                    
x+=pt+s;
                }
                
setShadow(mo.shadow);
                
gc.fillStyle=mo.color;
                for(
i=0;i<b.lines.length;++i,y+=lh)
                    
gc.fillText(b.lines[i],x,y);
                
unsetShadow();
            }
        }
        
gc.restore();
    },

    
plot={

        
line: function() {
            var 
nds=dlen,cy=drng?rh/drng:0,d,g,i,j,v,l,cu=mode=="curve",ly=ry2+labels.marks+2,
            
drawPath=function(gc,x,y,v,n1,n2) {
                var 
n=n1,nx,ny,mx,my,px,py;
                while(
n<=n2) {
                    if(
v[n]===null)
                        
n++;
                    else if(
cu) {
                        
nx=x[n];
                        
ny=y[n];
                        
n++;
                        while(
n<=n2 && v[n]===nulln++;
                        if(
n>n2)
                            
gc.lineTo(nx,ny);
                        else {
                            
mx=(nx+x[n])/2;
                            
my=(ny+y[n])/2;
                            
px=(nx+mx)/2;
                            
py=(ny+my)/2;
                            
gc.quadraticCurveTo(nx,ny,px,py);
                            
px=(mx+x[n])/2;
                            
py=(my+y[n])/2;
                            
gc.quadraticCurveTo(mx,my,px,py);
                        }
                    } else {
                        
gc.lineTo(x[n],y[n]);
                        
n++;
                    }
                }
            };
            
overpts=[];
            while(
d=data[--nds])
                if((
l=d.len)>1) {
                    
//calc
                    
var x=[],y=[],n1,n2;
                    for(
i=0;i<l;++i) {
                        
v=0;
                        if(
flag.stack) for(j=0;j<=nds;j++) v+=data[j].val[i]-dinc;
                        else 
v=d.val[i]-dinc;
                        
x.push(rx+Math.round(i*(rw/(l-1))));
                        
y.push(ry2-Math.round(cy*v*acf));
                    }
                    if(
nds+1==dlendrawXGrid(x);
                    
overpts.push({x:x,y:y,v:data[nds].val,nds:nds});
                    
i--;
                    
x.push(rx+Math.round(i*(rw/(l-1))));
                    
y.push(ry2-Math.round(cy*v));
                    
//dont draw leading/ending null values
                    
n1=0;
                    while(
d.val[n1]===nulln1++;
                    
n2=l-1;
                    while(
d.val[n2]===nulln2--;
                    
//fill
                    
if(n1<=n2 && setGradient(d.col)) {
                        
gc.beginPath();
                        
gc.moveTo(x[n1],ry2);
                        
gc.lineTo(x[n1],y[n1]);
                        
drawPath(gc,x,y,d.val,n1,n2);
                        
gc.lineTo(x[n2],ry2);
                        
gc.closePath();
                        
gc.fill();
                    }
                    
//draw lines
                    
gc.beginPath();
                    
gc.moveTo(x[n1],y[n1]);
                    
drawPath(gc,x,y,d.val,n1,n2);
                    
stroke(d.col);
                    
//draw x labels
                    
if(nds==0)
                        for(
i=0;i<l;++i)
                            
drawXLabel(i,x[i],ly,'center','top','h');
                    
//draw points
                    
if(radiuspoint) {
                        
gc.fillStyle=d.col;
                        for(
i=0;i<l;++i)
                            if(
d.val[i]!=undefined){
                                
gc.beginPath();
                                
gc.arc(x[i],y[i],radiuspoint,0,2*Math.PI);
                                
gc.closePath();
                                
gc.fill();
                            }
                    }
                }
        },

        
curve: function(){ plot.line() },

        
chart: function() {
            
//console.log("[harry] chart ("+dlen+" dataset)");
            
overpts = [];
            if(
dlen){
                var 
nd,nds,nbd=data[0].len,m=barspace=='a'?(dlen>1?4:0):barspace,
                    
fs=flag.stack,fv=flag.vertical,nbdsv=fs?1:dlen,tbw=fv?rh:rw,
                    
bw=(nbd && dlen)?(((tbw-(m*(nbd-1)))/nbd)/nbdsv)-1:0,
                    
d,g,y,y1,y2,x,x1,x2,tcf=fv?rw:rh,ly=ry2+labels.marks+2,gx=[],
                    
cf=fs?(dsum?tcf/dsum:0):(dmax?tcf/dmax:0);
                if(
bw<0bw=0;
                for(
y=fv?ry:rx,g=(fv?rh:rw)/(nbd||1),nd=0;nd<=nbd;nd++) gx.push(Math.round(y+nd*g));
                
drawXGrid(gx);
                for(
nds=0;nds<dlen;nds++) overpts.push({x:[],y:[],v:[],nds:nds});
                if(
fv)
                    for(
y=ry,nd=0;nd<nbd;nd++) {
                        
drawXLabel(nd,rx-labels.marks-2,y,'right','top','v');
                        
x=rx;
                        for(
nds=0;nds<dlen;nds++) {
                            
d=data[nds];
                            
x1=fs?x:rx;
                            
x=x1+Math.round(cf*d.val[nd]*acf);
                            
y1=Math.round(y);
                            
y2=Math.round(y+bw);
                            if(
d.val[nd]!==null) {
                                
gc.beginPath();
                                
gc.moveTo(x1,y1);
                                
gc.lineTo(x1,y2);
                                
gc.lineTo(x,y2);
                                
gc.lineTo(x,y1);
                                
fillstroke(d.col);
                            }
                            
overpts[nds].x.push(x);
                            
overpts[nds].y.push(Math.floor(y+bw/2));
                            
overpts[nds].v.push(d.val[nd]);
                            if(!
fsy+=bw+1;
                        }
                        
y+=fs?bw+1+m:m;
                    }
                else
                    for(
x=rx,nd=0;nd<nbd;nd++) {
                        
drawXLabel(nd,x+(((bw+1)*nbdsv)/2),ly,'center','top','h');
                        
y=ry2;
                        for(
nds=0;nds<dlen;nds++) {
                            
d=data[nds];
                            
y1=fs?y:ry2;
                            
y=y1-Math.round(cf*d.val[nd]*acf);
                            
x1=Math.round(x);
                            
x2=Math.round(x+bw);
                            if(
d.val[nd]!==null) {
                                
gc.beginPath();
                                
gc.moveTo(x1,y1);
                                
gc.lineTo(x1,y);
                                
gc.lineTo(x2,y);
                                
gc.lineTo(x2,y1);
                                
fillstroke(d.col);
                            }
                            
overpts[nds].x.push(Math.floor(x+bw/2));
                            
overpts[nds].y.push(y);
                            
overpts[nds].v.push(d.val[nd]);
                            if(!
fsx+=bw+1;
                        }
                        
x+=fs?bw+1+m:m;
                    }                    
            }
        },

        
pie: function() {
            
//console.log("[harry] pie ("+dlen+" dataset)");
            
overpts = [];
            if(
dlen){
                
//precalc angles
                
var i,nb=0,va=[],vc=[],pi2=Math.PI*2,lab=[],pct=[];
                if(
dlen>1) {
                    var 
sum=0;
                    for(
i=0;i<dlen;i++) sum+=data[i].sum;
                    if(
sum)
                        for(
i=0,nb=dlen;i<dlen;i++) {
                            
va[i]=acf*data[i].sum/sum*pi2;
                            
vc[i]=data[i].col;
                            
lab.push(data[i].sum);
                            
pct.push(percent(data[i].sum,sum));
                        }
                } else {
                    var 
d=data[0];
                    if(
d.sum)
                        for(
nb=d.len,i=0;i<nb;i++) {
                            
va[i]=acf*d.val[i]/d.sum*pi2;
                            
vc[i]=COLORS[i%COLORS.length];
                            
lab.push(d.val[i]);
                            
pct.push(percent(d.val[i],d.sum));
                        }
                }
                
//draw
                
var cx=rx+Math.round(rw/2),cy=ry+Math.round(rh/2),
                    
r=Math.min(rh/2,rw/2)-1rl=r+labels.fontpx,dx,dy,
                    
g,a1=Math.PI*1.5,a2,a,nx,ny,n=overpie.n;
                
overpie={r:r,x:cx,y:cy,n:n};
                for(
i=0;i<nb;i++) {
                    
a2=a1+va[i];
                    
a=(a1+a2)/2;
                    
overpts.push({a:a1%(2*Math.PI),n:i});
                    if(
i===n) {
                        
dx=cx+Math.cos(a)*10;
                        
dy=cy+Math.sin(a)*10;
                    } else {
                        
dx=cx;
                        
dy=cy;
                    }
                    
gc.beginPath();
                    
gc.moveTo(dx,dy);
                    
gc.arc(dx,dy,r,a1,a2,false);
                    
fillstroke(vc[i]);
                    if(
i===n) {
                        
nx=dx+rl/2*Math.cos(a);
                        
ny=dy+rl/2*Math.sin(a);
                    } else
                        
drawXLabel(lab[i],dx+rl*Math.cos(a),dy+rl*Math.sin(a),'center','middle');
                    
a1=a2;
                }
                if(
n!==falsedrawBullets([{
                    
xnx,
                    
yny,
                    
r0,
                    
vlab[n],
                    
pctpct[n],
                    
nn,
                    
ndsdlen>1?n:0
                
}], true);
                
overpts.sort(function(a,b){return a.a-b.a});
            }
        }
    },

    
over={

        
line: function(x,y) {
            var 
i,j,nb,n=false,p,m,c,lw=mo.linewidth||1,bs=[];
            if(
overpts.length) {
                for(
i=0;i<overpts[0].x.length;++i) {
                    for(
j=0;j<overpts.length;++j) {
                        
p=overpts[j];
                        if(
p.v[i]!=undefined) {
                            
c=flag.vertical Math.abs(y-p.y[i]) : Math.abs(x-p.x[i]);
                            if(
n===false || c<m) {
                                
m=c;
                                
n=i;
                            }
                            break;
                        }
                    }
                }
                if(
n!==false) {
                    for(
i=0;i<overpts.length;++i) {
                        
p=overpts[i];
                        if(
p.v[n]!=undefined) {
                            if(
mo.border2) {
                                
gc.beginPath();
                                
gc.lineWidth=lw+2;
                                
gc.arc(p.x[n],p.y[n],mo.radius,0,2*Math.PI);
                                if(
mo.linewidth==0) {
                                    
gc.fillStyle=mo.border2;
                                    
gc.fill();
                                } else {
                                    
gc.strokeStyle=mo.border2;
                                    
gc.stroke();
                                }
                            }
                            
gc.beginPath();
                            
gc.lineWidth=lw;
                            
gc.arc(p.x[n],p.y[n],mo.radius,0,2*Math.PI);
                            if(
mo.linewidth==0) {
                                
gc.fillStyle=mo.circle;
                                
gc.fill();
                            } else {
                                
gc.strokeStyle=mo.circle;
                                
gc.stroke();
                            }
                            if(
mo.axis){
                                var 
xy,z,s=2;
                                
gc.lineWidth=1;
                                
//draw axis
                                
if(/x/i.test(mo.axis)){
                                    
z=p.y[n]+mo.radius;
                                    while(
z<ry2){
                                        
gc.moveTo(p.x[n],z);
                                        
z+=s;
                                        if(
z>ry2z=ry2;
                                        
gc.lineTo(p.x[n],z);
                                        
z+=s;
                                    }
                                    
gc.stroke();
                                }
                                if(/
y/i.test(mo.axis)){
                                    
x=p.x[n]+mo.radius;
                                    while(
x<rx2){
                                        
gc.moveTo(x,p.y[n]);
                                        
x+=s;
                                        if(
x>rx2x=rx2;
                                        
gc.lineTo(x,p.y[n]);
                                        
x+=s;
                                    }
                                    
gc.stroke();
                                }
                            }
                            
bs.push({
                                
xp.x[n],
                                
yp.y[n],
                                
rlw/2+1+mo.radius,
                                
vp.v[n],
                                
nn,
                                
ndsp.nds
                            
})
                        }
                    }
                    
drawBullets(bs);
                }
            }
        },

        
chart: function(x,y){ over.line(x,y) },
        
curve: function(x,y){ over.line(x,y) },

        
pie: function(x,y) {
            var 
d=Math.sqrt(Math.pow(x-overpie.x,2)+Math.pow(y-overpie.y,2)),a,n,i=0;
            if(
d<=overpie.r){
                
a=Math.PI-Math.atan2(overpie.y-y,x-overpie.x);
                
a=(a+3*Math.PI)%(2*Math.PI);
                while(
i<overpts.length && a>overpts[i].ai++;
                if(--
i<0i=overpts.length-1;
                
overpie.n=overpts[i].n;
                
draw(true);
            } else if(
overpie.n!==false) {
                
overpie.n=false;
                
draw(true);
            }
        }

    },

    
clear=function() {
        
data=[];
        
dlen=0;
        
setup();
    },

    
draw=function(nover) {
        
//console.log("[harry] draw "+mode+" "+keys(flag).join(" "));
        
lxl=-1;
        
cls();
        
drawYGrid();
        
drawYLabels();
        if(
title && title.z=='top') {
            
plot[mode]();
            
drawTitle();
        } else {
            
drawTitle();
            
plot[mode]();
        }
        
drawLegends();
        if(!
nover) {
            
canvas.onmouseover=
            
canvas.onmousemove=
            
canvas.onmouseout=undefined;
            
overpie.n=false;
            if(
mo) {
                
imgdata gc.getImageData(0,0,w,h);
                if(
mouseposover[mode](mousepos.x,mousepos.y);
                
canvas.onmouseover=function(e){
                    
mousepos=mouseXY(e);
                };
                
canvas.onmousemove=function(e){
                    if(
mousepos) {
                        if(!
flag.piegc.putImageData(imgdata,0,0);
                        
mousepos=mouseXY(e);
                        
over[mode](mousepos.x,mousepos.y);
                    };
                };
                
canvas.onmouseout=function(){
                    
mousepos=undefined;
                    
gc.putImageData(imgdata,0,0);
                };
            } else
                
mousepos=undefined;
        }
    },

    
anim=function(s){
        var 
i=100/6,icf=1/(s*i),cb;
        
cb=function(){
            
draw();
            if(
acf<1) {
                
acf+=icf;
                if(
acf>=1acf=1;
                
setTimeout(cb,i);
            }
        };
        
acf=0;
        
cb();
    };
    
//INIT ========================================================================

    //console.log("[harry] init("+w+","+h+")");
    
gc.translate(0.5,0.5);
    if(
o.datasloads(o.datas);
    else 
setup();
    if(
o.animanim(o.anim);
    else 
draw();

//PUBLIC METHODS ==============================================================

    
return {
        
canvascanvas,
        
datadata,
        
clear: function() {
            
clear();
            return 
this;
        },
        
load: function(d) {
            
loads(d);
            return 
this;
        },
        
cls: function(){
            
//console.log("harry.cls() is obsolete, cls is performed by draw()");
            
return this;
        },
        
draw: function(m) {
            if(
m) {
                
mode=getMode(m);
                
flag=getFlag(m);
                
setup();
            }
            
draw();
            return 
this;
        }
    };
}),
plotter=harry;
?>
Онлайн: 0
Реклама