在 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;width: 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-width: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-width: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.运行效果

posted @ 2013-01-07 13:12  E=mc&#178;  阅读(2924)  评论(2编辑  收藏  举报