zoukankan      html  css  js  c++  java
  • 在 Asp.net 中使用 SVG生成家族树图形

    根据后台树形结构数据表创建家族树形图

    1.数据库结构

    其中NodePkey存储父节点PKey,如若是根节点则为0

    2.使用SVG动态创建树图形

    (1)根据数据库原始数据获取,家族树列表,家族按家族代及每代人数表。根绝两基础数据集合,动态计算出布局以及需要连线的具体位置。

     private ObjectTable ConvertData()
        {
            ObjectTable treeDataTable = new ObjectTable();
            DataTable treeData = new DataTable();
            DataTable treeLev = new DataTable();
    
            #region Load data.
            if (IsLogin)
            {
                string dataSqlLogin = "SELECT PKey,NodePKey,IsFAlive,IsMAlive,Father,Mather,Lev"
                                    + " FROM View_FaimlyTree"
                                    + " WHERE FirstName=@FirstName AND PartPKey=@PartPKey"
                                    + " Order By Lev,NodePKey";
                ODBParameterCollection opcData = new ODBParameterCollection();
                opcData.Add("@FirstName", DropDownList3.SelectedValue);
                opcData.Add("@PartPKey", DropDownList2.SelectedValue);
                treeData = DataAccess.ExecuteDataTable(dataSqlLogin, opcData);
                string levSqlLogin = "SELECT Count(Lev) AS C,Lev FROM View_FaimlyTree"
                                   + "  WHERE FirstName=@FirstName AND PartPKey=@PartPKey"
                                   + " GROUP BY Lev Order By C DESC";
                ODBParameterCollection opcLev = new ODBParameterCollection();
                opcLev.Add("@FirstName", DropDownList3.SelectedValue);
                opcLev.Add("@PartPKey", DropDownList2.SelectedValue);
                treeLev = DataAccess.ExecuteDataTable(levSqlLogin, opcLev);
            }
            else
            {
                string dataSqlLogin = "SELECT PKey,NodePKey,IsFAlive,IsMAlive,Father,Mather,Lev"
                                    + " FROM View_FaimlyTree"
                                    + " WHERE FirstName=@FirstName AND PartPKey=@PartPKey AND ISFAlive = 0 AND IsMAlive = 0"
                                    + " Order By Lev,NodePKey";
                ODBParameterCollection opcData = new ODBParameterCollection();
                opcData.Add("@FirstName", DropDownList3.SelectedValue);
                opcData.Add("@PartPKey", DropDownList2.SelectedValue);
                treeData = DataAccess.ExecuteDataTable(dataSqlLogin, opcData);
                string levSqlLogin = "SELECT Count(Lev) AS C,Lev FROM View_FaimlyTree"
                                   + "  WHERE FirstName=@FirstName AND PartPKey=@PartPKey AND ISFAlive = 0 AND IsMAlive = 0"
                                   + " GROUP BY Lev Order By C DESC";
                ODBParameterCollection opcLev = new ODBParameterCollection();
                opcLev.Add("@FirstName", DropDownList3.SelectedValue);
                opcLev.Add("@PartPKey", DropDownList2.SelectedValue);
                treeLev = DataAccess.ExecuteDataTable(levSqlLogin, opcLev);
            }
            #endregion
    
            #region Load data withe sytle,lines.
    
            if (treeData.Rows.Count > 0)
            {
    
                int maxWidth = ((int)treeLev.Rows[0]["C"]) * 80;
                int middleLeft = maxWidth / 2 - 30;
                int count = 0;
                int lev = 0;
                //--------control the modle of the node.
                int width = 120;
                int innerWidth = 100;
                int innerHeight = 50;
                int height = 80;
                //-------------------------------------.
                if (maxWidth < 500)
                {
                    middleLeft = 470;
                }
    
                #region Math the Point should be lining.
    
                foreach (DataRow treeDataDr in treeData.Rows)
                {
                    if (lev != (int)treeDataDr["Lev"])
                    {
                        count = 0;
                    }
                    else
                    {
                        count++;
                    }
    
                    lev = (int)treeDataDr["Lev"];
    
                    if (lev == 0)
                    {
                        count--;
                    }
                    int left = middleLeft - ((width / 2) * ((int)treeLev.Select("Lev ='" + lev.ToString() + "'")[0]["C"]) - innerWidth / 2);
                    ObjectRow objRow = new ObjectRow();
                    Point tPoint = new Point();
                    Point dPoint = new Point();
                    int top = ((int)treeDataDr["Lev"]) * height;
                    tPoint.X = left + width * count + innerWidth / 2;
                    tPoint.Y = top;
                    dPoint.X = left + width * count + innerWidth / 2;
                    dPoint.Y = top + height / 2 + 10;
                    objRow.Id = treeDataDr["PKey"].ToString();
                    objRow["Father"] = new ObjectCell(treeDataDr["Father"]);
                    objRow["Mather"] = new ObjectCell(treeDataDr["Mather"]);
                    objRow["IsFAlive"] = new ObjectCell(treeDataDr["IsFAlive"]);
                    objRow["IsMAlive"] = new ObjectCell(treeDataDr["IsMAlive"]);
                    objRow["Lev"] = new ObjectCell(treeDataDr["Lev"]);
                    objRow["NodePKey"] = new ObjectCell(treeDataDr["NodePKey"]);
                    objRow["Count"] = new ObjectCell(count);
                    objRow["tPoint"] = new ObjectCell(tPoint);
                    objRow["dPoint"] = new ObjectCell(dPoint);
                    objRow["sPoint"] = new ObjectCell(new Point(0, 0));
                    objRow["Y"] = new ObjectCell(top);
                    objRow["X"] = new ObjectCell(left + width * count);
                    objRow["Line"] = new ObjectCell("");
                    objRow["innerWidth"] = new ObjectCell(innerWidth);
                    objRow["innerHeight"] = new ObjectCell(innerHeight);
                    treeDataTable.Rows.Add(objRow);
                }
                #endregion
    
                #region lining.
    
                foreach (ObjectRow or in treeDataTable.Rows)
                {
                    if (or["NodePKey"].value.ToString().Trim() != "0")
                    {
                        Point sPoint = new Point();
                        Point ePoint = new Point();
                        ePoint = (Point)or["tPoint"].value;
                        sPoint = (Point)treeDataTable.Rows.Find(delegate(ObjectRow n) { return n.Id == or["NodePKey"].ToString(); })["dPoint"].value;
                        or["sPoint"] = new ObjectCell(sPoint);
                    }
                }
                #endregion
            }
    
            #endregion
    
            return treeDataTable;
        }

    (2) 转换数据加入SVG标签以及SVG连线

    private void SVGDraw(ObjectTable data)
        {
            // rect : X,Y,width,height,F-X,F-Y,M-X,F-Y,F,M
            string nodeBlock = "<svg version='1.1' style='position:absolute; 100%; height: 100%' xmlns:svg='http://www.w3.org/2000/svg'>"
                             + "<rect x='{0}' y='{1}' rx='5' ry='5' width='{2}' height='{3}'"
                             + "style='fill:#00CC99;stroke:black;text-align:center;stroke-1;opacity:1'/>"
                             + "<text x='{4}' y='{5}' dx='5' dy='2'  textLength='90'>父:{8}</text>"
                             + "<text x='{6}' y='{7}' dx='5' dy='2'  textLength='90'>母:{9}</text></svg>";
    
            string lineBlock = "<svg width='100%' style='position:absolute;' height='100%' version='1.1' xmlns='http://www.w3.org/2000/svg'>"
                             + "<line x1='{0}' y1='{1}' x2='{2}' y2='{3}' style='stroke:rgb(99,99,99);stroke-1'/></svg>";
    
            foreach (ObjectRow or in data.Rows)
            {
                int X = (int)or["X"].value;
                int Y = (int)or["Y"].value;
                int width = (int)or["innerWidth"].value;
                int height = (int)or["innerHeight"].value;
                int F_X = (int)or["X"].value;
                int F_Y = (int)or["Y"].value + 20;
                int M_X = (int)or["X"].value;
                int M_Y = (int)or["Y"].value + 40;
                object father = or["Father"].value;
                object mather = or["Mather"].value;
                int x0 = ((Point)or["sPoint"].value).X;
                int y0 = ((Point)or["sPoint"].value).Y;
                int x1 = ((Point)or["tPoint"].value).X;
                int y1 = ((Point)or["tPoint"].value).Y;
                if (or["NodePKey"].value.ToString().Trim() != "0")
                {
                    or["NodeBlock"] = new ObjectCell(string.Format(nodeBlock, X, Y, width, height, F_X, F_Y, M_X, M_Y, father, mather));
                    or["LineBlock"] = new ObjectCell(string.Format(lineBlock, x0, y0, x1, y1));
                }
                else
                {
                    or["NodeBlock"] = new ObjectCell(string.Format(nodeBlock, X, Y, width, height, F_X, F_Y, M_X, M_Y, father, mather));
                    or["LineBlock"] = new ObjectCell("");
                }
            }
    
            #region load template.
    
            string templatePath = Page.MapPath("~/Templates/Tree.template");
            TemplateManager templateManager = TemplateManager.FromFile(templatePath);
            templateManager.SetValue("Data", data);
            output = templateManager.Process();
    
            #endregion
        }

    3.运行效果

    博客不易,转载请注明出处。Binarysoft.
  • 相关阅读:
    零拷贝
    RxJava2源码解析
    一次博客崩溃日志分析
    Spring循环依赖的解决
    解决网络卡顿问题
    软工第一次作业
    3月26-27号训练笔记
    Codeforces Round #708 (Div. 2)题解A,B,C1,C2,E1,E2
    求出所有LIS的可行起点
    2020小米邀请赛决赛补题G,I,J(三DP)
  • 原文地址:https://www.cnblogs.com/BinaryBoy/p/2849108.html
Copyright © 2011-2022 走看看