ThinkGeo.com    |     Documentation    |     Premium Support

Placing text labels manually

I have world point, and I'm drawing a label at that location with the Canvase.DrawTextWithWorldCoordinate(...).


My users have the ability to set the alignment of that text relative to the point... TopCenter, TopLeft, etc, etc.    Do you have anything built-in to do that easily, or must I do something to get the size of the text (in pixels), and apply x/y offsets in screen coordinates?



 Ted,


 
  The alignment logic is in the PositionStyle which is the parent of the TextStyle.  If you do not use either of those two styles as the base you will need to do it yourself.  To help you along I have created a self contained style that encapsulates the alignment logic.  You should be able to quickly incorporate it into your own style.  Let me know if you have any questions.
 


    public class PlacementStyle : Style
    {
        private GeoFont font;
        private Single xOffsetInPixel;
        private PointPlacement pointPlacement;
        private GeoSolidBrush geoSolidBrush;
        private string textColumn;

        public PlacementStyle()
            : base()
        {
            geoSolidBrush = new GeoSolidBrush(GeoColor.StandardColors.Black);
            xOffsetInPixel = 0;
            yOffsetInPixel = 0;
            pointPlacement = PointPlacement.Center;
            font = new GeoFont("Arial", 15);
            textColumn = string.Empty;
        }

        public string TextColumn
        {
            get { return textColumn; }
            set { textColumn = value; }
        }

        public GeoSolidBrush FillSolidBrush
        {
            get { return geoSolidBrush; }
            set { geoSolidBrush = value; }
        }

        public Single XOffsetInPixel
        {
            get { return xOffsetInPixel; }
            set { xOffsetInPixel = value; }
        }
        private Single yOffsetInPixel;

        public Single YOffsetInPixel
        {
            get { return yOffsetInPixel; }
            set { yOffsetInPixel = value; }
        }

        public PointPlacement PointPlacement
        {
            get { return pointPlacement; }
            set { pointPlacement = value; }
        }

        public GeoFont Font
        {
            get { return font; }
            set { font = value; }
        }

        protected override void DrawCore(System.Collections.Generic.IEnumerable<Feature> features, GeoCanvas canvas, System.Collections.ObjectModel.Collection<SimpleCandidate> labelsInThisLayer, System.Collections.ObjectModel.Collection<SimpleCandidate> labelsInAllLayers)
        {
            foreach (Feature feature in features)
            {
                if (feature.GetWellKnownType() == WellKnownType.Point)
                {
                    ScreenPointF point = ExtentHelper.ToScreenCoordinate(canvas.CurrentWorldExtent, (PointShape)feature.GetShape(), canvas.Width, canvas.Height);

                    DrawingRectangleF size = canvas.MeasureText(feature.ColumnValues[textColumn], font);
                    double width = size.Width;
                    double height = size.Height;

                    PointShape upperLeftPoint = new PointShape(point.X + xOffsetInPixel * (canvas.Dpi / 96.0), point.Y - yOffsetInPixel * (canvas.Dpi / 96.0));
                    upperLeftPoint = GetNewUpperLeftPointByPlacement(upperLeftPoint, width, height, pointPlacement);

                    canvas.DrawTextWithScreenCoordinate(feature.ColumnValues[textColumn], font, geoSolidBrush, (float)upperLeftPoint.X, (float)upperLeftPoint.Y, DrawingLevel.LabelLevel);
                }
            }
        }

        private static PointShape GetNewUpperLeftPointByPlacement(PointShape upperLeftPoint, double width, double height, PointPlacement placementOfPoint)
        {
            double upperLeftPointX = upperLeftPoint.X;
            double upperLeftPointY = upperLeftPoint.Y;
            PointShape newUpperLeftPoint = null;

            switch (placementOfPoint)
            {
                case PointPlacement.UpperRight:
                    newUpperLeftPoint = new PointShape(upperLeftPointX, upperLeftPointY - height);
                    break;

                case PointPlacement.CenterRight:
                    newUpperLeftPoint = new PointShape(upperLeftPointX, upperLeftPointY - height * 0.5);
                    break;

                case PointPlacement.LowerRight:
                    newUpperLeftPoint = new PointShape(upperLeftPointX, upperLeftPointY);
                    break;

                case PointPlacement.UpperLeft:
                    newUpperLeftPoint = new PointShape(upperLeftPointX - width, upperLeftPointY - height);
                    break;

                case PointPlacement.CenterLeft:
                    newUpperLeftPoint = new PointShape(upperLeftPointX - width, upperLeftPointY - height * 0.5);
                    break;

                case PointPlacement.LowerLeft:
                    newUpperLeftPoint = new PointShape(upperLeftPointX - width, upperLeftPointY);
                    break;

                case PointPlacement.UpperCenter:
                    newUpperLeftPoint = new PointShape(upperLeftPointX - width * 0.5, upperLeftPointY - height);
                    break;

                case PointPlacement.Center:
                    newUpperLeftPoint = new PointShape(upperLeftPointX - width * 0.5, upperLeftPointY - height * 0.5);
                    break;

                case PointPlacement.LowerCenter:
                    newUpperLeftPoint = new PointShape(upperLeftPointX - width * 0.5, upperLeftPointY);
                    break;

                default:
                    break;
            }

            return newUpperLeftPoint;
        }

        protected override Collection<string> GetRequiredColumnNamesCore()
        {
            Collection<string> requiredColumns = base.GetRequiredColumnNamesCore();

            requiredColumns.Add(textColumn);

            return requiredColumns;
        }
    }


 
David

The code in DrawCore was exactly what I was looking for, David.    Thank you.    I was not aware of the PointPlacement style.   Thanks for pointing it out. 
  
 One suggestion, after working with it a bit…  maybe you could provide an overload on the Canvas.DrawText* methods that accepts a point placement.   This would make it easier for people that want to draw text manually, rather than use a features collection. 
  
 Thanks again for the great help!

Ted, 
  
 We’re glad it’s working with you. And your suggestion is very good, we will consider it if we have time. 
  
 Thanks 
 James