/// <summary> /// Returns the leaf Rectangle that contains the location /// </summary> /// <param name="location"></param> /// <returns></returns> public TreeRectangle LocationInsideLeafRectangle(Point location) { Vector2 lowerLeft = new Vector2(iLowerLeft.X * iScale.X, iLowerLeft.Y * iScale.Y); Vector2 upperRight = new Vector2(iUpperRight.X * iScale.X, iUpperRight.Y * iScale.Y); if (lowerLeft.X <= location.X && upperRight.X >= location.X && lowerLeft.Y <= location.Y && upperRight.Y >= location.Y) { if (iChildRectangles.Count == 0) { return(this); } else { foreach (TreeRectangle child in iChildRectangles) { TreeRectangle result = child.LocationInsideLeafRectangle(location); // if found if (result != null) { return(result); } } } } return(null); }
/// <summary> /// Checks whether the row can be continued, or is it better to start a new one. /// </summary> /// <param name="aRow">List of values</param> /// <param name="aHead">The proposed new row member</param> /// <param name="aWidth">Width of the current cell</param> /// <returns>True if the row should be continued</returns> private bool ContinueRow(List <TreeRectangle> aRow, TreeRectangle aChild, TreeRectangle aParent) { float width = aParent.MinSideLength(); float area = aChild.GetArea(); int count = aRow.Count; if (count == 0) { return(true); } float widthSqr = width * width; //First ratio float sum = Sum(aRow); float sumSqr = sum * sum; float rMax = aRow[0].GetArea(); float rMin = aRow[count - 1].GetArea(); float max = (widthSqr * rMax) / sumSqr; float min = sumSqr / (widthSqr * rMin); float firstMax = Math.Max(max, min); //Second ratio sum += area; sumSqr = sum * sum; rMax = Math.Max(rMax, area); rMin = Math.Min(rMin, area); max = (widthSqr * rMax) / sumSqr; min = sumSqr / (widthSqr * rMin); float secondMax = Math.Max(max, min); //does the aspect ratio improve or not? return(firstMax >= secondMax); }
/// <summary> /// /// </summary> /// <param name="location"></param> public void IncreaseLevel(Point location) { // If already zoomed, quit if (iZoomIn) { return; } TreeRectangle selectedRectangle = null; foreach (TreeRectangle rectangle in iCurrentRootRectangle.GetChildren()) { selectedRectangle = rectangle.LocationInsideRectangle(location); if (selectedRectangle != null) { break; } } if (selectedRectangle != null) { this.iCurrentRootRectangle = selectedRectangle; } /************************************************************************/ /* THE SAME AS IN SIZECHANGED!!! CREATE INVALIDATEDATA / INVALIDATEVIEW */ /************************************************************************/ UpdateData(); UpdateScale(); UpdateDrawingArea(); this.Invalidate(); iZoomIn = true; }
/// <summary> /// /// </summary> /// <param name="location"></param> /// <returns></returns> private object OnHoverRectangle(Point location) { TreeRectangle rectangle = iCurrentRootRectangle.LocationInsideLeafRectangle(location); if (rectangle != null) { return(rectangle.Data); } return(null); }
/// <summary> /// Creates the Tooltip Data /// </summary> /// <param name="aRectangle"></param> /// <param name="aDataCube"></param> /// <param name="aToolTipComponents"></param> private void BuildToolTipData(TreeRectangle aRectangle, object[, ,] aDataCube, List <GMSToolTipComponent> aToolTipComponents, int aRow) { string toolTip = ""; foreach (GMSToolTipComponent toolTipComponent in aToolTipComponents) { toolTip += toolTipComponent.iPrefix + ": " + aDataCube[toolTipComponent.iColumnIndex, aRow, 0] + " " + toolTipComponent.iSuffix + "\n"; } aRectangle.Data = toolTip; }
/// <summary> /// /// </summary> public void DecreaseLevel() { if (iZoomIn) { iZoomIn = false; // switch to the original root iCurrentRootRectangle = iRootRectangle; UpdateData(); UpdateScale(); UpdateDrawingArea(); this.Invalidate(); } }
/// <summary> /// Parse the whole tree squerifying all the nodes /// </summary> /// <param name="aRectangle">current rectangle</param> public void SquarifyTree(TreeRectangle aRectangle) { if (0 == aRectangle.GetChildren().Count) { return; } List <TreeRectangle> row = new List <TreeRectangle>(); List <TreeRectangle> copyOfChildren = new List <TreeRectangle>(aRectangle.GetChildren()); SquarifyLevel(copyOfChildren, row, aRectangle); foreach (TreeRectangle rect in aRectangle.GetChildren()) { SquarifyTree(rect); } }
/// <summary> /// Initializes the TreeMap from a descending order object[,,] cube /// </summary> /// <param name="aDataCube">[columns, rows, 1]</param> /// <param name="aQuantitativeDataIndex"></param> /// <param name="aOrdinalDataIndex"></param> /// <param name="aIdIndex"></param> private void InitTreeMapFromDataCube(object[, ,] aDataCube, int aQuantitativeDataIndex, int aOrdinalDataIndex, int aIdIndex, int aLeafNodeLabelIndex, List <GMSToolTipComponent> aToolTipComponents) { iRootRectangle = new TreeRectangle(0.0F); iCurrentRootRectangle = iRootRectangle; string currentGroup = (string)aDataCube[aOrdinalDataIndex, 0, 0]; TreeRectangle currentNode = new TreeRectangle(0.0F); currentNode.Label = currentGroup; // iterate through the rows for (int i = 0; i < aDataCube.GetLength(1); i++) { // if changing to a different group if (currentGroup != (string)aDataCube[aOrdinalDataIndex, i, 0]) { // only add the node to the root if any children have been created if (currentNode.GetChildren().Count != 0) { iRootRectangle.AddRectangle(currentNode); } currentNode = new TreeRectangle(0.0F); currentGroup = (string)aDataCube[aOrdinalDataIndex, i, 0]; currentNode.Label = currentGroup; } float area = Convert.ToSingle(aDataCube[aQuantitativeDataIndex, i, 0]); // only add the node if the area is bigger or equal to one if (area >= 1.0F) { TreeRectangle childRectangle = new TreeRectangle(area); childRectangle.Id = Convert.ToInt32(aDataCube[aIdIndex, i, 0]); // Tooltip Data and Label BuildToolTipData(childRectangle, aDataCube, aToolTipComponents, i); childRectangle.Label = (string)aDataCube[aLeafNodeLabelIndex, i, 0]; currentNode.AddRectangle(childRectangle); } } iRootRectangle.AddRectangle(currentNode); }
/// <summary> /// Split the input values to the rectangle /// </summary> /// <param name="aChildren">input values(the tree) </param> /// <param name="aRow">The current work row</param> /// <param name="aWidth">The length of the current rectangle's max side</param> public void SquarifyLevel(List <TreeRectangle> aChildren, List <TreeRectangle> aRow, TreeRectangle aRectangle) { if (0 == aChildren.Count) { aRectangle.LayOutRow(aRow); return; } TreeRectangle head = aChildren[0]; if (ContinueRow(aRow, head, aRectangle)) { aRow.Add(head); aChildren.RemoveAt(0); SquarifyLevel(aChildren, aRow, aRectangle); } else { aRectangle.LayOutRow(aRow); SquarifyLevel(aChildren, new List <TreeRectangle>(), aRectangle); } }
/// <summary> /// Add an existing rectangle to current rectangles childrens /// </summary> /// <param name="aRectangle">a rectangle to be added to the child list</param> public void AddRectangle(TreeRectangle aRectangle) { iArea += aRectangle.iArea; iChildRectangles.Add(aRectangle); }