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.