Custom Theme and Legend in Ajax Page

May 22, 2008 at 8:37 AM

Hi there,

             I am using sharpmap 0.9.0.0 version dll

             I have  used my own custom theme rendering as follows :
 
         SharpMap.Layers.VectorLayer AdminBnd = new SharpMap.Layers.VectorLayer("Resultant Layer");
        AdminBnd.DataSource = new SharpMap.Data.Providers.ShapeFile(HttpContext.Current.Server.MapPath(@"~\App_Data\Admin.shp"), true);
        SharpMap.Rendering.Thematics.CustomTheme iTheme = new SharpMap.Rendering.Thematics.CustomTheme(GetCSStyle);
        AdminBnd.Theme = iTheme;
        
  The GetCSStyle method is as follows :

 public static SharpMap.Styles.VectorStyle GetCSStyle(SharpMap.Data.FeatureDataRow dr)
     
 {
      
          
        SharpMap.Styles.VectorStyle style = new SharpMap.Styles.VectorStyle();

        if (dr["FIELD1"].ToString() == "800-1000")
        {
            style.Fill = Brushes.Red;
            return style;
        }

        else if (dr["FIELD2"].ToString() == "ABOVE 1000")
        {
            style.Fill = Brushes.Thistle;
            return style;
        }

        else if (dr["FIELD3"].ToString() == "BELOW 800")
        {
            style.Fill = Brushes.Turquoise;
            return style;
        }

        else
        {
            style.Fill = Brushes.LightGray;
            return style;
        }

       
     }    

Everything works fine - the AdminBnd layer is rendered by different colors

when this is implemented along with displaying a Legend to display with the rendered colors(different colors  in a sinlge layer) as mentioned above in an AJAX page- the problem arises as "style" needs to be derived from the customtheme assigned to the layer

plz suggest any alternative ways of filling the style from the theme
 
code for generating the Legend is based on MNorm_Ajax3 sample code found in one of the listings

private HtmlGenericControl LegendDiv(SharpMap.Layers.ILayer myLayer)
    {
        HtmlGenericControl legendDiv = new HtmlGenericControl("div");
        legendDiv.Style.Add("width", "2em");
        legendDiv.Style.Add("overflow", "hidden");
        legendDiv.Style.Add("position", "absolute");
        legendDiv.Style.Add("margin-left", "0.5em");
        legendDiv.Style.Add("margin-bottom", "0px");
        if (myLayer.GetType() == typeof(SharpMap.Layers.VectorLayer))
        {
            SharpMap.Layers.VectorLayer myVectorLayer = (myLayer as SharpMap.Layers.VectorLayer);
            SharpMap.Styles.VectorStyle myStyle = new SharpMap.Styles.VectorStyle();

            if (myVectorLayer.Theme != null)
            {
                if (myVectorLayer.Theme.GetType() == typeof(SharpMap.Rendering.Thematics.CustomTheme))
                {
                    SharpMap.Rendering.Thematics.CustomTheme myTheme = (myVectorLayer.Theme as SharpMap.Rendering.Thematics.CustomTheme);
                    myStyle = (myTheme.DefaultStyle as SharpMap.Styles.VectorStyle);
                   
                }
                else if (myVectorLayer.Theme.GetType() == typeof(SharpMap.Rendering.Thematics.GradientTheme))
                {
                    SharpMap.Rendering.Thematics.GradientTheme myTheme = (myVectorLayer.Theme as SharpMap.Rendering.Thematics.GradientTheme);
                    myStyle = (myTheme.MinStyle as SharpMap.Styles.VectorStyle);
                }
            }
            else
                myStyle = myVectorLayer.Style;

            if (myStyle.Outline.Color.Name.ToString() != "Black")
            {
                string lineStyle = (myStyle.Outline.DashStyle.ToString() == "Dash") ? "dotted" : "solid";
                legendDiv.Style.Add("border", lineStyle + " " + myStyle.Outline.Width.ToString() + "px " + ColorToHex(myStyle.Outline.Color));
                legendDiv.Style.Add("height", "1em");
            }
            else
            {
                string lineStyle = (myStyle.Line.DashStyle.ToString() == "Dash") ? "dotted" : "solid";
                legendDiv.Style.Add("border-bottom", lineStyle + " " + myStyle.Line.Width.ToString() + "px " + ColorToHex(myStyle.Line.Color));
               legendDiv.Style.Add("height", "0.8em");
            }

            System.Drawing.SolidBrush fillBrush = (myVectorLayer.Style.Fill as System.Drawing.SolidBrush);
            if (fillBrush.Color.Name.ToString() != "Black")
            {
                HtmlGenericControl fillDiv = new HtmlGenericControl("div");
                fillDiv.Style.Add("border-left", "solid 2em " + ColorToHex(fillBrush.Color));
                fillDiv.Style.Add("height", "1.2em");
                fillDiv.Style.Add("overflow", "hidden");
                fillDiv.Style.Add("opacity ", ColorAlpha(fillBrush.Color) + "%");
                fillDiv.Style.Add("filter", "ALPHA(opacity=" + ColorAlpha(fillBrush.Color) + ")");
                legendDiv.Controls.Add(fillDiv);
            }
        }
        return legendDiv;
    }

The code above checks the theme assigend to it and if it is a custom theme the defaultstyle is assigned rather than the unique style in the GetCSStyle... how to get the style from the customtheme .

Coordinator
May 22, 2008 at 9:41 AM
Hi Sirisha, have a go with this - it is untested but should work ;) 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpMap.Styles;
using SharpMap.Data;
using System.Drawing;

