tslediter/funcext/tvclib/utvclgraphicsext.tsf

2160 lines
77 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

unit utvclgraphicsext;
interface
uses utslvclauxiliary,utvclgraphics;//,utslvclconstant;
{
//玫瑰图
uses tslvcl,utvclgraphics,utvclgraphicsext;
app := initializeapplication();
app.createform(class(tfm),fm);
fm.show();
app.run();
type tfm=class(tvcform)
function create(aowner);
begin
inherited;
caption := "玫瑰图";
width := 800;
Height := 800;
fg := new tg_WinControl(self);
fg.parent := self;
fg.Align := alClient;
//////////设置坐标轴属性////////////////////////
axs := new tg_axes();
axs.figure := fg.figure;
axs.title.text := "玫瑰图";
args := array(('name':'a','value':300)
,('name':'b','value':200)
,('name':'c','value':500)
,('name':'d','value':700)
,('name':'e','value':300)
,('name':'f','value':200)
,('name':'g','value':500)
,('name':'h','value':700)
,('name':'i','value':300)
,('name':'j','value':200)
,('name':'k','value':500)
,('name':'l','value':700)
);
line := new tg_Polypie();
line.graph_data := args;
line.pie_type := "rose"; //'ring';
line.parent := axs;
//绘制图例
lg := new tg_legend();
lg.parent := axs;
//lg.location := lg.tgc_by_axes;
lg.postion := array(-0.11,0.7);
//lg.text := array("aaa","bbb",'ccc','ddd');
lg.links := array(line);
//构造提示标签
fmovetip := new tg_tips();
fmovetip.parent := line;
fmovetip.box_mode := true; //false;
fmovetip.display_function := function(o,ps,d)
begin
p := o.parent;
if not fshowpos then return;
if p then
begin
dd := p.get_graph_data_by_idx(o.data_idx);
p.xyz_to_zoom(fshowpos[0],fshowpos[1],nil,x1,y1);
ps := array(x1,y1);
d := array(dd["name"],tostn(dd["value"]));
end
end
//设置提示数据点
line.onhit_at := function(o,d)
begin
x := d["cvsx"];
y := d["cvsy"];
r := o.ExecuteCommand("hit_part",array(x,y));
r := r >= 0;
return r;
end
line.addEventListener("mouse_in", function(e)
begin
if e.eventPhase <> 2 then return;
e.stoppropagation();
end
,true);
line.addEventListener("mouse_out", function(e)
begin
if e.eventPhase <> 2 then return;
fmovetip.Visible := false;
e.stoppropagation();
end
,true);
line.addEventListener("mouse_move", function(e)
begin
if e.eventPhase <> 2 then return;
e.stoppropagation();
x := e.cvsx;
y := e.cvsy;
idx := e.target.ExecuteCommand("hit_part",array(x,y));
if idx >= 0 then
begin
fmovetip.data_idx := idx;
fshowpos := array(x,y);
fmovetip.Visible := true;
end
end
,true);
end
fmovetip;
fg;
fshowpos;
end
//雷达图
uses tslvcl,utvclgraphics,utvclgraphicsext;
app := initializeapplication();
app.createform(class(tfm),fm);
fm.show();
app.run();
type tfm = class(tvcform)
function create(aowner);
begin
inherited;
caption := "雷达图";
width := 800;
Height := 800;
fg := new tg_WinControl(self);
fg.parent := self;
fg.Align := alClient;
//////////设置坐标轴属性////////////////////////
axs := new tg_axes();
axs.box := true;
axs.figure := fg.figure;
axs.title.text := "雷达图";
line := new tg_Polyradar();
indicator := array(
('name':'射击','max':300),
('name':'游泳','max':200),
('name':'篮球','max':500),
('name':'足球','max':700),
('name':'跑步','max':300),
('name':'举重','max':200)
);
indicator := array(
('name':'射击','max':110),
('name':'游泳','max':110),
('name':'篮球','max':110),
('name':'足球','max':110),
('name':'跑步','max':110),
('name':'举重','max':110)
);
args := array(
('name':'一班','value':array(90, 80, 85, 85, 95, 95)),
('name':'二班','value':array(85, 65, 65, 90, 100, 70)),
('name':'三班','value':array(70, 60, 99, 50, 90, 80))
);
line.graph_data := args;
line.indicator := indicator;
line.parent := axs;
lg := new tg_legend();
lg.parent := axs;
lg.postion := array(-0.11,0.7);
lg.links := array(line);
end
fg;
end
//树图
uses tslvcl,utvclgraphics,utvclgraphicsext;
app := initializeapplication();
app.createform(class(tfm),fm);
fm.show();
app.run();
type tfm = class(tvcform)
function create(aowner);
begin
inherited;
Caption := "树图";
fg := new tg_WinControl(self);
fg.Caption := "树图";
fg.parent := self;
fg.Align := alClient;
//////////设置坐标轴属性////////////////////////
axs := new tg_axes();
axs.figure := fg.figure;
axs.title.text := "树图";
//设置线型属性
line := new tg_Polytree();
line.parent := axs;
line.lineinfo.color := 0x0000ff;
line.markinfo.bkcolor := 0x00ff00;
line.markinfo.color := 0x0000ff;
line.mark_mode := true;
line.markinfo.size := 5;
line.show_text := true;//展示节点文本
d := array();
idx := 0;
line.graph_data := array('name':'111','show': true,'children':(
('name':'222','children':(('name':'333','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':())))
)
))))),
('name':'555','children':(('name':'666','show': false,'children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':())))
)
))))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':())))
)
)))))
)
))),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':())))
)
))))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':())))
)
)))))
)
))),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':())))
)
))),('name':'444','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':())))
)
))))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':())))
)
))))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':())))
)
))))),
('name':'888','children':(('name':'999','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':())))
)
)))))
)
)))))
)
))),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':())))
)
)))))
)
)))))
)
))),('name':'xxx','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':(('name':'111','children':(
('name':'222','children':(('name':'333','children':()),('name':'444','children':()))),
('name':'555','children':(('name':'666','children':()),('name':'777','children':()))),
('name':'888','children':(('name':'999','children':()),('name':'xxx','children':()),('name':'zzz','children':())))
)
)))))
)
)))))
)
)))))
)
))),('name':'zzz','children':(('name':'777','children':())))))
)
);
end
fg;
end
//k线图
uses tslvcl,utvclgraphics,utvclgraphicsext;
app := initializeapplication();
app.createform(class(tfm),fm);
fm.show();
app.run();
type tfm = class(tvcform)
function create(aowner);
begin
inherited;
Caption := "k线图";
fg := new tg_WinControl(self);
fg.parent := self;
fg.Align := alClient;
//////////设置坐标轴属性////////////////////////
axs := new tg_axes();
axs.figure := fg.figure;
axs.title.text := "k线图 ";
axs.title.fontinfo.size := 15;
axs.title.fontinfo.color := 0xff0000;
axs.x_label.text := "日期";
axs.grid(0).Width := 2;
axs.grid(0).color := 0x0ff0f0;
axs.auto_ticks(0) := false;
//设置线型属性
line := new tg_Polycandlestick();
line.lineinfo.color := 0xff0000;
line.bullcolor := 0x0000ff;
line.bearcolor := 0x00ff00;
line.line_mode := false;
line.graph_data := array(("2017-10-24",1.1,1,1.3,0.3),("2017-10-25",3,4,4.5,2.5),("2017-10-26",5,8,9,3),("2017-10-27",10,8,9,3),("2017-10-28",5,8,9,8.5),("2017-10-29",5,8,9,3)
,("2017-10-30",5,8,9,3),("2017-10-31",5,8,9,3),("2017-11-01",5,8,9,3));
line.parent := axs;
end
fg;
end
//盒须图
uses tslvcl,utvclgraphics,utvclgraphicsext;
app := initializeapplication();
app.createform(class(tfm),fm);
fm.show();
app.run();
type tfm = class(tvcform)
function create(aowner);
begin
inherited;
Caption := "盒须图";
fg := new tg_WinControl(self);
fg.Caption := "盒须图";
fg.parent := self;
fg.Align := alClient;
//////////设置坐标轴属性////////////////////////
axs := new tg_axes();
axs.figure := fg.figure;
axs.title.text := "盒须图";
axs.title.fontinfo.size := 15;
axs.title.fontinfo.color := 0xff0000;
axs.axises(1).tics_color := 0x0000ff;
axs.axises(1).fontinfo.size := 8;
axs.axises(1).lineinfo.color := 0x00ff00;
axs.grid(0).Width := 2;
axs.grid(0).color := 0x0ff0f0;
line := new tg_Polyboxplot();
line.lineinfo.color := 0xff0000;
line.graph_data := array((850, 740, 900, 1070, 930, 850, 950, 980, 980, 880, 1000, 980, 930, 650, 760, 810, 1000, 1000, 960, 960),
(960, 940, 960, 940, 880, 800, 850, 880, 900, 840, 830, 790, 810, 880, 880, 830, 800, 790, 760, 800),
(880, 880, 880, 860, 720, 720, 620, 860, 970, 950, 880, 910, 850, 870, 840, 840, 850, 840, 840, 840),
(890, 810, 810, 820, 800, 770, 760, 740, 750, 760, 910, 920, 890, 860, 880, 720, 840, 850, 850, 780),
(890, 840, 780, 810, 760, 810, 790, 810, 820, 850, 870, 870, 810, 740, 810, 940, 950, 800, 810, 870)
);
line.parent := axs;
end
fg;
end
//旭日图
uses tslvcl,utvclgraphics,utvclgraphicsext;
app := initializeapplication();
app.createform(class(tfm),fm);
fm.show();
app.run();
type tfm = class(tvcform)
function create(aowner);
begin
inherited;
caption := '旭日图';
width := 800;
Height := 800;
fg := new tg_WinControl(self);
fg.parent := self;
fg.Align := alClient;
//////////设置坐标轴属性////////////////////////
axs := new tg_axes();
axs.box := true;
axs.figure := fg.figure;
axs.title.text :="旭日图";
args := array(
'name': '组织',
'children': (
(
'name': '总经理办公室',
'children': (
(
'name': '财务部',
"itemstyle":("color":0xff00ff),
'value': 15,
'children': (
('name': '会计', 'value': 2),
(
'name': '财务主管',
'value': 5,
'children': (
('name': '财务专员', 'value': 2)
)
),
('name': '财务助理', 'value': 4)
)
),
('name': '市场部', 'children': (('name': '市场经理', 'value': 4))),
(
'name': '人力资源部',
'value': 10,
'children': (
('name': '人事经理', 'value': 5, 'itemStyle': ('color': 'yellow')),
('name': '招聘专员', 'value': 1)
)
)
)
),
(
'name': '技术部',
'children': (
(
'name': '研发部',
'children': (
('name': '项目经理', 'value': 3),
(
'name': '开发工程师',
'value': 4,
'children': (('name': '实习生', 'value': 2))
)
)
)
)
),
(
'name': '销售部',
'children': (
(
'name': '销售经理',
'children': (
('name': '销售代表', 'value': 1),
('name': '销售助理', 'value': 2)
)
)
)
)
)
);
line := new tg_Polysunburst();
line.graph_data := args;
line.parent := axs;
end
fg;
end
}
type tg_Polycandlestick = class(tg_graph) //k线图
function create(pms);
begin
inherited;
fbarrgn := array();
clip_state := tgc_on;
line_mode := tgc_on;
mark_mode := tgc_off;
fbar_width := 0.3;
fdata_bounds := array((0,1),(0,1),(0,1));
end
function get_data_bounds();override; //边界
begin
//fdata_bounds[0,1] := length(fgraph_data);
return fdata_bounds;
end
function paint(cvs);override; //绘制
begin
if tgc_on<> visible then return ;
tempbarw := 0;
bx := axes.zoom_box;
if clip_state=tgc_on then
begin
pts := array();
for i,v in graph_paint_rec_to_points( array(bx[0,0],bx[1,0],bx[0,1],bx[1,1])) do
begin
zoom_to_xyz(v[0],v[1],bx[2,0],x,y);
pts[i] := array(x,y);
end
cvs.clip_rgn(pts);
end else
begin
cvs.axesunclip();
end
xys := array();
wick_y := array();
set_lineinfo_to_canvas(cvs);
xlbl := array("0");
xcd := array(0);
for i,v in fgraph_data do
begin
xlbl[i+1] := v[0];
xcd[i+1] := i+1;
end
axes.axises(0).tics_coord := xcd;
axes.axises(0).tics_labels := xlbl;
ys := array();
for i,v in fgraph_data do
begin
if not zoom_to_xyz(i+1,v[1],bx[2,0],x,y) then return ;
xys[i] := array(integer(x),integer(y));
if not zoom_to_xyz(i+1,v[3],bx[2,0],x,y) then return ;
wick_y[i][0] := array(integer(x),integer(y));
if not zoom_to_xyz(i+1,v[4],bx[2,0],x,y) then return ;
wick_y[i][1] := array(integer(x),integer(y));
zoom_to_xyz(i+1,v[2],bx[2,0],x,y) ;
ys[i] := array(integer(x),integer(y));
if not zoom_to_xyz(i+1,v[1],bx[2,0],x,y) then return ;
if not(tempbarw) and fbar_width>0 then ////////计算宽度///////
begin
b := get_abs_barwidth();
zoom_to_xyz((i+1+b/2),v[1],bx[2,0],xtemp,ytemp);
xtemp-=x;
ytemp-=y;
tempbarw := array();
tempbarw[0] := b*(xtemp)/(abs(xtemp)+abs(ytemp));
tempbarw[1] := b*(ytemp)/(abs(xtemp)+abs(ytemp));
end
end
fline_points_in_canvas := xys;
fbarrgn := array();
pinfo := array("line_mode":line_mode,"bar_width":tempbarw,"color":lineinfo.color,"bullcolor":fbullcolor,"bearcolor":fbearcolor,"bkcolor":lineinfo.bkcolor,"xy0":ys,"wick_y": wick_y);
paint_candlestick(cvs,0,xys,0,fgraph_data,pinfo);
fbarrgn := pinfo["barrgn"];
inherited;
end
function executecommand(cmd,p);override;
begin
case cmd of
"hit_point":
begin
for i,v in fbarrgn do
begin
if point_in_rgn(p,v) then return i;
end
return -1;
end
"points_in_canvas":return (visible=tgc_on)? fline_points_in_canvas:nil; //???????
end;
return inherited;
end
published
property bar_width read fbar_width write set_barwidth;//宽度
property bullcolor read fbullcolor write set_bullcolor;//牛色
property bearcolor read fbearcolor write set_bearcolor;//熊色
private
fline_points_in_canvas;
fbarrgn;
fdata_bounds;
fforeground;
fbackground;
fbar_width;
fbullcolor;
fbearcolor;
protected
function set_graph_data(d);override; //设置数据
begin
if d<>fgraph_data then
begin
//fx := d[:,0];
fdata_bounds[0,0] := 0;
fdata_bounds[0,1] := length(d);
fdata_bounds[1,0] := minvalue(d[:,4]);
fdata_bounds[1,1] := maxvalue(d[:,3]);
inherited;
end
end
private
function get_abs_barwidth();//获得
begin
if fbar_width>0 and fbar_width<=1 then
begin
if zoom_to_xyz(0,0,nil,x1,y1) and zoom_to_xyz(1,0,nil,x2,y2) then
begin
return (abs(x1-x2)+abs(y1-y2))*fbar_width;
end
end
return fbar_width;
end
function set_barwidth(v);//设置宽度
begin
if (v<>fbar_width) and (v>0) then
begin
fbar_width := v;
prop_changed("barwidth",v);
end
end
function set_bullcolor(v);//牛色
begin
//if not graph_paint_boolen_value(v,nv) then return ;
if v<>fbullcolor and ifnumber(v) then
begin
fbullcolor := v;
prop_changed("bullcolor",v);
end
end
function set_bearcolor(v);//熊色
begin
//if not graph_paint_boolen_value(v,nv) then return ;
if v<>fbearcolor and ifnumber(v) then
begin
fbearcolor := v;
prop_changed("bearcolor",v);
end
end
end
type tg_Polyboxplot = class(tg_graph) //盒须图
function create(pms);
begin
inherited;
fbarrgn := array();
clip_state := tgc_on;
line_mode := tgc_on;
mark_mode := tgc_off;
fbar_width := 0.3;
fdata_bounds := array((0,1),(0,1),(0,1));
end
function get_data_bounds();override; //??????
begin
return fdata_bounds;
end
function paint(cvs);override; //???
begin
if tgc_on<> visible then return ;
bx := axes.zoom_box;
if clip_state=tgc_on then
begin
//cvs.axesclip();
pts := array();
for i,v in graph_paint_rec_to_points( array(bx[0,0],bx[1,0],bx[0,1],bx[1,1])) do
begin
zoom_to_xyz(v[0],v[1],bx[2,0],x,y);
pts[i] := array(x,y);
end
cvs.clip_rgn(pts);
end else
begin
cvs.axesunclip();
end
xys := array();
medians := array();
wick_y := array();
outliers := array();
inliers := array(());
set_lineinfo_to_canvas(cvs);
ys := array();
for i,v in fgraph_data do
begin
q1 := Quartile(v,1);
q2 := Quartile(v,2);
q3 := Quartile(v,3);
iqr := q3-q1;
maximum := q3+(1.5*iqr);
minimum := q1-(1.5*iqr);
inliers[i] := array();
for j,w in v do
begin
len := length(outliers);
if w>=minimum and w<=maximum then
begin
inlen := length(inliers[i]);
inliers[i][inlen] := w;
end
else if w < minimum then
begin
if not zoom_to_xyz(i+1,w,bx[2,0],x,y) then return ;
outliers[len] := array(integer(x),integer(y));
end
else
begin
if not zoom_to_xyz(i+1,w,bx[2,0],x,y) then return ;
outliers[len] := array(integer(x),integer(y));
end
end
if not zoom_to_xyz(i+1,q1,bx[2,0],x,y) then return ;
xys[i] := array(integer(x),integer(y));
if not zoom_to_xyz(i+1,q2,bx[2,0],x,y) then return ;
medians[i] := array(integer(x),integer(y));
if not zoom_to_xyz(i+1,MaxValue(inliers[i]),bx[2,0],x,y) then return ;
wick_y[i][0] := array(integer(x),integer(y));
if not zoom_to_xyz(i+1,MinValue(inliers[i]),bx[2,0],x,y) then return ;
wick_y[i][1] := array(integer(x),integer(y));
zoom_to_xyz(i+1,q3,bx[2,0],x,y) ;
ys[i] := array(integer(x),integer(y));
if not zoom_to_xyz(i+1,q1,bx[2,0],x,y) then return ;
if not(tempbarw) and fbar_width>0 then ////////????bar????///////
begin
b := get_abs_barwidth();
zoom_to_xyz((i+1+b/2),q1,bx[2,0],xtemp,ytemp);
xtemp-=x;
ytemp-=y;
tempbarw := array();
tempbarw[0] := b*(xtemp)/(abs(xtemp)+abs(ytemp));
tempbarw[1] := b*(ytemp)/(abs(xtemp)+abs(ytemp));
end
end
fline_points_in_canvas := xys;
pinfo := array("line_mode":line_mode,"bar_width":tempbarw,"color":lineinfo.color,"bkcolor":lineinfo.bkcolor,"xy0":ys,"wick_y": wick_y, "medians": medians);
paint_boxplot(cvs,0,xys,0,pinfo);
fbarrgn := pinfo["barrgn"];
mk := markinfo.clone();
if mark_mode=tgc_on and mk.size>2 then
begin
graph_paint_points(mk,cvs,outliers);
end
inherited;
end
function executecommand(cmd,p);override;
begin
case cmd of
"points_in_canvas":return (visible=tgc_on)? fline_points_in_canvas:nil; //???????
end;
return inherited;
end
function get_legend_size(w,h);virtual; //??????????
begin
mk := markinfo;
h := fontinfo.size*2+4;
w := 100;
if mark_mode=tgc_on then
begin
h := max(h,mk.size+4);
w := 5*h;
end
end
function paint_legend(cvs,rec);override; //???????
begin
y0 := ceil(rec[1]+(rec[3]-rec[1])/2);
dis := ceil((rec[2]-rec[0])/5);
xys := array((rec[0]+dis,y0),(rec[0]+4*dis,y0));
set_lineinfo_to_canvas(cvs);
graph_paint_lines(cvs,tgc_LS_interpolated,xys,0,array("line_mode":line_mode,"bar_width":fbar_width,"color":lineinfo.color,"bkcolor":lineinfo.bkcolor));
mk := markinfo.clone();
if mark_mode=tgc_on and mk.size>2 then
begin
xys := array((rec[0]+dis*2,y0),(rec[0]+3*dis,y0));
graph_paint_points(mk,cvs,xys);
end
end
property bar_width read fbar_width write set_bar_width;//= "0" ??????
private
fbarrgn;
fline_points_in_canvas;
fdata_bounds;
fforeground;
fbackground;
fbar_width;
protected
function set_graph_data(d);override; //????????
begin
if d<>fgraph_data then
begin
fdata_bounds[0,0] := 0;
fdata_bounds[0,1] := length(d);
fdata_bounds[1,0] := minvalue(minvalue(d));
fdata_bounds[1,1] := maxvalue(maxvalue(d));
inherited;
end
end
private
function get_abs_barwidth();//获得
begin
if fbar_width>0 and fbar_width<=1 then
begin
if zoom_to_xyz(0,0,nil,x1,y1) and zoom_to_xyz(1,0,nil,x2,y2) then
begin
return (abs(x1-x2)+abs(y1-y2))*fbar_width;
end
end
return fbar_width;
end
function set_bar_width(v);
begin
if v<>fbar_width and v>0 then
begin
fbar_width := v;
prop_changed("bar_width",nv);
end
end
end
type tg_Polypie = class(tg_graph) //饼图
function create(pms);
begin
ftexts := array();
fshow_text := 1;
pie_radian := array();
inherited;
clip_state := tgc_on;
fcolormap := get_default_color_list();
line_mode := tgc_on;
mark_mode := tgc_off;
fpie_type := 'pie';
fdata_bounds := array((0,1),(0,1),(0,1));
end
function get_data_bounds();override; //
begin
return fdata_bounds;
end
function paint(cvs);override;
begin
if tgc_on<> visible then return ;
bx := axes.zoom_box;
if clip_state=tgc_on then
begin
pts := array();
for i,v in graph_paint_rec_to_points( array(bx[0,0],bx[1,0],bx[0,1],bx[1,1])) do
begin
zoom_to_xyz(v[0],v[1],bx[2,0],x,y);
pts[i] := array(x,y);
end
cvs.clip_rgn(pts);
end else
begin
cvs.axesunclip();
end
xys := array();
medians := array();
wick_y := array();
outliers := array();
inliers := array(());
set_lineinfo_to_canvas(cvs);
ys := array();
prominentidx := 1;//
prominentrate := 0; //
fpei_parts_data := array();
for i,v in pie_radian do
begin
if fpie_type='pie' then
begin
pie_data := 1+get_pie_lines(v[0],v[1],i=prominentidx,prominentrate);
end
else if fpie_type='ring' then
begin
pie_data := 1+get_pie_ring_lines(v[0],v[1],0.7,0.4,i=prominentidx,prominentrate);
end
else if fpie_type='rose' then
begin
pie_data := 1+get_rose_lines(v[0],v[1],i=prominentidx,prominentrate, v[3]);
end
xys := array();
for j,v in pie_data do
begin
if not zoom_to_xyz(v[0],v[1],bx[2,0],x,y) then return ;
xys[j] := array(integer(x),integer(y));
end
index := i%length(fcolormap);
item_color := fcolormap[index];
paint_pie(cvs,xys,array("line_mode":line_mode,"color":item_color,"bkcolor":item_color,"xy0":ys));
fpei_parts_data[i] := xys;
end
end
function executecommand(cmd,p);override;
begin
case cmd of
"get_texts":
begin
return ftexts;
end
"hit_part":
begin
for i,v in fpei_parts_data do
begin
if point_in_rgn(p,v,true) then return i;
end
return -1;
end
end;
return inherited;
end
function get_legend_size(w,h);override; //获取图例大小
begin
if not pie_radian then return inherited;
sz := fontinfo.size;
h := (sz*2+6)*max(1,length(pie_radian))+5;
w := 0;
ws := 5;
for i,v in pie_radian do
begin
si :=v[2];
if ifstring(si) then ws := max((length(si))*sz,ws);
end
w +=ws;
w +=35;
end
function paint_legend(cvs,rec);override; //绘制图例
begin
set_lineinfo_to_canvas(cvs);
set_fontinfo_to_canvas(cvs);
h := fontinfo.size*2+6;// + ((h-fontinfo.size)/2);
y0 := rec[1]+h;
for i,v in pie_radian do
begin
index := i%length(fcolormap);
item_color := fcolormap[index];
xys := array((rec[0]+2,y0+i*h-3),(rec[0]+25,y0+i*h-3),(rec[0]+25,y0-h+6+i*h),(rec[0]+2,y0-h+6+i*h));
paint_pie(cvs,xys,array("line_mode":line_mode,"bar_width":fbar_width,"color":item_color,"bkcolor":item_color));
cvs.textout(v[2],array(rec[0]+30,y0+(i-1)*h+3));
end
end
property color_map read fcolormap write set_colormap;//颜色地图
property pie_type read fpie_type write set_pie_type;//类型
property show_text read fshow_text write set_show_text;
private
ftexts;
fshow_text;
pie_radian;
fpei_parts_data;
fdata_bounds;
fpie_type;
fforeground;
fbackground;
fcolormap;
protected
function set_graph_data(d);override; //设置数据
begin
if d<>fgraph_data then
begin
fdata_bounds[0,0] := 0;
fdata_bounds[1,0] := 0;
fdata_bounds[0,1] := 2;
fdata_bounds[1,1] := 2;
inherited;
data_process();
end
end
private
function set_pie_type(v);
begin
if v<>fpie_type and ( v in array("pie","rose","ring")) then
begin
fpie_type := v;
data_process();
end
end
function set_show_text(v);
begin
if v<>fshow_text and (v in array(0,1,2,3)) then
begin
fshow_text := v;
data_process();
end
end
function set_colormap(v);
begin
if ifarray(v) and v<>fcolormap then
begin
fcolormap := v;
end
end
function data_process(); //
begin
total := 0;
total_value_list := array();
for i,v in fgraph_data do
begin
total := total + v['value'];
total_value_list[i] := v['value'];
end
maxt := maxvalue(total_value_list);
currentAngle := 0;
pie_radian := array();
for i,v in ftexts do //清空
begin
v.parent := false;
end
ftexts := array();
for i,v in fgraph_data do
begin
pie_radian[i][0] := currentAngle;
rs := v['value'] / total;
pie_radian[i][1] := currentAngle + (rs) * 2 * pi();
sri := format("%3f",rs*100)+"%";
pie_radian[i][2] := mult_str(" ",7-length(sri))$sri$" "$v["name"];
pie_radian[i][3] := v['value']/maxt;
pie_radian[i][4] := currentAngle + rs * pi();
pie_radian[i][5] := (rs) * 2 * pi();
carg := currentAngle + rs * pi();
currentAngle := pie_radian[i][1];
gtx := new tg_text();
gtx.parent := self;
gtx.clip_state :=false;
case pie_type of
"rose":
begin
gtx.data := 1+array(sin(pie_radian[i][4])*pie_radian[i][3],cos(pie_radian[i][4])*pie_radian[i][3]);
end
"ring":
begin
gtx.data := 1+array(sin(pie_radian[i][4])*0.7,cos(pie_radian[i][4])*0.7);
end else
begin
gtx.data := 1+array(sin(pie_radian[i][4]),cos(pie_radian[i][4]))*0.8;
end
end ;
if carg<(pi()/4) then
begin
gtx.textalign := 8;
end else
if carg<(pi()*3/4) then
begin
gtx.textalign := 4;
end else
if carg<(pi()*5/4) then
begin
gtx.textalign := 2;
end else
if carg<(pi()*7/4) then
begin
gtx.textalign := 6;
end else gtx.textalign := 8;
case fshow_text of
1:
begin
gtx.text := array(sri);
end
2:
begin
gtx.text := array(v["name"]);
end
3:
begin
gtx.text := array(pie_radian[i][2]);
end
else
begin
gtx.text := array();
end
end;
ftexts[i] := gtx;
end
end
function get_pie_lines(arg1,arg2,prominent,prominentrate); //?????????????
begin
stp := pi()/360;
d := 1;
r := array();
r[0] := array(0,0);
idx := 1;
for i:= arg1 to arg2 step stp do
begin
r[idx++] := array(sin(i),cos(i));
end
r[idx] :=array(0,0);
if prominent then
begin
rx := r[integer(idx/2)]*prominentrate;
for i := 0 to idx do
begin
r[i]+=rx;
end
end
return r*0.8;
end
function get_rose_lines(arg1,arg2,prominent,prominentrate,proportion); //???????????????
begin
stp := pi()/360;
d := 1;
r := array();
r[0] := array(0,0);
idx := 1;
for i:= arg1 to arg2 step stp do
begin
r[idx++] := array(sin(i),cos(i));
end
r[idx] :=array(0,0);
if prominent then
begin
rx := r[integer(idx/2)]*prominentrate;
for i := 0 to idx do
begin
r[i]+=rx;
end
end
return r*proportion;
end
end
type tg_Polyradar = class(tg_graph) //雷达图
function create(pms);
begin
findicator_texts := array();
inherited;
clip_state := tgc_on;
fcolormap := get_default_color_list();
line_mode := tgc_on;
mark_mode := tgc_off;
fdata_bounds := array((0,1),(0,1),(0,1));
end
function get_data_bounds();override; //数据边界
begin
return fdata_bounds;
end
function paint(cvs);override; //绘制
begin
if tgc_on<> visible then return ;
bx := axes.zoom_box;
if clip_state=tgc_on then
begin
//cvs.axesclip();
pts := array();
for i,v in graph_paint_rec_to_points( array(bx[0,0],bx[1,0],bx[0,1],bx[1,1])) do
begin
zoom_to_xyz(v[0],v[1],bx[2,0],x,y);
pts[i] := array(x,y);
end
cvs.clip_rgn(pts);
end else
begin
cvs.axesunclip();
end
xys := array();
medians := array();
wick_y := array();
outliers := array();
inliers := array(());
set_lineinfo_to_canvas(cvs);
ys := array();
radar_indicator_radian := data_indicator_process(findicator);
draw_radar_grid(cvs,radar_indicator_radian);
for j,w in fgraph_data do
begin
vl := array();
for jj,vj in w['value'] do
begin
vl[jj] := vj/findicator[jj]['max'];
end
cl := fcolormap[j%length(fcolormap)];
cvs.pen.color := cl;
for i,v in 1+get_radar_cyclings(radar_indicator_radian,vl) do
begin
zoom_to_xyz(v[0],v[1],z,x,y) ;
xys[i] := array(x,y);
end
cvs.brush.color := cl;
cvs.brush.style := BS_SOLID;
cvs.alpha := 60+j*10;
cvs.draw_polygon().points(xys).draw();
cvs.alpha := 255;
cvs.draw_polyline().points(xys).draw();
end
end
function executecommand(cmd,p);override;
begin
case cmd of
"points_in_canvas":return (visible=tgc_on)? fline_points_in_canvas:nil; //???????
end;
return inherited;
end
function get_legend_size(w,h);override; //图例大小
begin
sz := fontinfo.size;
h := (sz*2+6)*max(1,length(fgraph_data))+5;
w := 0;
ws := 5;
for i,v in fgraph_data do
begin
si :=v["name"];
if ifstring(si) then ws := max((length(si))*sz,ws);
end
w +=ws;
w +=35;
end
function paint_legend(cvs,rec);override; //图例绘制
begin
set_lineinfo_to_canvas(cvs);
set_fontinfo_to_canvas(cvs);
h := fontinfo.size*2+6;// + ((h-fontinfo.size)/2);
y0 := rec[1]+h;
for i,v in fgraph_data do
begin
index := i%length(fcolormap);
item_color := fcolormap[index];
xys := array((rec[0]+2,y0+i*h),(rec[0]+25,y0+i*h),(rec[0]+25,y0-fontinfo.size+i*h),(rec[0]+2,y0-fontinfo.size+i*h));
paint_pie(cvs,xys,array("line_mode":line_mode,"bar_width":fbar_width,"color":item_color,"bkcolor":item_color));
cvs.textout(v["name"],array(rec[0]+30,y0+(i-1)*h));
end
end
property color_map read fcolormap write fcolormap;
property indicator read findicator write set_indicator;// 指标轴
private
fline_points_in_canvas;
fdata_bounds;
fcolormap;
fforeground;
fbackground;
findicator;
findicator_texts;
protected
function set_graph_data(d);override; //????????
begin
if d<>fgraph_data then
begin
fdata_bounds[0,0] := -0.1;
fdata_bounds[0,1] := 2.1;
fdata_bounds[1,0] := -0.2;
fdata_bounds[1,1] := 2.1;
inherited;
end
end
private
function set_indicator(v);
begin
if ifarray(v) and v<>findicator then
begin
findicator := v;
draw_indicator_text(v);
end
end
function data_indicator_process(data); //计算数据
begin
borders := Length(data);
angleStep := 2 * pi() / borders;
currentAngle := 0;
segments := array(0);
for i,v in data do
begin
if i=0 then continue;
currentAngle += angleStep;
segments[i] := currentAngle;
end
return segments;
end
function draw_indicator_text(data);
begin
borders := Length(data);
angleStep := 2 * pi() / borders;
currentAngle := 0;
rightVertices := array();
for i,v in findicator_texts do
begin
v.parent := nil;
end
findicator_texts := array();
for i := 0 to borders - 1 do
begin
text_indicator := 1+array(sin(currentAngle)*1,cos(currentAngle)*1);
gtx := new tg_text();
gtx.clip_state := tgc_off;
gtx.line_mode := false;
gtx.parent := self;
gtx.text := array(data[i]['name']);
gtx.data := text_indicator;
if currentAngle<(pi()/4) then
begin
gtx.textalign := 8;
end else
if currentAngle<(pi()*3/4) then
begin
gtx.textalign := 4;
end else
if currentAngle<(pi()*5/4) then
begin
gtx.textalign := 2;
end else
if currentAngle<(pi()*7/4) then
begin
gtx.textalign := 6;
end else gtx.textalign := 8;
//gtx.font_angle := currentAngle-pi()*3/4;
currentAngle := currentAngle + angleStep;
findicator_texts[i] := gtx;
end
end
function get_radar_cyclings(iradar,r1);
begin
vis := array();
r := array();
for i,vi in iradar do
begin
if ifarray(r1) then rx := r1[i];
else rx := r1;
x0 := sin(vi)*rx;
y0 := cos(vi)*rx;
r[i] := array(x0,y0);
end
r[length(r)] := r[0];
return r;
end
function draw_radar_grid(cvs,iradar);
begin
bx := axes.zoom_box;
z := bx[2,0];
vis := array();
set_lineinfo_to_canvas(cvs);
for i,vi in iradar do
begin
x0 := sin(vi);
y0 := cos(vi);
if not zoom_to_xyz(x0+1,y0+1,z,x,y) then return ;
zoom_to_xyz(1,1,z,x1,y1);
cvs.moveto(array(x1,y1));
cvs.lineto(array(x,y));
end
n := 4;
st := 1/n;
for i := 1 to n do
begin
for i,v in 1+get_radar_cyclings(iradar,i*st) do
begin
zoom_to_xyz(v[0],v[1],z,x,y) ;
if i=0 then cvs.moveto(x,y);
else cvs.lineto(x,y);
end
end
end
end
type tg_Polytree = class(tg_graph) //树图对象
function create(pms);
begin
inherited;
clip_state := tgc_on;
line_mode := tgc_on;
mark_mode := tgc_off;
fshow_text := tgc_on;
fdata_bounds := array((0,50),(0,50),(0,50));
fnode_space_x := 50;
end
function get_data_bounds();override; //数据边界
begin
return fdata_bounds;
end
function paint(cvs);override; //绘图
begin
if tgc_on<> visible then return ;
bx := axes.zoom_box;
if clip_state=tgc_on then
begin
pts := array();
for i,v in graph_paint_rec_to_points( array(bx[0,0],bx[1,0],bx[0,1],bx[1,1])) do
begin
zoom_to_xyz(v[0],v[1],bx[2,0],x,y);
pts[i] := array(x,y);
end
cvs.clip_rgn(pts);
end else
begin
cvs.axesunclip();
end
xys := array();
set_lineinfo_to_canvas(cvs);
ys := array();
fline_points_in_canvas := xys;
render_tree(fstructure_tree, cvs, bx);
end
function executecommand(cmd,p);override;
begin
case cmd of
"points_in_canvas":return (visible=tgc_on)? fline_points_in_canvas:nil; //数据散点
end;
return inherited;
end
function firstwalk(V,Distance);override; // 第一次递归
begin
if V.NodeCount = 0 then
begin
if V.leftmost_sibling <> nil then
begin
if V.left_brother() = nil then
V.X := 0 + Distance;
else
V.X := V.left_brother().X + Distance;
end
else
V.X := 0;
end
else
begin
DefaultAncestor := V.GetNodeByIndex(0);
for i := 0 to V.NodeCount-1 do
begin
firstwalk(V.GetNodeByIndex(i), Distance);
DefaultAncestor := apportion(V.GetNodeByIndex(i), DefaultAncestor, Distance);
end;
ExecuteShifts(V);
Midpoint := (V.GetNodeByIndex(0).X + V.LastChild.X) / 2;
W := V.left_brother();
if W <> nil then
begin
V.X := W.X + Distance;
V.ModVal := V.X - Midpoint;
end
else
V.X := Midpoint;
end;
return V;
end;
function apportion(V,DefaultAncestor, Distance);override; //修正子孙节点定位
begin
LeftBrother := V.left_brother();
if LeftBrother <> nil then
begin
VInnerRight := V;
VOuterRight := V;
VInnerLeft := LeftBrother;
VOuterLeft := V.leftmost_sibling;
if VOuterLeft = nil then VOuterLeft := V;
SInnerRight := V.ModVal;
SOuterRight := V.ModVal;
SInnerLeft := VInnerLeft.ModVal;
SOuterLeft := VOuterLeft.ModVal;
while (VInnerLeft.right() <> nil) and (VInnerRight.left() <> nil) do
begin
VInnerLeft := VInnerLeft.right();
VInnerRight := VInnerRight.left();
VOuterLeft := VOuterLeft.left();
VOuterRight := VOuterRight.right();
if VInnerLeft = 0 then
begin
end
if VOuterRight = 0 then
begin
end
VOuterRight.Ancestor := V;
Shift := (VInnerLeft.X + SInnerLeft) - (VInnerRight.X + SInnerRight) + Distance;
if Shift > 0 then
begin
Anc := get_ancestor(VInnerLeft, V, DefaultAncestor);
move_subtree(Anc, V, Shift);
SInnerRight := SInnerRight + Shift;
SOuterRight := SOuterRight + Shift;
end;
SInnerLeft := SInnerLeft + VInnerLeft.ModVal;
SInnerRight := SInnerRight + VInnerRight.ModVal;
SOuterLeft := SOuterLeft + VOuterLeft.ModVal;
SOuterRight := SOuterRight + VOuterRight.ModVal;
end;
if (VInnerLeft.right() <> nil) and (VOuterRight.right() = nil) then
begin
VOuterRight.Thread := VInnerLeft.right();
VOuterRight.ModVal := VOuterRight.ModVal + (SInnerLeft - SOuterRight);
end
else if (VInnerRight.left() <> nil) and (VOuterLeft.left() = nil) then
begin
VOuterLeft.Thread := VInnerRight.left();
VOuterLeft.ModVal := VOuterLeft.ModVal + (SInnerRight - SOuterLeft);
end;
DefaultAncestor := V;
end;
return DefaultAncestor;
end;
function move_subtree(WL,WR, Shift);override; //移动子树
begin
Subtrees := WR.TNumber - WL.TNumber;
_WRChange := WR.Change - (Shift / Subtrees);
WR.Change := _WRChange;
_WRShift := WR.Shift + Shift;
WR.Shift := _WRShift;
_WLChange := WL.Change + (Shift / Subtrees);
WL.Change :=_WLChange;
_WRX := WR.X + Shift;
WR.X := _WRX;
_WRModVal := WR.ModVal + Shift;
WR.ModVal := _WRModVal;
end;
function ExecuteShifts(V);override;
begin
Shift := 0;
Change := 0;
for i := V.NodeCount-1 downto 0 do
begin
W := V.GetNodeByIndex(i);
W.X := W.X + Shift;
W.ModVal := W.ModVal + Shift;
Change := Change + W.Change;
Shift := Shift + W.Shift + Change;
if Change = NAN then
if Change = -INF then
end;
end;
function get_ancestor(VIL, V, DefaultAncestor);override; //如果vil节点的祖先节点在v节点的兄弟节点中那么返回vil的祖先节点否则返回default_ancestor
begin
if (VIL.Ancestor <> nil) and (V.Parent <> nil) and (VIL.Ancestor.Parent = V.Parent) then
return VIL.Ancestor;
else
return DefaultAncestor;
end;
function second_walk(V, M, Depth, Min);override; //第二次遍历
begin
V.X := V.X + M;
V.Y := Depth;
if Min = -1 then
Min := V.X
else if V.X < Min then
Min := V.X;
for i := 0 to V.NodeCount-1 do
Min := second_walk(V.GetNodeByIndex(i), M + V.ModVal, Depth + 1, Min);
return Min;
end;
function third_walk(V, N);override; // 第三次遍历
begin
V.X := V.X + N;
for i := 0 to V.NodeCount-1 do
third_walk(V.GetNodeByIndex(i), N);
end;
function Buchheim(Tree);override;
begin
DT := firstwalk(Tree, 1);
Min := second_walk(DT, 0, 0, -1);
if Min < 0 then third_walk(DT, -Min);
return DT;
end;
function handle_tree(V);override;
begin
V.X := V.X * fnode_space_x;
V.X := V.X + fnode_space_x;
V.Y := V.Y * fnode_space_x;
V.Y := V.Y + fnode_space_x;
for i := 0 to V.NodeCount-1 do handle_tree(V.GetNodeByIndex(i));
end;
function render_tree(Tree,cvs, bx);override; //绘制树
begin
if Tree.ShowNode then
begin
for j := 0 to Tree.NodeCount-1 do
begin
if Tree.GetNodeByIndex(j).ShowNode then
begin
xys := array();
set_lineinfo_to_canvas(cvs);
ys := array();
//_data := array((Tree.X,Tree.Y),(Tree.X,(Tree.Y + Tree.GetNodeByIndex(j).Y) / 2),(Tree.GetNodeByIndex(j).X,(Tree.Y + Tree.GetNodeByIndex(j).Y) / 2),(Tree.GetNodeByIndex(j).X,Tree.GetNodeByIndex(j).Y));
TreeY := Tree.Y;
TreeX := Tree.X;
tndj := Tree.GetNodeByIndex(j);
Treejy := tndj.Y;
Treejx := tndj.x;
try2 := (TreeY + Treejy) / 2;
_data := array(
(TreeY, TreeX),
(try2, TreeX),
(try2, Treejx),
(Treejy, Treejx)
);
{_data := array(
(Tree.Y, Tree.X),
((Tree.Y + Tree.GetNodeByIndex(j).Y) / 2, Tree.X),
((Tree.Y + Tree.GetNodeByIndex(j).Y) / 2, Tree.GetNodeByIndex(j).X),
(Tree.GetNodeByIndex(j).Y, Tree.GetNodeByIndex(j).X)
);}
for i,v in _data do
begin
if not zoom_to_xyz(v[0],v[1],bx[2,0],x,y) then return ;
xys[i] := array(integer(x),integer(y));
end
fline_points_in_canvas := xys;
set_lineinfo_to_canvas(cvs);
paint_tree(cvs,xys,array("line_mode":line_mode,"bar_width":0,"color":lineinfo.color,"bkcolor":lineinfo.bkcolor,"xy0":ys));
mk := markinfo.clone();
if mark_mode=tgc_on and mk.size>2 then
begin
graph_paint_points(mk,cvs,array(xys[0], xys[3]));
end
if (Tree.GetNodeByIndex(j).NodeCount) then render_tree(Tree.GetNodeByIndex(j),cvs, bx);
end
end
end
end;
property node_space_x read fnode_space_x write set_node_space_x;//= "0" 柱状宽度
property show_text read fshow_text write set_show_text;//= "0" 柱状宽度
private
fline_points_in_canvas;
fdata_bounds;
fforeground;
fbackground;
fnode_space_x;
fshow_text;
fstructure_tree;
protected
function set_graph_data(d);override; //设置数据
begin
if d<>fgraph_data then
begin
test_tree := new tg_tree_node(d,nil,0,1);
Buchheim_tree := Buchheim(test_tree);
handle_tree(Buchheim_tree);
fstructure_tree := Buchheim_tree;
find_data_bounds(fstructure_tree);
//fdata_bounds[0,1] := fdata_bounds[0,1] +fnode_space_x;
//fdata_bounds[1,1] := fdata_bounds[1,1] +fnode_space_x;
inherited;
end
end
private
function set_node_space_x(v);
begin
if v >=0 and v<>fnode_space_x then
begin
fnode_space_x := v;
prop_changed("node_space_x",v);
end
end
function set_show_text(v);
begin
if not graph_paint_boolen_value(v,nv) then return ;
if nv<>fshow_text then
begin
fshow_text := nv;
find_data_bounds(fstructure_tree);
prop_changed("show_text",nv);
end
end
function find_data_bounds(Tree); //设置数据
begin
if not fstructure_tree then return ;
if Tree.ShowNode then
begin
if fshow_text = tgc_on then
begin
n := Tree.TName;
if n and ifstring(n) then
begin
if tree.ftextobj then
begin
gtx.data := array(Tree.Y, Tree.X);
end else
begin
gtx := new tg_text();
gtx.clip_state := tgc_off;
gtx.parent := self;
gtx.text := array(n);
gtx.data := array(Tree.Y, Tree.X);
tree.ftextobj := gtx;
end
end else
begin
if tree.ftextobj then
begin
tree.ftextobj.visible := false;
end
end
end
if Tree.NodeCount >0 then
begin
for j := 0 to Tree.NodeCount-1 do
begin
ndj := Tree.GetNodeByIndex(j);
//fdata_bounds[0,0] := 0;
//fdata_bounds[1,0] := 0;
fdata_bounds[0,1] := Max(fdata_bounds[0,1],ndj.Y);
fdata_bounds[1,1] := Max(fdata_bounds[1,1],ndj.X);
find_data_bounds(ndj);
end
end
end
end
end
type tg_Polysunburst = class(tg_graph) //旭日图
function create(pms);
begin
inherited;
ftext_container := array();
clip_state := tgc_on;
fcolormap := get_default_color_list();
line_mode := tgc_on;
mark_mode := tgc_off;
fbar_width := 0;
fdata_bounds := array((0,1),(0,1),(0,1));
fshow_text := tgc_on;
end
function get_data_bounds();override; //边界
begin
return fdata_bounds;
end
function paint(cvs);override; //绘制
begin
if tgc_on<> visible then return ;
bx := axes.zoom_box;
if clip_state=tgc_on then
begin
pts := array();
for i,v in graph_paint_rec_to_points( array(bx[0,0],bx[1,0],bx[0,1],bx[1,1])) do
begin
zoom_to_xyz(v[0],v[1],bx[2,0],x,y);
pts[i] := array(x,y);
end
cvs.clip_rgn(pts);
end else
begin
cvs.axesunclip();
end
xys := array();
medians := array();
wick_y := array();
outliers := array();
inliers := array(());
set_lineinfo_to_canvas(cvs);
ys := array();
CalculateCoordinates(1.0, 10.0, 0.4, 0.7, 0, 360, fgraph_data, cvs, bx);
inherited;
end
function executecommand(cmd,p);override;
begin
case cmd of
"points_in_canvas":return (visible=tgc_on)? fline_points_in_canvas:nil; //???????
end;
return inherited;
end
function CalculateCoordinates(x1, y1, r1, r2, startAngle, endAngle, node, cvs, bx);
begin
totalValue := CalculateTotalValue(node);
angle := startAngle;
_r3 := r1 + (r2 - r1);
_r4 := r2 + (r2 - r1);
ndc := node['children'];
if ndc and ifarray(ndc) then
begin
for i := 0 to length(ndc)-1 do
begin
childStartAngle := angle;
xys := array();
_portion := CalculateTotalValue(ndc[i]) / totalValue;
childEndAngle := angle +_portion * 2 * pi() * x1;
pie_data := fcenter+get_pie_ring_lines(childStartAngle,childEndAngle,r2,r1,0,0);
for j,v in pie_data do
begin
if not zoom_to_xyz(v[0],v[1],bx[2,0],x,y) then return ;
xys[j] := array(integer(x),integer(y));
zoom_to_xyz(v[0],0,0,x,y) ;
end
fline_points_in_canvas := xys;
its := ndc[i]['itemstyle']['color'];
item_color := ifnumber(its)?its: fcolormap[1];
paint_sunburst(cvs,xys,array("line_mode":line_mode,"bar_width":0,"color":0xffffff,"bkcolor":item_color,"xy0":ys));
CalculateCoordinates(_portion * x1, y1, _r3, _r4, childStartAngle, childEndAngle, ndc[i], cvs, bx);
angle := childEndAngle;
end;
end
end;
function CalculateTotalValue(node); //设置数据
begin
if node = nil then return 0;
pv := 0;
if node['value'] <> nil then pv := node['value'];
//return node['value'];
totalValue := 0;
ndc := node['children'];
if ifarray(ndc) and ndc then
begin
for i := 0 to length(ndc)-1 do
begin
totalValue := totalValue + CalculateTotalValue(ndc[i]);
end;
end
return max(pv,totalValue);
end;
function getTreeDepth(node); //获取深度
begin
ndc := node['children'];
if not(ifarray(ndc) and ndc) then
begin
return 0;
end
_deep := 0;
for i := 0 to length(ndc)-1 do
begin
_deep := Max(_deep, getTreeDepth(ndc[i]));
end
return _deep + 1;
end
function get_pie_ring_center(arg1_,arg2_,r1,r2,prominent,prominentrate); //???????????????
begin
arg := arg1_+(arg2_-arg1_)/2;
d1 := r1;
return array(sin(arg)*d1,cos(arg)*d1);
end
function get_legend_size(w,h);override;
begin
inherited ;
end
function paint_legend(cvs,rec);override;
begin
inherited;
end
property color_map read fcolormap write fcolormap;//
property show_text read fshow_text write set_show_text;//
private
ftext_container;
fline_points_in_canvas;
fdata_bounds;
fcolormap;
fshow_text;
fforeground;
fbackground;
fcenter;
protected
function set_graph_data(d);override; //设置数据
begin
if d<>fgraph_data then
begin
clear_text();
deep := getTreeDepth(d);
fcenter := deep*(0.7-0.4)+0.4;
fdata_bounds[0,0] := 0;
fdata_bounds[1,0] := 0;
fdata_bounds[0,1] := fcenter * 2;
fdata_bounds[1,1] := fcenter * 2;
inherited;
draw_text();
end
end
private
function set_show_text(v);
begin
if not graph_paint_boolen_value(v,nv) then return ;
if nv<>fshow_text then
begin
fshow_text := nv;
draw_text();
end
end
function clear_text();
begin
for i,v in ftext_container do
begin
v.parent := nil;
end
ftext_container := array();
end
function draw_text();
begin
if fshow_text = tgc_on then
begin
CalculateTextCoordinates(1.0, 10.0, 0.1, 0.4, 0, 360, fgraph_data);
end else
begin
clear_text();
end
end
function CalculateTextCoordinates(x1, y1, r1, r2, startAngle, endAngle, node);
begin
totalValue := CalculateTotalValue(node);
angle := startAngle;
_r3 := r1 + (r2 - r1);
_r4 := r2 + (r2 - r1);
textct := length(ftext_container)>0;
if ifarray(node) and node["name"] and ifstring(node["name"]) then
begin
gtx := new tg_text();
gtx.clip_state := tgc_on;
gtx.line_mode := 0;
if textct then
begin
gtx.font_angle := ((startAngle + endAngle) / 2) - pi()/2;
text_data := fcenter+get_pie_ring_center(startAngle,endAngle,r1,r2,0,0);
end else
begin
gtx.textalign := 5;
text_data := fcenter+get_pie_ring_center(startAngle,endAngle,r1/2,r2,0,0);
end
gtx.data := text_data;
gtx.parent := self;
gtx.text := array(node['name']);
ftext_container[length(ftext_container)] := gtx;
end
ndc := node['children'];
if ifarray(ndc) and ndc then
begin
for i := 0 to length(ndc)-1 do
begin
childStartAngle := angle;
_portion := CalculateTotalValue(ndc[i]) / totalValue;
childEndAngle := angle +_portion * 2 * pi() * x1;
CalculateTextCoordinates(_portion * x1, y1, _r3, _r4, childStartAngle, childEndAngle, ndc[i]);
angle := childEndAngle;
end;
end
end;
end
implementation
type tg_tree_node = class(TNode)
private
public
ftextobj;
fName;
X; // x坐标
Y; // y坐标
//fChildren;
Thread; // 线程节点,也就是指向下一个轮廓节点
ModVal; // 根据左兄弟定位的x与根据子节点中间定位的x之差
Ancestor; // 要么指向自身,要么指向所属树的根
Change;
Shift;
TNumber; // 这是它在兄弟节点中的位置索引 1...n
LmostSibling; // 最左侧的兄弟节点
ShowNode;
function Create(tree,p,depth,number);virtual;
begin
class(TNode).create();
fName := tree['name'];
ndc := tree['children'];
if ifarray(ndc) and ndc then
begin
for i,v in ndc do
begin
it := new tg_tree_node(v,self,depth+1, i+1) ;
it.parent := self;
AppendNode(it);
//self(true).fChildren := it;
end
end
X := -1;
Y := Depth;
Thread := nil;
ModVal := 0;
Ancestor := self(true);
Change := 0;
Shift := 0;
TNumber := number;
LmostSibling := nil;
ShowNode := tree['show'] = nil ? true : tree['show'];
end
function right(); // 有线程返回线程节点,否则返回最右侧的子节点,也就是树的右轮廓
begin
if self.Thread <> nil then
Result := self.Thread;
else if self.NodeCount > 0 then
Result := self.LastChild;
else
Result := nil;
return Result;
end
function left();virtual; // 有线程返回线程节点,否则返回最左侧的子节点,也就是树的左轮廓
begin
if self.Thread <> nil then
result := self.Thread;
else if self.NodeCount > 0 then
Result := self.GetNodeByIndex(0);
else
Result := nil;
return Result;
end
function left_brother(); // 获取前一个兄弟节点
begin
Result := nil;
if self.Parent = nil then
return Result;
for i := 0 to self.parent.NodeCount-1 do
begin
if self.parent.GetNodeByIndex(i) = self then
return Result;
else
Result := self.parent.GetNodeByIndex(i);
end;
return Result;
end
function get_lmost_sibling(); // 获取同一层级第一个兄弟节点如果第一个是自身那么返回null
begin
if (self.LmostSibling = nil) and (self.Parent <> nil) and (self <> self.Parent.GetNodeByIndex(0)) then
self.LmostSibling := self.Parent.GetNodeByIndex(0);
Result := self.LmostSibling;
return Result;
end
function destroy();override;
begin
inherited;
if ftextobj then ftextobj.parent := nil;
ftextobj := nil;
end
property TName read fName;
property leftmost_sibling read get_lmost_sibling;
end
function get_pie_ring_lines(arg1,arg2,r1,r2,prominent,prominentrate); //???????????????
begin
stp := pi()/360;
d1 := r1;
d2 := r2;
r := array();
s := array();
s_reverse := array();
//r[0] := array(0,0);
idx := 0;
for i:= arg1+(prominent?stp:0) to arg2-(prominent?stp:0) step stp do
begin
s[idx] := array(sin(i)*d2,cos(i)*d2);
r[idx++] := array(sin(i)*d1,cos(i)*d1);
end
ls :=length(s);
for j,v in s do
begin
s_reverse[j] := s[ls-j-1];
end
r &= s_reverse;
if prominent then
begin
rx := r[integer(idx/2)]*prominentrate;
for i := 0 to idx do
begin
r[i]+=rx;
end
end
return r;
end
function paint_candlestick(cvs,pls,xys,cls,fdata,ifo);
begin
o := static new tg_const();
b_w_x := integer(ifo["bar_width"][0]/2);
b_w_y := integer(ifo["bar_width"][1]/2);
//cvs.brush.color := ifo["bullcolor"];
wflg := (abs(b_w_x)+abs(b_w_y))>1;
barrgn := array();
for i,v in xys do
begin
if wflg then
begin
v1 := array(v[0]-b_w_x,v[1]-b_w_y);
v2 := array(v[0]+b_w_x,v[1]+b_w_y);
v3 := array(ifo["xy0",i,0]+b_w_x,ifo["xy0",i,1]+b_w_y);
v4 := array(ifo["xy0",i,0]-b_w_x,ifo["xy0",i,1]-b_w_y);
cvs.brush.style := tgc_BS_SOLID;
upper_wick_start := fdata[i][2]>= fdata[i][1]?ifo["xy0",i]:v;
lower_wick_start := fdata[i][2]>= fdata[i][1]?v:ifo["xy0",i];
cvs.brush.color := fdata[i][2]>= fdata[i][1]?ifo["bullcolor"]:ifo["bearcolor"];
cvs.pen.color := cvs.brush.color;
v1234 := array(v1,v2,v3,v4);
barrgn[i] := v1234;
cvs.draw_polygon().points(v1234).draw();
cvs.moveto(upper_wick_start);
cvs.lineto(ifo["wick_y",i,0]); //
cvs.moveto(lower_wick_start);
cvs.lineto(ifo["wick_y",i,1]); //
end else
begin
cvs.moveto(array(ifo["xy0",i,0],ifo["xy0",i,1]));
cvs.lineto(array(ifo["xy0",i,0],ifo["xy0",i,1]));
end
end
ifo["barrgn"] := barrgn;
end
function paint_boxplot(cvs,pls,xys,cls,ifo); //
begin
o := static new tg_const();
b_w_x := integer(ifo["bar_width"][0]/2);
b_w_y := integer(ifo["bar_width"][1]/2);
barrgn := array();
wflg := (abs(b_w_x)+abs(b_w_y))>1;
for i,v in xys do
begin
if wflg then
begin
v1 := array(v[0]-b_w_x,v[1]-b_w_y);
v2 := array(v[0]+b_w_x,v[1]+b_w_y);
v3 := array(ifo["xy0",i,0]+b_w_x,ifo["xy0",i,1]+b_w_y);
v4 := array(ifo["xy0",i,0]-b_w_x,ifo["xy0",i,1]-b_w_y);
v1234 := array(v1,v2,v3,v4);
barrgn[i] := v1234;
upper_wick_start := ifo["xy0",i];
lower_wick_start := v;
cvs.pen.color := cvs.brush.color; // ???????????
cvs.draw_polygon().points(v1234).draw();
cvs.moveto(upper_wick_start);
cvs.lineto(ifo["wick_y",i,0]); // ?????10???????????????????????????wick_y
cvs.moveto(lower_wick_start);
cvs.lineto(ifo["wick_y",i,1]);
upper_bound_start := array(ifo["wick_y",i,0,0]-b_w_x,ifo["wick_y",i,0,1]-b_w_y);
upper_bound_end := array(ifo["wick_y",i,0,0]+b_w_x,ifo["wick_y",i,0,1]+b_w_y);
cvs.moveto(upper_bound_start);
cvs.lineto(upper_bound_end);
lower_bound_start := array(ifo["wick_y",i,1,0]-b_w_x,ifo["wick_y",i,1,1]-b_w_y);
lower_bound_end := array(ifo["wick_y",i,1,0]+b_w_x,ifo["wick_y",i,1,1]+b_w_y);
cvs.moveto(lower_bound_start);
cvs.lineto(lower_bound_end);
medians_start := array(ifo["medians",i,0]-b_w_x,ifo["medians",i,1]-b_w_y);
medians_end := array(ifo["medians",i,0]+b_w_x,ifo["medians",i,1]+b_w_y);
cvs.moveto(medians_start);
cvs.lineto(medians_end);
end else
begin
cvs.moveto(array(ifo["xy0",i,0],ifo["xy0",i,1]));
cvs.lineto(array(ifo["xy0",i,0],ifo["xy0",i,1]));
end
end
ifo["barrgn"] := barrgn;
end
function paint_pie(cvs,xys,ifo); //画饼
begin
cvs.brush.color := ifo["bkcolor"];
cvs.brush.style := tgc_BS_SOLID;
cvs.pen.style := 0;
cvs.pen.color := ifo["color"];
cvs.draw_polygon().points(xys).draw();
end
function paint_sunburst(cvs,xys,ifo);//画饼
begin
return paint_pie(cvs,xys,ifo);
end
function paint_tree(cvs,xys,ifo); //画树
begin
//cvs.brush.color := ifo["bkcolor"];
//cvs.pen.style := 0;
//cvs.pen.color := ifo["color"];
//cvs.pen.color := 0x0000ff;
tree := cvs.draw_bezier();
//tree.startpoint(xys[0]);
tree.addpoints(xys);
//tree.addpoints(array(xys[1]));
//tree.addpoints(array(xys[2]));
//tree.addpoints(array(xys[3]));
tree.draw();
end
function mult_str(s,n);
begin
r := s;
for i := 2 to n do //exp
begin
r+=s;
end
return r;
end
function get_default_color_list(); //获取默认的颜色列表
begin
//return array(0xc67054, 0x75cc91, 0x58c8fa, 0x6666ee, 0xdec073, 0x72a23b, 0x5284fc, 0xb4609a, 0xcc7cea);
return array(0x00CED1,0xFA8072,0x00BFFF,0xFFFFE0,0xF0FFFF,0xFDF5E6,0xFAF0E6,0xFF8C00,0xC0C0C0,0x008B8B,0xE6E6FA,0xF5DEB3,0xE9967A,0xFF00FF,0x9400D3,0x00FF00,0xDC143C,0xFF4500,0xD8BFD8,0x6B8E23,0x1E90FF,0x708090,0x00FA9A,0xFAEBD7,0xADD8E6,0x8B4513,0xFFFAFA,0x8A2BE2,0x4169E1,0x000080,0xF0FFF0,0x191970,0xF4A460,0xFFDEAD,0x0000CD,0xF5FFFA,0x8B0000,0xFF7F50,0xBA55D3,0x7CFC00,0xFFE4C4,0xDCDCDC,0x87CEEB,0x696969,0x808080,0xFF1493,0x48D1CC,0xFFF0F5,0x00008B,0xDDA0DD,0xFFA07A,0x4682B4,0xFFDAB9,0x6495ED,0xFFC0CB,0x008000,0xADFF2F,0xBDB76B,0x66CDAA,0xEE82EE,0xFFFF00,0x556B2F,0xFFB6C1,0x20B2AA,0xDB7093,0xFFFAF0,0xB22222,0x6A5ACD,0xFF6347,0x778899,0xFAFAD2,0x800080,0x00FFFF,0x006400,0x8FBC8F,0xFFFFFF,0x40E0D0,0xFFD700,0x00FF7F,0xF8F8FF,0xA0522D,0x87CEFA,0xDEB887,0x000000,0x0000FF,0xD2691E,0xFF00FF,0xF5F5F5,0xFFF5EE,0x98FB98,0xFFF8DC,0xF0F8FF,0x800000,0xBC8F8F,0x8B008B,0xD3D3D3,0x9ACD32,0xA9A9A9,0xFF69B4,0xAFEEEE,0xB8860B,0xD2B48C,0xF5F5DC,0x5F9EA0,0x228B22,0x2F4F4F,0xA52A2A,0x7FFFD4,0x90EE90,0x7B68EE,0xB0C4DE,0xF08080,0x32CD32,0x483D8B,0x9370DB,0xCD5C5C,0xDA70D6,0x808000,0x008080,0xFFE4B5,0xC71585,0x9932CC,0xFFEBCD,0xE0FFFF,0x00FFFF,0x4B0082,0xEEE8AA,0xFFE4E1,0xFFEFD5,0xDAA520,0x2E8B57,0xF0E68C,0x7FFF00,0xB0E0E6,0xFFFFF0,0xFFA500,0xFF0000,0xCD853F,0x3CB371,0xFFFACD);
end
initialization
finalization
end.