namespace CustomThemeExample
{
    public class TrackingTheme
    {
        private Dictionary<string, VectorStyle> _usedStyles = new Dictionary<string, VectorStyle>();
        public IEnumerable<VectorStyle> UsedStyles
        {
            get
            {
                foreach (VectorStyle s in _usedStyles.Values)
                    yield return s;
            }
        }

        public VectorStyle GetCSStyle(FeatureDataRow dr)
        {

            VectorStyle style = new VectorStyle();
            if (dr["FIELD1"].ToString() == "800-1000")
            {
                style.Fill = Brushes.Red;
                SaveStyle("800-1000", style);
                return style;
            }

            else if (dr["FIELD2"].ToString() == "ABOVE 1000")
            {
                style.Fill = Brushes.Thistle;
                SaveStyle("ABOVE 1000", style);

                return style;
            }

            else if (dr["FIELD3"].ToString() == "BELOW 800")
            {
                style.Fill = Brushes.Turquoise;
                SaveStyle("BELOW 800", style);
                return style;
            }

            else
            {
                style.Fill = Brushes.LightGray;
                SaveStyle("default", style);
                return style;
            }

        }

        private void SaveStyle(string discriminator, VectorStyle style)
        {
            if (!_usedStyles.ContainsKey(discriminator))
                _usedStyles.Add(discriminator, style);
        }

    }
}

/*NEXT CLASS*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpMap.Layers;
using SharpMap.Data.Providers;
using SharpMap.Rendering.Thematics;
using SharpMap.Styles;

 
namespace CustomThemeExample
{
    class Test
    {
        public Test()
        {

            VectorLayer l = new VectorLayer("myLayer", new ShapeFile("mypath.shp"));

            TrackingTheme tracker = new TrackingTheme();
            l.Theme = new CustomTheme(tracker.GetCSStyle);

 

            /*
             * ...
             *
             * Render your map
             *
             *
             */

            foreach (VectorStyle v in tracker.UsedStyles)
            {
                //do something
            }

        }
    }
}

hth jd

May 27, 2008 at 7:38 AM

hi John,

i have been working on a similar requirement to display a legend in an Ajax page....(i'm using version 0.9.0.0)

i have few questions, i would be grateful if you could help me out

1. Is there a way to assign "Style.Fill" for a vector layer with more than one colors based on attribute values without using Custom Theme

2. A Custom theme renders different colors based on Attribute values but the vectorstyle cannot be extracted from the Custom theme

    Theme and Style are two different things and cannot be synchronously in this case to display the Legend which is dependent on vectorLayer Style property
 
        can we retreive something like

         VectorLayer l = new VectorLayer("myLayer", new ShapeFile("mypath.shp"));
         TrackingTheme tracker = new TrackingTheme();
            l.Theme = new CustomTheme(tracker.GetCSStyle);

               l.Style =l.Theme.GetStyle();   // Which returns a vectorStyle without passing FeatureDataRow since Theme already has the FeatureDataRow being passed to it

3. How to Label the Legend displaying text what a particular color depicts

4. Is there any demo project available(from any old posts which i might have missed out) which has this Legend with CustomTheme displayed in Ajax page

Plz correct me if i'm going wrong anywhere

also i'm confused why there is not much importance to Legend tool in the SharpMap development as it is the basic and important element when we talk of displaying maps

there are many posts about the SharpMap Version 2.0 which incorporates many of the functionalities but is still not yet complete and also as per codekaizen mention in one of the post SharpMap 2.0 is much inclined towards desktop and Version 0.9 is much towards the Web

What's your say?

Thanks

Coordinator
May 27, 2008 at 9:41 AM
1. Is there a way to assign "Style.Fill" for a vector layer with more than one colors based on attribute values without using Custom Theme

There is nothing to stop you from programatically change the style.Fill property - I cant really think of a situation where this would be preferred over a custom theme though.

2. A Custom theme renders different colors based on Attribute values but the vectorstyle cannot be extracted from the Custom theme

I'm not sure I follow your meaning here - A theme creates styles based on attributes - the only way of getting every style out of a theme is to call it with a set of FeatureDataRows  containing every discriminator - or to look at the code and build it manually.  

3. How to Label the Legend displaying text what a particular color depicts

 
In the example above I used the discriminator value as a key in the dictionary - You could make UsedStyles return IEnumerable<KeyValuePair<string, VectorStyle>> or the dictionary itself and have access to the key that way.

4. Is there any demo project available(from any old posts which i might have missed out) which has this Legend with CustomTheme displayed in
Ajax page

Very possibly, I must confess I dont know a lot of the demos. The code above was just a quick and dirty starting point showing how it  _could_ be done. I havent actually completed it. Perhaps when I have some spare time I will flesh it out a bit.

also i'm confused why there is not much importance to Legend tool in the SharpMap development as it is the basic and important element when we talk of displaying maps

IMHO sharpmap is a set of tools to help you solve domain problems - The actual legend appropriate for one useage is probably inappropriate for the next - so it is left to the person who knows what they need to actually make it. The tools provide extension points where they can be extended to cope with these individual needs. Personally I dont use any of the sharpmap ajax stuff.. 


there are many posts about the SharpMap Version 2.0 which incorporates many of the functionalities but is still not yet complete and also as per codekaizen mention in one of the post SharpMap 2.0 is much inclined towards desktop and Version 0.9 is much towards the Web.
 
When the time is right V2 will support the web just as much as the desktop - we just need to have one platform firming up before we cloud the water too much with the next..  But it will be there..


May 28, 2008 at 4:15 AM
thanks John