Source Code ServiceEdition ProjectTemplates DemographicMap CS.zip
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace ThinkGeo.MapSuite.USDemographicMap
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
MainForm.cs
using System;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;
using ThinkGeo.MapSuite.Core;
using ThinkGeo.MapSuite.USDemographicMap.Properties;
namespace ThinkGeo.MapSuite.USDemographicMap
{
public partial class MainForm : Form
{
private bool avoidUpdatingMap;
private DemographicStyleBuilder currentStyleBuilder;
private ShapeFileFeatureLayer censusStateFeatureLayer;
private ShapeFileFeatureLayer customFeatureLayer;
private ShapeFileFeatureLayer currentFeatureLayer;
private MapEngine mapEngine;
private Bitmap bitmap;
public MainForm()
{
InitializeComponent();
mapEngine = new MapEngine();
}
private void MainForm_Load(object sender, EventArgs e)
{
bitmap = new Bitmap(MapPictureBox.Width, MapPictureBox.Height);
mapEngine.CurrentExtent = ExtentHelper.GetDrawingExtent(new RectangleShape(-124.005659494527, 62.0896678017427, -70.8601705812137, 13.9927294319521), bitmap.Width, bitmap.Height);
// Add WorldMapKit Overlay
mapEngine.StaticLayers.Add(new WorldMapKitLayer());
// Add Demographic Layer
customFeatureLayer = new ShapeFileFeatureLayer();
censusStateFeatureLayer = new ShapeFileFeatureLayer(@"../../App_Data/usStatesCensus2010.shp");
censusStateFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
censusStateFeatureLayer.DrawingMarginPercentage = 100;
currentFeatureLayer = censusStateFeatureLayer;
mapEngine.DynamicLayers.Add(currentFeatureLayer);
// Initialize style builder to Thematic
currentStyleBuilder = new ThematicDemographicStyleBuilder();
currentStyleBuilder.SelectedColumns.Add("Population");
// Initialize the Legend
LegendAdornmentLayer legendAdornmentLayer = new LegendAdornmentLayer();
legendAdornmentLayer.Location = AdornmentLocation.LowerLeft;
legendAdornmentLayer.Title = new LegendItem();
legendAdornmentLayer.Title.ImageJustificationMode = LegendImageJustificationMode.JustifyImageRight;
legendAdornmentLayer.Title.TopPadding = 10;
legendAdornmentLayer.Title.BottomPadding = 10;
legendAdornmentLayer.Title.TextStyle = new TextStyle("Population", new GeoFont("Segoe UI", 12), new GeoSolidBrush(GeoColor.SimpleColors.Black));
mapEngine.AdornmentLayers.Add(legendAdornmentLayer);
// Update the controls and map.
UpdateUIControls(currentStyleBuilder);
UpdateMap(currentStyleBuilder);
LoadDataSelectorUserControls();
}
// This method would be called whenever the style needs to updated
private void dataSelectorUserControl_StyleUpdated(object sender, StyleUpdatedDataSelectorUserControlEventArgs e)
{
HideStyleControls();
DataSelectorUserControl dataSelectorUserControl = sender as DataSelectorUserControl;
LegendAdornmentLayer legendAdornmentLayer = (LegendAdornmentLayer)mapEngine.AdornmentLayers[0];
// Here we update the styleBuilder and UI according to the style builder type passed from the data selector user control.
switch (e.DemographicStyleBuilderType)
{
case DemographicStyleBuilderType.ValueCircle:
currentStyleBuilder = new ValueCircleDemographicStyleBuilder();
trackBarValueCirleRadio.Visible = true;
lblValueCircle.Visible = true;
legendAdornmentLayer.Title.TextStyle.TextColumnName = e.ActivatedStyleSelectors[0].LegendTitle;
break;
case DemographicStyleBuilderType.DotDensity:
currentStyleBuilder = new DotDensityDemographicStyleBuilder();
lblFewer.Visible = true;
lblMore.Visible = true;
trackBarDots.Visible = true;
lblDotDensityUnit.Visible = true;
legendAdornmentLayer.Title.TextStyle.TextColumnName = e.ActivatedStyleSelectors[0].LegendTitle;
break;
case DemographicStyleBuilderType.PieChart:
currentStyleBuilder = new PieChartDemographicStyleBuilder();
foreach (StyleSelectorUserControl item in e.ActivatedStyleSelectors)
{
((PieChartDemographicStyleBuilder)currentStyleBuilder).SelectedColumnAliases.Add(item.Alias);
}
if (dataSelectorUserControl != null)
legendAdornmentLayer.Title.TextStyle.TextColumnName = dataSelectorUserControl.Title;
break;
default:
currentStyleBuilder = new ThematicDemographicStyleBuilder();
lblDisplayEndColor.Visible = true;
lblColorWheelDirection.Visible = true;
cbxActiveEndColor.Visible = true;
cbxSelectColorWheelDirection.Visible = true;
legendAdornmentLayer.Title.TextStyle.TextColumnName = e.ActivatedStyleSelectors[0].LegendTitle;
lblDisplayColor.Text = Resources.Display_Start_ColorText;
break;
}
foreach (StyleSelectorUserControl activatedStyleSelector in e.ActivatedStyleSelectors)
{
currentStyleBuilder.SelectedColumns.Add(activatedStyleSelector.ColumnName);
}
// Update UI and map.
UpdateUIControls(currentStyleBuilder);
UpdateMap(currentStyleBuilder);
}
private void ActiveColorComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
currentStyleBuilder.Color = new GeoColor(cbxActiveColor.SelectedColor.R, cbxActiveColor.SelectedColor.G, cbxActiveColor.SelectedColor.B);
UpdateMap(currentStyleBuilder);
}
private void ActiveEndColorComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
ThematicDemographicStyleBuilder thematicDemographicStyle = (ThematicDemographicStyleBuilder)currentStyleBuilder;
thematicDemographicStyle.EndColor = new GeoColor(cbxActiveEndColor.SelectedColor.R, cbxActiveEndColor.SelectedColor.G, cbxActiveEndColor.SelectedColor.B);
UpdateMap(thematicDemographicStyle);
}
private void SelectColorWheelDirectionComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
ColorWheelDirection direction = ColorWheelDirection.CounterClockwise;
if (cbxSelectColorWheelDirection.SelectedIndex == 0) direction = ColorWheelDirection.Clockwise;
ThematicDemographicStyleBuilder thematicDemographicStyle = (ThematicDemographicStyleBuilder)currentStyleBuilder;
thematicDemographicStyle.ColorWheelDirection = direction;
UpdateMap(thematicDemographicStyle);
}
private void ValueCirleRadioTrackBar_ValueChanged(object sender, EventArgs e)
{
ValueCircleDemographicStyleBuilder valueCircleDemographicStyle = (ValueCircleDemographicStyleBuilder)currentStyleBuilder;
valueCircleDemographicStyle.RadiusRatio = trackBarValueCirleRadio.Value / 3d;
UpdateMap(valueCircleDemographicStyle);
}
private void DotsTrackBar_ValueChanged(object sender, EventArgs e)
{
DotDensityDemographicStyleBuilder dotDensityDemographicStyle = (DotDensityDemographicStyleBuilder)currentStyleBuilder;
dotDensityDemographicStyle.DotDensityValue = 50 * (trackBarDots.Value / 3d);
UpdateMap(dotDensityDemographicStyle);
}
private void CategoryBorder_Resize(object sender, EventArgs e)
{
pnlStyleControls.Top = pnlControl.Top + pnlControl.Height + 5;
}
private void UpdateUIControls(DemographicStyleBuilder activeStyleBuilder)
{
avoidUpdatingMap = true;
foreach (var item in cbxActiveColor.SimpleColors)
{
GeoColor styleColor = activeStyleBuilder.Color;
if (item.Value.R == styleColor.RedComponent
&& item.Value.G == styleColor.GreenComponent
&& item.Value.B == styleColor.BlueComponent)
{
cbxActiveColor.SetSelectedColor(item.Key);
break;
}
}
ThematicDemographicStyleBuilder activeThematicSetting = activeStyleBuilder as ThematicDemographicStyleBuilder;
if (activeThematicSetting != null)
{
foreach (var item in cbxActiveEndColor.SimpleColors)
{
GeoColor styleColor = activeThematicSetting.EndColor;
if (item.Value.R == styleColor.RedComponent
&& item.Value.G == styleColor.GreenComponent
&& item.Value.B == styleColor.BlueComponent)
{
cbxActiveEndColor.SetSelectedColor(item.Key);
break;
}
}
cbxSelectColorWheelDirection.SelectedIndex = (int)activeThematicSetting.ColorWheelDirection;
}
avoidUpdatingMap = false;
}
private void UpdateMap(DemographicStyleBuilder styleBuilder)
{
if (!avoidUpdatingMap)
{
Collection<Style> activeStyles = styleBuilder.GetStyles(currentFeatureLayer.FeatureSource);
currentFeatureLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Clear();
foreach (Style activeStyle in activeStyles)
{
currentFeatureLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(activeStyle);
}
LegendAdornmentLayer legendAdornmentLayer = (LegendAdornmentLayer)mapEngine.AdornmentLayers[0];
UpdateLegend(currentStyleBuilder, legendAdornmentLayer);
RefreshMap();
}
}
private void UpdateLegend(DemographicStyleBuilder styleBuilder, LegendAdornmentLayer legendAdornmentLayer)
{
legendAdornmentLayer.LegendItems.Clear();
if (styleBuilder is ThematicDemographicStyleBuilder)
{
AddThematicLegendItems(legendAdornmentLayer);
}
else if (styleBuilder is DotDensityDemographicStyleBuilder)
{
AddDotDensityLegendItems(legendAdornmentLayer);
}
else if (styleBuilder is ValueCircleDemographicStyleBuilder)
{
AddValueCircleLegendItems(legendAdornmentLayer);
}
else if (styleBuilder is PieChartDemographicStyleBuilder)
{
AddPieGraphLegendItems(legendAdornmentLayer);
}
legendAdornmentLayer.ContentResizeMode = LegendContentResizeMode.Fixed;
legendAdornmentLayer.Height = GetLegendHeight(legendAdornmentLayer);
legendAdornmentLayer.Width = GetLegendWidth(legendAdornmentLayer);
}
private void AddPieGraphLegendItems(LegendAdornmentLayer legendAdornmentLayer)
{
PieZedGraphStyle zedGraphStyle = (PieZedGraphStyle)currentStyleBuilder.GetStyles(currentFeatureLayer.FeatureSource)[0];
foreach (KeyValuePair<string, GeoColor> item in zedGraphStyle.PieSlices)
{
LegendItem legendItem = new LegendItem();
legendItem.ImageWidth = 20;
legendItem.TextRightPadding = 5;
legendItem.RightPadding = 5;
legendItem.ImageStyle = new AreaStyle(new GeoSolidBrush(item.Value));
legendItem.TextStyle = new TextStyle(item.Key, new GeoFont("Segoe UI", 10), new GeoSolidBrush(GeoColor.SimpleColors.Black));
legendAdornmentLayer.LegendItems.Add(legendItem);
}
}
private void AddValueCircleLegendItems(LegendAdornmentLayer legendAdornmentLayer)
{
ValueCircleStyle valueCircleStyle = (ValueCircleStyle)currentStyleBuilder.GetStyles(currentFeatureLayer.FeatureSource)[0];
// Here we generate 4 legend items, with the area of 160, 320, 640 and 1280 square pixels seperately.
int[] circleAreas = { 160, 320, 640, 1280 };
foreach (int circleArea in circleAreas)
{
LegendItem legendItem = new LegendItem();
double radius = Math.Sqrt(circleArea / Math.PI);
legendItem.ImageStyle = new PointStyle(PointSymbolType.Circle, new GeoSolidBrush(valueCircleStyle.InnerColor), new GeoPen(new GeoSolidBrush(valueCircleStyle.OuterColor)), (int)(radius * 2));
AreaStyle maskStyle = new AreaStyle(new GeoPen(GeoColor.StandardColors.LightGray, 1), new GeoSolidBrush(GeoColor.SimpleColors.Transparent));
legendItem.ImageMask = maskStyle;
legendItem.ImageWidth = 48;
legendItem.TextTopPadding = 16;
legendItem.TextRightPadding = 5;
legendItem.BottomPadding = 16;
legendItem.TopPadding = 16;
legendItem.RightPadding = 5;
double drawingRadius = circleArea / valueCircleStyle.DrawingRadiusRatio * valueCircleStyle.BasedScale / valueCircleStyle.DefaultZoomLevel.Scale;
double ratio = (valueCircleStyle.MaxValidValue - valueCircleStyle.MinValidValue) / (valueCircleStyle.MaxCircleAreaInDefaultZoomLevel - valueCircleStyle.MinCircleAreaInDefaultZoomLevel);
double resultValue = (drawingRadius - valueCircleStyle.MinCircleAreaInDefaultZoomLevel) * ratio + valueCircleStyle.MinValidValue;
string text = TextFormatter.GetFormatedStringForLegendItem(valueCircleStyle.ColumnName, resultValue);
legendItem.TextStyle = new TextStyle(text, new GeoFont("Segoe UI", 10), new GeoSolidBrush(GeoColor.SimpleColors.Black));
legendAdornmentLayer.LegendItems.Add(legendItem);
}
}
private void AddDotDensityLegendItems(LegendAdornmentLayer legendAdornmentLayer)
{
CustomDotDensityStyle dotDensityStyle = (CustomDotDensityStyle)currentStyleBuilder.GetStyles(currentFeatureLayer.FeatureSource)[0];
// Here we generate 4 legend items, for 5, 10, 20 and 50 points seperately.
int[] pointCounts = { 5, 10, 20, 50 };
foreach (int pointCount in pointCounts)
{
LegendItem legendItem = new LegendItem();
legendItem.ImageMask = new AreaStyle(new GeoPen(GeoColor.StandardColors.LightGray, 1), new GeoSolidBrush(GeoColor.SimpleColors.Transparent));
legendItem.ImageWidth = 48;
legendItem.TextTopPadding = 16;
legendItem.TextRightPadding = 5;
legendItem.BottomPadding = 16;
legendItem.TopPadding = 16;
legendItem.RightPadding = 5;
CustomDotDensityStyle legendDotDensityStyle = (CustomDotDensityStyle)dotDensityStyle.CloneDeep();
legendDotDensityStyle.DrawingPointsNumber = pointCount;
legendItem.ImageStyle = legendDotDensityStyle;
string text = string.Format(CultureInfo.InvariantCulture, "{0:0.####}", TextFormatter.GetFormatedStringForLegendItem(dotDensityStyle.ColumnName, (pointCount / dotDensityStyle.PointToValueRatio)));
legendItem.TextStyle = new TextStyle(text, new GeoFont("Segoe UI", 10), new GeoSolidBrush(GeoColor.SimpleColors.Black));
legendAdornmentLayer.LegendItems.Add(legendItem);
}
}
private void AddThematicLegendItems(LegendAdornmentLayer legendAdornmentLayer)
{
ClassBreakStyle thematicStyle = (ClassBreakStyle)currentStyleBuilder.GetStyles(currentFeatureLayer.FeatureSource)[0];
for (int i = 0; i < thematicStyle.ClassBreaks.Count; i++)
{
LegendItem legendItem = new LegendItem();
if (i < thematicStyle.ClassBreaks.Count)
{
legendItem.ImageStyle = thematicStyle.ClassBreaks[i].DefaultAreaStyle;
legendItem.ImageWidth = 20;
legendItem.TextRightPadding = 5;
legendItem.RightPadding = 5;
string text;
if (i != thematicStyle.ClassBreaks.Count - 1)
{
text = string.Format(CultureInfo.CurrentCulture, "{0:#,0.####} ~ {1:#,0.####}",
TextFormatter.GetFormatedStringForLegendItem(thematicStyle.ColumnName, thematicStyle.ClassBreaks[i].Value),
TextFormatter.GetFormatedStringForLegendItem(thematicStyle.ColumnName, thematicStyle.ClassBreaks[i|+ 1].Value));
}
else
{
text = string.Format(CultureInfo.CurrentCulture, "> {0:#,0.####}",
TextFormatter.GetFormatedStringForLegendItem(thematicStyle.ColumnName, thematicStyle.ClassBreaks[i].Value));
}
legendItem.TextStyle = new TextStyle(text, new GeoFont("Segoe UI", 10), new GeoSolidBrush(GeoColor.SimpleColors.Black));
}
legendAdornmentLayer.LegendItems.Add(legendItem);
}
}
private static float GetLegendWidth(LegendAdornmentLayer legendAdornmentLayer)
{
GdiPlusGeoCanvas gdiPlusGeoCanvas = new GdiPlusGeoCanvas();
LegendItem title = legendAdornmentLayer.Title;
float width = gdiPlusGeoCanvas.MeasureText(title.TextStyle.TextColumnName, new GeoFont("Segoe UI", 12)).Width + title.ImageWidth + title.ImageRightPadding + title.ImageLeftPadding + title.TextRightPadding + title.TextLeftPadding + title.LeftPadding + title.RightPadding;
foreach (LegendItem legendItem in legendAdornmentLayer.LegendItems)
{
float legendItemWidth = gdiPlusGeoCanvas.MeasureText(legendItem.TextStyle.TextColumnName, new GeoFont("Segoe UI", 10)).Width + legendItem.ImageWidth + legendItem.ImageRightPadding + legendItem.ImageLeftPadding + legendItem.TextRightPadding + legendItem.TextLeftPadding + legendItem.LeftPadding + legendItem.RightPadding;
if (width < legendItemWidth)
{
width = legendItemWidth;
}
}
return width;
}
private static float GetLegendHeight(LegendAdornmentLayer legendAdornmentLayer)
{
GdiPlusGeoCanvas gdiPlusGeoCanvas = new GdiPlusGeoCanvas();
LegendItem title = legendAdornmentLayer.Title;
float titleMeasuredHeight = gdiPlusGeoCanvas.MeasureText(title.TextStyle.TextColumnName, new GeoFont("Segoe UI", 12)).Height;
float legendHeight = new[] { titleMeasuredHeight, title.ImageHeight, title.Height }.Max();
float height = legendHeight + Math.Max(title.ImageTopPadding, title.TextTopPadding) + title.TopPadding + Math.Max(title.ImageBottomPadding, title.TextBottomPadding) + title.BottomPadding;
foreach (LegendItem legendItem in legendAdornmentLayer.LegendItems)
{
float itemLegendHeight = Math.Max(gdiPlusGeoCanvas.MeasureText(legendItem.TextStyle.TextColumnName, new GeoFont("Segoe UI", 10)).Height, legendItem.ImageHeight);
float itemHeight = itemLegendHeight + Math.Max(legendItem.ImageTopPadding, legendItem.TextTopPadding) + legendItem.TopPadding + Math.Max(legendItem.ImageBottomPadding, legendItem.TextBottomPadding) + legendItem.BottomPadding;
height += itemHeight;
}
return height;
}
private void HideStyleControls()
{
lblFewer.Visible = false;
lblMore.Visible = false;
trackBarDots.Visible = false;
lblDotDensityUnit.Visible = false;
trackBarValueCirleRadio.Visible = false;
lblValueCircle.Visible = false;
lblDisplayEndColor.Visible = false;
lblColorWheelDirection.Visible = false;
cbxActiveEndColor.Visible = false;
cbxSelectColorWheelDirection.Visible = false;
lblDisplayColor.Text = Resources.MainForm_HideStyleControls_Display_Color_;
}
// Load all the nodes on the left from xml file.
private void LoadDataSelectorUserControls()
{
XDocument xDocument = XDocument.Load(@"../../App_Data/CategoryList.xml");
IEnumerable<XElement> elements = from category in xDocument.Element("DemographicMap").Elements("Category")
select category;
foreach (var element in elements)
{
DataSelectorUserControl dataSelector;
if (element.Attribute("name").Value != "Custom Data")
{
dataSelector = new DataSelectorUserControl();
}
else
{
CustomDataSelectorUserControl customControl = new CustomDataSelectorUserControl();
customControl.DataSelected += MainForm_CustomDataSelected;
dataSelector = customControl;
}
dataSelector.Title = element.Attribute("name").Value;
dataSelector.Image = new Bitmap(string.Format("{0}{1}", "../../", element.Attribute("icon").Value));
foreach (var item in element.Elements("item"))
{
StyleSelectorUserControl styleSelector = new StyleSelectorUserControl();
styleSelector.ColumnName = item.Element("columnName").Value;
styleSelector.Alias = item.Element("alias").Value;
styleSelector.LegendTitle = item.Element("legendTitle").Value;
dataSelector.AddStyleSelector(styleSelector);
}
if (dataSelector.GetStyleSelectorCount() >= 2)
{
dataSelector.PieChartEnabled = true;
}
dataSelector.StyleUpdated += dataSelectorUserControl_StyleUpdated;
dataSelector.Click += DataSelector_Click;
flowLayoutPanel1.Controls.Add(dataSelector);
}
((DataSelectorUserControl)(flowLayoutPanel1.Controls[0])).SetActiveStatus(true);
}
private void MainForm_CustomDataSelected(object sender, DataSelectedCustomDataSelectorUserControlEventArgs e)
{
customFeatureLayer = e.ShapeFileFeatureLayer;
customFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
customFeatureLayer.DrawingMarginPercentage = 100;
currentFeatureLayer = customFeatureLayer;
currentStyleBuilder.SelectedColumns.Clear();
mapEngine.CurrentExtent = ExtentHelper.GetDrawingExtent(e.ShapeFileFeatureLayer.GetBoundingBox(), bitmap.Width, bitmap.Height);
mapEngine.DynamicLayers.Clear();
mapEngine.DynamicLayers.Add(currentFeatureLayer);
}
private void DataSelector_Click(object sender, EventArgs e)
{
DataSelectorUserControl clickedDataSelector = (DataSelectorUserControl)sender;
foreach (DataSelectorUserControl control in flowLayoutPanel1.Controls.OfType<DataSelectorUserControl>())
{
if (clickedDataSelector != control && control.IsActive)
{
control.SetActiveStatus(false);
}
}
clickedDataSelector.SetActiveStatus(!clickedDataSelector.IsActive);
if (!(clickedDataSelector is CustomDataSelectorUserControl))
{
currentFeatureLayer = censusStateFeatureLayer;
}
else
{
currentFeatureLayer = customFeatureLayer;
}
mapEngine.DynamicLayers.Clear();
mapEngine.DynamicLayers.Add(currentFeatureLayer);
}
private void LeftSideBarPanel_PanelCollapseButtonClick(object sender, EventArgs e)
{
MapPictureBox.Width = Width - LeftSideBarPanel.Width;
MapPictureBox.Left = LeftSideBarPanel.Width;
mapEngine.CurrentExtent = ExtentHelper.GetDrawingExtent(mapEngine.CurrentExtent, MapPictureBox.Width, MapPictureBox.Height);
RefreshMap();
}
private void ToolBar_ButtonClick(object sender, ToolBarButtonClickEventArgs e)
{
switch (e.Button.Tag.ToString())
{
case "Zoom In":
mapEngine.CurrentExtent.ScaleDown(50);
break;
case "Zoom Out":
mapEngine.CurrentExtent.ScaleUp(50);
break;
case "Full Extent":
currentFeatureLayer.Open();
mapEngine.CurrentExtent = ExtentHelper.GetDrawingExtent(currentFeatureLayer.GetBoundingBox(), bitmap.Width, bitmap.Height);
break;
case "Pan Left":
mapEngine.CurrentExtent = ExtentHelper.Pan(mapEngine.CurrentExtent, PanDirection.Left, 20);
break;
case "Pan Right":
mapEngine.CurrentExtent = ExtentHelper.Pan(mapEngine.CurrentExtent, PanDirection.Right, 20);
break;
case "Pan Up":
mapEngine.CurrentExtent = ExtentHelper.Pan(mapEngine.CurrentExtent, PanDirection.Up, 20);
break;
case "Pan Down":
mapEngine.CurrentExtent = ExtentHelper.Pan(mapEngine.CurrentExtent, PanDirection.Down, 20);
break;
}
RefreshMap();
}
private void RefreshMap()
{
bitmap = new Bitmap(MapPictureBox.Width, MapPictureBox.Height);
mapEngine.OpenAllLayers();
mapEngine.CurrentExtent = ExtentHelper.GetDrawingExtent(mapEngine.CurrentExtent, MapPictureBox.Width, MapPictureBox.Height);
mapEngine.DrawStaticLayers(bitmap, GeographyUnit.DecimalDegree);
mapEngine.DrawDynamicLayers(bitmap, GeographyUnit.DecimalDegree);
mapEngine.DrawAdornmentLayers(bitmap, GeographyUnit.DecimalDegree);
mapEngine.CloseAllLayers();
UpdateImageSource();
}
private void UpdateImageSource()
{
Image oldImage = MapPictureBox.Image;
MapPictureBox.Image = bitmap;
if (oldImage != null) oldImage.Dispose();
}
private void MapPictureBox_MouseMove(object sender, MouseEventArgs e)
{
ScreenPointF screenPoint = new ScreenPointF(e.X, e.Y);
PointShape worldPoint = ExtentHelper.ToWorldCoordinate(mapEngine.CurrentExtent, screenPoint, MapPictureBox.Width, MapPictureBox.Height);
lblLocationX.Text = string.Format(CultureInfo.InvariantCulture, "X: {0:N6}", worldPoint.X);
lblLocationY.Text = string.Format(CultureInfo.InvariantCulture, "Y: {0:N6}", worldPoint.Y);
}
}
}
HighlightOverlay.cs
using System.Collections.ObjectModel;
using ThinkGeo.MapSuite.Core;
using ThinkGeo.MapSuite.DesktopEdition;
namespace ThinkGeo.MapSuite.USDemographicMap
{
// This overlay is to highlight a feature when mouse over.
public class HighlightOverlay : Overlay
{
private InMemoryFeatureLayer highlightFeatureLayer;
private Feature highlightFeature;
public HighlightOverlay()
: base()
{
highlightFeatureLayer = new InMemoryFeatureLayer();
highlightFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.CreateSimpleAreaStyle(GeoColor.FromArgb(100, GeoColor.FromHtml("#449fbc")), GeoColor.FromHtml("#014576"), 1); ;
highlightFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
highlightFeatureLayer.Open();
}
public Feature HighlightFeature
{
get { return highlightFeature; }
}
public void UpdateHighlightFeature(FeatureLayer featureLayer, PointShape mouseLocation)
{
Collection<Feature> features = featureLayer.QueryTools.GetFeaturesContaining(mouseLocation, ReturningColumnsType.AllColumns);
highlightFeature = features.Count > 0 ? features[0] : null;
}
protected override void DrawCore(GeoCanvas canvas)
{
if (highlightFeature != null)
{
highlightFeatureLayer.Clear();
highlightFeatureLayer.InternalFeatures.Add(highlightFeature);
highlightFeatureLayer.Draw(canvas, new Collection<SimpleCandidate>());
}
}
}
}
CustomDotDensityStyle.cs
using System;
using System.Collections.ObjectModel;
using ThinkGeo.MapSuite.Core;
namespace ThinkGeo.MapSuite.USDemographicMap
{
// We custom this DotDensity Style to enhance its drawing on the legend.
[Serializable]
class CustomDotDensityStyle : DotDensityStyle
{
private int drawingPointsNumber;
public CustomDotDensityStyle()
: base()
{ }
public int DrawingPointsNumber
{
get { return drawingPointsNumber; }
set { drawingPointsNumber = value; }
}
protected override void DrawSampleCore(GeoCanvas canvas, DrawingRectangleF drawingExtent)
{
base.DrawSampleCore(canvas, drawingExtent);
PointShape upperLeftPoint = ExtentHelper.ToWorldCoordinate(canvas.CurrentWorldExtent, drawingExtent.CenterX - drawingExtent.Width / 2, drawingExtent.CenterY - drawingExtent.Height / 2, canvas.Width, canvas.Height);
PointShape lowerRightPoint = ExtentHelper.ToWorldCoordinate(canvas.CurrentWorldExtent, drawingExtent.CenterX + drawingExtent.Width / 2, drawingExtent.CenterY + drawingExtent.Height / 2, canvas.Width, canvas.Height);
RectangleShape rectangle = new RectangleShape(upperLeftPoint, lowerRightPoint);
rectangle.ScaleDown(10);
// Here draw the points on Legend Image
Random random = new Random(DateTime.Now.Millisecond);
Collection<BaseShape> drawingPoints = new Collection<BaseShape>();
for (int i = 0; i < DrawingPointsNumber; i++)
{
double x = rectangle.LowerLeftPoint.X + random.NextDouble() * (rectangle.Width);
double y = rectangle.LowerLeftPoint.Y + random.NextDouble() * (rectangle.Height);
drawingPoints.Add(new PointShape(x, y));
}
TextStyle textStyle = new TextStyle(DrawingPointsNumber.ToString(), new GeoFont("Arial", 20, DrawingFontStyles.Bold), new GeoSolidBrush(GeoColor.FromArgb(180, GeoColor.FromHtml("#d3d3d3"))));
textStyle.DrawSample(canvas, drawingExtent);
CustomPointStyle.Draw(drawingPoints, canvas, new Collection<SimpleCandidate>(), new Collection<SimpleCandidate>());
}
}
}
DemographicStyleBuilder.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using ThinkGeo.MapSuite.Core;
namespace ThinkGeo.MapSuite.USDemographicMap
{
// We have the StyleBuilder to generate different styles
public abstract class DemographicStyleBuilder
{
private int opacity;
private GeoColor color;
private Collection<string> selectedColumns;
protected DemographicStyleBuilder()
: this(new Collection<string>())
{ }
protected DemographicStyleBuilder(IEnumerable<string> selectedColumns)
{
this.Opacity = 100;
this.color = GeoColor.FromHtml("#F1F369");
this.selectedColumns = new Collection<string>(selectedColumns.ToList());
}
// The generated style would based on the columns we selected here.
// Multiple columns are required For PieChart style, only one column is needed for other styles in this sample.
public Collection<string> SelectedColumns
{
get { return selectedColumns; }
}
public GeoColor Color
{
get { return color; }
set { color = value; }
}
public int Opacity
{
get { return opacity; }
protected set { opacity = value; }
}
public Collection<Style> GetStyles(FeatureSource featureSource)
{
return GetStylesCore(featureSource);
}
protected abstract Collection<Style> GetStylesCore(FeatureSource featureSource);
}
}
DemographicStyleBuilderType.cs
namespace ThinkGeo.MapSuite.USDemographicMap
{
public enum DemographicStyleBuilderType
{
Thematic = 0,
ValueCircle = 1,
DotDensity = 2,
PieChart = 3
}
}
DotDensityDemographicStyleBuilder.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using ThinkGeo.MapSuite.Core;
namespace ThinkGeo.MapSuite.USDemographicMap
{
public class DotDensityDemographicStyleBuilder : DemographicStyleBuilder
{
private double dotDensityValue;
public DotDensityDemographicStyleBuilder()
: this(new string[] { })
{ }
public DotDensityDemographicStyleBuilder(IEnumerable<string> selectedColumns)
: base(selectedColumns)
{
Opacity = 255;
DotDensityValue = 50;
Color = GeoColor.SimpleColors.DarkRed;
}
public double DotDensityValue
{
get { return dotDensityValue; }
set { dotDensityValue = value; }
}
protected override Collection<Style> GetStylesCore(FeatureSource featureSource)
{
// here we generate CustomDotDensityStyle.
double totalValue = 0;
featureSource.Open();
int featureCount = featureSource.GetCount();
for (int i = 0; i < featureCount; i++)
{
Feature feature = featureSource.GetFeatureById((i + 1).ToString(CultureInfo.InvariantCulture), SelectedColumns);
double columnValue;
if (double.TryParse(feature.ColumnValues[SelectedColumns[0], out columnValue))
{
totalValue += columnValue;
}
}
featureSource.Close();
CustomDotDensityStyle dotDensityStyle = new CustomDotDensityStyle();
dotDensityStyle.ColumnName = SelectedColumns[0];
dotDensityStyle.PointToValueRatio = DotDensityValue / (totalValue / featureCount);
dotDensityStyle.CustomPointStyle = PointStyles.CreateSimpleCircleStyle(GeoColor.FromArgb(Opacity, Color), 4);
return new Collection<Style>() { dotDensityStyle };
}
}
}
PieChartDemographicStyleBuilder.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using ThinkGeo.MapSuite.Core;
using ZedGraph;
namespace ThinkGeo.MapSuite.USDemographicMap
{
public class PieChartDemographicStyleBuilder : DemographicStyleBuilder
{
private Collection<string> selectedColumnAliases;
private Collection<GeoColor> pieColors;
public PieChartDemographicStyleBuilder()
: this(new string[] { })
{ }
public PieChartDemographicStyleBuilder(IEnumerable<string> selectedColumns)
: base(selectedColumns)
{
Opacity = 200;
Color = GeoColor.SimpleColors.LightBlue;
selectedColumnAliases = new Collection<string>();
}
public Collection<string> SelectedColumnAliases
{
get { return selectedColumnAliases; }
}
protected override Collection<Style> GetStylesCore(FeatureSource featureSource)
{
// here we generated the PieZedGraphStyle.
PieZedGraphStyle zedGraphStyle = new PieZedGraphStyle();
zedGraphStyle.ZedGraphDrawing += ZedGraphStyle_ZedGraphDrawing;
pieColors = GeoColor.GetColorsInQualityFamily(GeoColor.FromArgb(Opacity, Color), SelectedColumns.Count);
for (int i = 0; i < SelectedColumns.Count; i++)
{
zedGraphStyle.RequiredColumnNames.Add(SelectedColumns[i]);
zedGraphStyle.PieSlices.Add(SelectedColumnAliases[i], pieColors[i]);
}
return new Collection<Style>(){zedGraphStyle};
}
private void ZedGraphStyle_ZedGraphDrawing(object sender, ZedGraphDrawingEventArgs e)
{
ZedGraphControl zedGraph = new ZedGraphControl();
zedGraph.Size = new Size(100, 100);
zedGraph.GraphPane.Fill.Type = FillType.None;
zedGraph.GraphPane.Chart.Fill.Type = FillType.None;
zedGraph.GraphPane.Border.IsVisible = false;
zedGraph.GraphPane.Chart.Border.IsVisible = false;
zedGraph.GraphPane.XAxis.IsVisible = false;
zedGraph.GraphPane.YAxis.IsVisible = false;
zedGraph.GraphPane.Legend.IsVisible = false;
zedGraph.GraphPane.Title.IsVisible = false;
for (int i = 0; i < SelectedColumns.Count; i++)
{
double value = 0;
if (!double.TryParse(e.Feature.ColumnValues[SelectedColumns[i], out value))
{
zedGraph.Dispose();
return;
}
Color color = System.Drawing.Color.FromArgb(pieColors[i].AlphaComponent, pieColors[i].RedComponent, pieColors[i].GreenComponent, pieColors[i].BlueComponent);
PieItem pieItem = zedGraph.GraphPane.AddPieSlice(value, color, 0.08, "");
pieItem.LabelDetail.IsVisible = false;
}
zedGraph.AxisChange();
e.Bitmap = zedGraph.GraphPane.GetImage();
zedGraph.Dispose();
}
}
}
PieZedGraphStyle.cs
using System.Collections.Generic;
using ThinkGeo.MapSuite.Core;
namespace ThinkGeo.MapSuite.USDemographicMap
{
// We custom this class just make it a bit easier to use.
public class PieZedGraphStyle : ZedGraphStyle
{
private Dictionary<string, GeoColor> pieSlices;
public PieZedGraphStyle()
{
pieSlices = new Dictionary<string, GeoColor>();
}
public Dictionary<string, GeoColor> PieSlices
{
get { return pieSlices; }
}
}
}
TextFormatter.cs
using System;
using System.Globalization;
namespace ThinkGeo.MapSuite.USDemographicMap
{
public static class TextFormatter
{
public static string GetFormatedStringForLegendItem(string columnName, double value)
{
string aliasUnitString = GetFormatedString(columnName, value);
string[] subStrings = aliasUnitString.Split(new string[] { ": " }, StringSplitOptions.None);
if (subStrings[subStrings.Length|- 1].Contains("%"))
{
aliasUnitString = subStrings[subStrings.Length|- 1];
}
else
{
aliasUnitString = value.ToString("N0", CultureInfo.InvariantCulture);
}
return aliasUnitString;
}
public static string GetFormatedString(string columnName, double value)
{
string result = string.Empty;
switch (columnName)
{
case "Population":
result = string.Format("Population : {0} People", value.ToString("N0", CultureInfo.InvariantCulture));
break;
case "PopDensity":
result = string.Format("Population Density : {0} People / sq.mi.", value.ToString("N0", CultureInfo.InvariantCulture));
break;
case "Female":
result = string.Format("Female : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "Male":
result = string.Format("Male : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "AREALAND":
result = string.Format("Land Area : {0} sq.mi.", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "AREAWATR":
result = string.Format("Water Area : {0} sq.mi.", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "White":
result = string.Format("White : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "Black":
result = string.Format("Black : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "Indian":
result = string.Format("American Indian : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "Islander":
result = string.Format("Native Pacific Islander : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "Asian":
result = string.Format("Asian : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "Other":
result = string.Format("Other : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "MultiRace":
result = string.Format("Multiracial : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "Under5":
result = string.Format("<= 5 : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "5to9":
result = string.Format("5 ~ 10 : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "10to14":
result = string.Format("10 ~ 15 : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "15to17":
result = string.Format("15 ~ 18 : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "18to24":
result = string.Format("18 ~ 25 : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "25to34":
result = string.Format("25 ~ 35 : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "35to44":
result = string.Format("35 ~ 45 : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "45to54":
result = string.Format("45 ~ 55 : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "55to64":
result = string.Format("55 ~ 65 : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "65to74":
result = string.Format("65 ~ 75 : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "75to84":
result = string.Format("75 ~ 85 : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
case "over85":
result = string.Format(">= 85 : {0} %", value.ToString("N2", CultureInfo.InvariantCulture));
break;
default:
result = columnName + " : " + value.ToString("N0", CultureInfo.InvariantCulture);
break;
}
return result;
}
}
}
ThematicDemographicStyleBuilder.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using ThinkGeo.MapSuite.Core;
namespace ThinkGeo.MapSuite.USDemographicMap
{
public class ThematicDemographicStyleBuilder : DemographicStyleBuilder
{
private int classBreakCount;
private GeoColor endColor;
private ColorWheelDirection colorWheelDirection;
public ThematicDemographicStyleBuilder()
: this(new string[] { })
{ }
public ThematicDemographicStyleBuilder(IEnumerable<string> selectedColumns)
: base(selectedColumns)
{
Opacity = 200;
ClassBreakCount = 10;
Color = GeoColor.SimpleColors.LightBlue;
EndColor = GeoColor.SimpleColors.LightRed;
ColorWheelDirection = ColorWheelDirection.CounterClockwise;
}
public int ClassBreakCount
{
get { return classBreakCount; }
set { classBreakCount = value; }
}
public ColorWheelDirection ColorWheelDirection
{
get { return colorWheelDirection; }
set { colorWheelDirection = value; }
}
public GeoColor StartColor
{
get { return Color; }
set { Color = value; }
}
public GeoColor EndColor
{
get { return endColor; }
set { endColor = value; }
}
protected override Collection<Style> GetStylesCore(FeatureSource featureSource)
{
// here we generated a class break style and a text style.
Collection<GeoColor> familyColors = GeoColor.GetColorsInQualityFamily(Color, EndColor, classBreakCount, ColorWheelDirection);
featureSource.Open();
int featureCount = featureSource.GetCount();
double[] values = new double[featureCount];
for (int i = 0; i < featureCount; i++)
{
Feature feature = featureSource.GetFeatureById((i + 1).ToString(CultureInfo.InvariantCulture), SelectedColumns);
double columnValue;
if (double.TryParse(feature.ColumnValues[SelectedColumns[0], out columnValue))
{
values[i] = columnValue;
}
}
featureSource.Close();
ClassBreakStyle classBreakStyle = new ClassBreakStyle(SelectedColumns[0]) { BreakValueInclusion = BreakValueInclusion.IncludeValue };
double[] classBreakValues = GetClusterClassBreaks(values, ClassBreakCount - 1);
for (int i = 0; i < classBreakValues.Length; i++)
{
ClassBreak classBreak = new ClassBreak(classBreakValues[i], AreaStyles.CreateSimpleAreaStyle(new GeoColor(this.Opacity, familyColors[i]), GeoColor.FromHtml("#f05133"), 1));
classBreakStyle.ClassBreaks.Add(classBreak);
}
return new Collection<Style>() { classBreakStyle, TextStyles.Country1("NAME") };
}
private double[] GetClusterClassBreaks(double[] values, int count)
{
var result = new List<double>();
var orderedValues = values.OrderBy(v => v).ToArray();
var min = orderedValues[0];
var max = orderedValues[orderedValues.Length|- 1];
var classesCount = (int)(orderedValues.Length / count);
var breakValue = min;
for (var i = 1; i < count; i++)
{
breakValue = orderedValues[i|* classesCount];
if (!result.Contains(breakValue))
{
result.Add(breakValue);
}
}
result.Insert(0, 0);
return result.ToArray();
}
}
}
ValueCircleDemographicStyleBuilder.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using ThinkGeo.MapSuite.Core;
namespace ThinkGeo.MapSuite.USDemographicMap
{
public class ValueCircleDemographicStyleBuilder : DemographicStyleBuilder
{
private double radiusRatio;
public ValueCircleDemographicStyleBuilder()
: this(new string[] { })
{ }
public ValueCircleDemographicStyleBuilder(IEnumerable<string> selectedColumns)
: base(selectedColumns)
{
radiusRatio = 1;
Color = GeoColor.SimpleColors.BrightOrange;
Opacity = 160;
}
public double RadiusRatio
{
get { return radiusRatio; }
set { radiusRatio = value; }
}
protected override Collection<Style> GetStylesCore(FeatureSource featureSource)
{
// here we generate a ValueCircle Style.
double minValue = double.MaxValue;
double maxValue = double.MinValue;
featureSource.Open();
for (int i = 0; i < featureSource.GetCount(); i++)
{
Feature feature = featureSource.GetFeatureById((i + 1).ToString(CultureInfo.InvariantCulture), SelectedColumns);
double columnValue;
if (double.TryParse(feature.ColumnValues[SelectedColumns[0], out columnValue))
{
if (columnValue < minValue)
{
minValue = columnValue;
}
else if (columnValue > maxValue)
{
maxValue = columnValue;
}
}
}
featureSource.Close();
ValueCircleStyle valueCircleStyle = new ValueCircleStyle();
valueCircleStyle.ColumnName = SelectedColumns[0];
valueCircleStyle.DrawingRadiusRatio = radiusRatio;
valueCircleStyle.MinValidValue = minValue;
valueCircleStyle.MaxValidValue = maxValue;
valueCircleStyle.MinCircleAreaInDefaultZoomLevel = 80;
valueCircleStyle.MaxCircleAreaInDefaultZoomLevel = 10000;
valueCircleStyle.InnerColor = GeoColor.FromArgb(this.Opacity, Color);
valueCircleStyle.OuterColor = GeoColor.SimpleColors.White;
return new Collection<Style>(){valueCircleStyle};
}
}
}
ValueCircleStyle.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using ThinkGeo.MapSuite.Core;
namespace ThinkGeo.MapSuite.USDemographicMap
{
// This custom style is for displaying circles with different sizes based on the value.
public class ValueCircleStyle : Style
{
private string columnName;
private double baseScale;
private double minValidValue;
private double maxValidValue;
private double drawingRadiusRatio;
private double maxCircleRadiusInDefaultZoomLevel;
private double minCircleRadiusInDefaultZoomLevel;
private GeoColor innerColor;
private GeoColor outerColor;
private ZoomLevel defaultZoomLevel;
public ValueCircleStyle()
: base()
{
ZoomLevelSet zoomLevelSet = new ZoomLevelSet();
defaultZoomLevel = zoomLevelSet.ZoomLevel04;
baseScale = zoomLevelSet.ZoomLevel05.Scale;
drawingRadiusRatio = 1;
outerColor = GeoColor.FromArgb(255, 10, 20, 255);
innerColor = GeoColor.FromArgb(100, 10, 20, 255);
minCircleRadiusInDefaultZoomLevel = 10;
maxCircleRadiusInDefaultZoomLevel = 100;
}
public string ColumnName
{
get { return columnName; }
set { columnName = value; }
}
public ZoomLevel DefaultZoomLevel
{
get { return defaultZoomLevel; }
set { defaultZoomLevel = value; }
}
public double DrawingRadiusRatio
{
get { return drawingRadiusRatio; }
set { drawingRadiusRatio = value; }
}
public GeoColor InnerColor
{
get { return innerColor; }
set { innerColor = value; }
}
// The data might be dramatically different but we don't want any circle be super large
// on the map, so here we have this property to identify the max circle we can have on map.
public double MaxCircleAreaInDefaultZoomLevel
{
get { return maxCircleRadiusInDefaultZoomLevel; }
set { maxCircleRadiusInDefaultZoomLevel = value; }
}
public double MaxValidValue
{
get { return maxValidValue; }
set { maxValidValue = value; }
}
// The data might be dramatically different but we don't want any circle be super tiny
// on the map, so here we have this property to identify the min circle we can have on map.
public double MinCircleAreaInDefaultZoomLevel
{
get { return minCircleRadiusInDefaultZoomLevel; }
set { minCircleRadiusInDefaultZoomLevel = value; }
}
public double MinValidValue
{
get { return minValidValue; }
set { minValidValue = value; }
}
public GeoColor OuterColor
{
get { return outerColor; }
set { outerColor = value; }
}
public double BasedScale
{
get { return baseScale; }
}
protected override void DrawCore(IEnumerable<Feature> features, GeoCanvas canvas, Collection<SimpleCandidate> labelsInThisLayer, Collection<SimpleCandidate> labelsInAllLayers)
{
double ratio = (maxValidValue - minValidValue) / (maxCircleRadiusInDefaultZoomLevel - minCircleRadiusInDefaultZoomLevel);
// here we calculate the size of each circle based on every feature's value.
foreach (Feature feature in features)
{
double value = 0;
if (!double.TryParse(feature.ColumnValues[columnName], out value))
{
continue;
}
if (value > maxValidValue || value < minValidValue)
{
continue;
}
double drawingDefaultCircleArea = (value - minValidValue) / ratio + minCircleRadiusInDefaultZoomLevel;
double graphArea = drawingDefaultCircleArea * defaultZoomLevel.Scale / baseScale * drawingRadiusRatio;
double graphHeght = Math.Sqrt(graphArea / Math.PI);
PointShape center = feature.GetShape().GetCenterPoint();
canvas.DrawEllipse(center, (float)(graphHeght * 2), (float)(graphHeght * 2), new GeoPen(outerColor, 1), new GeoSolidBrush(innerColor), DrawingLevel.LevelOne);
}
}
protected override Collection<string> GetRequiredColumnNamesCore()
{
Collection<string> requiredFieldNames = new Collection<string>();
requiredFieldNames.Add(columnName);
return requiredFieldNames;
}
}
}
CollapsiblePanel.cs
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using ThinkGeo.MapSuite.USDemographicMap.Properties;
namespace ThinkGeo.MapSuite.USDemographicMap
{
// This Panel is for the collapsible panel on the left.
public class CollapsiblePanel : Panel
{
private int lineWidth;
private int panelWidth;
private bool isCollapsible;
private Size collapsibleBoxSize;
private PictureBox pictureCollapsibleBox;
public event EventHandler<EventArgs> PanelCollapseButtonClick;
public CollapsiblePanel()
{
lineWidth = 5;
collapsibleBoxSize = new Size(12, 110);
pictureCollapsibleBox = new PictureBox();
pictureCollapsibleBox.BackColor = Color.Transparent;
pictureCollapsibleBox.Location = new Point(Width - lineWidth - collapsibleBoxSize.Width, this.Height / 2 - collapsibleBoxSize.Height / 2);
pictureCollapsibleBox.Size = collapsibleBoxSize;
pictureCollapsibleBox.Click += PictureCollapsibleBox_Click;
pictureCollapsibleBox.MouseEnter += PictureCollapsibleBox_MouseEnter;
pictureCollapsibleBox.MouseLeave += PictureCollapsibleBox_MouseLeave;
pictureCollapsibleBox.Image = GetCollapsibleImage();
Width = lineWidth + panelWidth + pictureCollapsibleBox.Width;
Controls.Add(pictureCollapsibleBox);
Resize += CollapsiblePanel_Resize;
}
public int LineWidth
{
get { return lineWidth; }
set { lineWidth = value; }
}
public int PanelWidth
{
get { return panelWidth; }
set { panelWidth = value; }
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Rectangle drawingRectangle = new Rectangle(Width - lineWidth, 0, lineWidth, Height);
LinearGradientBrush myBrush = new LinearGradientBrush(drawingRectangle, Color.Gray, Color.White, LinearGradientMode.Horizontal);
e.Graphics.FillRectangle(myBrush, drawingRectangle);
}
private void CollapsiblePanel_Resize(object sender, EventArgs e)
{
pictureCollapsibleBox.Location = new Point(Width - lineWidth - collapsibleBoxSize.Width, Height / 2 - collapsibleBoxSize.Height / 2);
}
private Bitmap GetCollapsibleImage()
{
if (pictureCollapsibleBox.Image != null)
{
pictureCollapsibleBox.Image.Dispose();
}
Bitmap bitmap = new Bitmap(pictureCollapsibleBox.Size.Width, pictureCollapsibleBox.Size.Height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
Size imageSize = Resources.collapse.Size;
int x = (pictureCollapsibleBox.Width - imageSize.Width) / 2;
int y = (pictureCollapsibleBox.Height - imageSize.Height) / 2;
graphics.DrawImage(isCollapsible ? Resources.expand : Resources.collapse, x, y);
}
return bitmap;
}
private void PictureCollapsibleBox_Click(object sender, EventArgs e)
{
isCollapsible = !isCollapsible;
pictureCollapsibleBox.Image = GetCollapsibleImage();
foreach (Control item in this.Controls)
{
if (item != pictureCollapsibleBox)
{
item.Visible = !isCollapsible;
}
}
Width = isCollapsible ? lineWidth + collapsibleBoxSize.Width : panelWidth + lineWidth + collapsibleBoxSize.Width;
Refresh();
OnPanelCollapseButtonClick();
}
private void PictureCollapsibleBox_MouseEnter(object sender, EventArgs e)
{
pictureCollapsibleBox.BackColor = Color.FromArgb(150, 4, 60, 153);
}
private void PictureCollapsibleBox_MouseLeave(object sender, EventArgs e)
{
pictureCollapsibleBox.BackColor = Color.Transparent;
}
private void OnPanelCollapseButtonClick()
{
if (PanelCollapseButtonClick != null)
{
PanelCollapseButtonClick(this, new EventArgs());
}
}
}
}
ColorComboBox.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using ThinkGeo.MapSuite.Core;
namespace ThinkGeo.MapSuite.USDemographicMap
{
// This is the color picking combobox.
public class ColorComboBox : ComboBox
{
private Dictionary<string, Color> simpleColors;
public ColorComboBox()
{
simpleColors = new Dictionary<string, Color>();
DrawMode = DrawMode.OwnerDrawFixed;
DropDownStyle = ComboBoxStyle.DropDownList;
ItemHeight = 25;
Type type = GeoColor.SimpleColors.GetType();
PropertyInfo[] propertyInfos = type.GetProperties();
foreach (PropertyInfo propertypInfo in propertyInfos.Where(p => !p.Name.Equals("TRANSPARENT", StringComparison.InvariantCultureIgnoreCase)))
{
string name = propertypInfo.Name;
object value = propertypInfo.GetValue(GeoColor.SimpleColors, null);
if (value.GetType() == typeof(GeoColor))
{
GeoColor geoColor = (GeoColor)value;
simpleColors.Add(name, Color.FromArgb(geoColor.RedComponent, geoColor.GreenComponent, geoColor.BlueComponent));
if (!Items.Contains(name))
{
Items.Add(name);
}
}
}
Text = "Black";
}
public Color SelectedColor
{
get { return simpleColors[Text]; }
}
public Dictionary<string, Color> SimpleColors
{
get { return simpleColors; }
set { simpleColors = value; }
}
public void SetSelectedColor(string key)
{
if (simpleColors.ContainsKey(key))
{
SelectedItem = key;
}
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
Rectangle rect = e.Bounds;
if (e.Index >= 0)
{
string colorName = Items[e.Index].ToString();
Color c = simpleColors[colorName];
using (Brush brush = new SolidBrush(c))
{
Brush whiteBrush = new SolidBrush(Color.White);
e.Graphics.DrawRectangle(new Pen(Color.Black, 1), rect.X + 5, rect.Y + 2, rect.Width / 4, rect.Height - 4);
e.Graphics.FillRectangle(brush, new Rectangle(rect.X + 7, rect.Y + 4, rect.Width / 4 - 3, rect.Height - 7));
e.Graphics.DrawString(colorName, new Font("Segoe UI", 10), new SolidBrush(Color.Black), new PointF(rect.X + rect.Width / 4 + 10, rect.Y + 4));
whiteBrush.Dispose();
}
}
}
}
}
CustomDataSelectorUserControl.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using ThinkGeo.MapSuite.Core;
namespace ThinkGeo.MapSuite.USDemographicMap
{
// This is the bottom "Custom Data" item on the left.
// It contains the initial SelectCustomDataUserControl, and would contain StyleSelectorUserControls like other DataSelectorUserControls.
public class CustomDataSelectorUserControl : DataSelectorUserControl
{
public event EventHandler<DataSelectedCustomDataSelectorUserControlEventArgs> DataSelected;
private SelectCustomDataUserControl customDataSelector;
public CustomDataSelectorUserControl()
: base()
{
customDataSelector = new SelectCustomDataUserControl();
customDataSelector.FileSelected = CustomDataSelector_FileSelected;
Panel.Controls.Add(customDataSelector);
CompleteHeight = customDataSelector.Height;
}
protected void OnCustomDataSelected(DataSelectedCustomDataSelectorUserControlEventArgs e)
{
EventHandler<DataSelectedCustomDataSelectorUserControlEventArgs> handler = DataSelected;
if (handler != null)
{
handler(this, e);
}
}
private void StyleSelectorUserControl_StyleUpdated(object sender, StyleUpdatedStyleSelectorUserControlEventArgs e)
{
if (e.DemographicStyleBuilderType != DemographicStyleBuilderType.PieChart)
{
StyleUpdatedDataSelectorUserControlEventArgs eventArgs = new StyleUpdatedDataSelectorUserControlEventArgs(e.DemographicStyleBuilderType);
eventArgs.ActivatedStyleSelectors.Add((StyleSelectorUserControl)sender);
OnStyleUpdated(eventArgs);
}
else
{
RaisePieChartUpdatedEvent();
}
}
private void CustomDataSelector_FileSelected(string pathFileName)
{
ShapeFileFeatureLayer featureLayer = new ShapeFileFeatureLayer(pathFileName);
featureLayer.Open();
if (featureLayer.GetShapeFileType() == ShapeFileType.Polygon)
{
AddStyleSelectors(featureLayer);
OnCustomDataSelected(new DataSelectedCustomDataSelectorUserControlEventArgs(featureLayer));
}
else
{
MessageBox.Show("The shape file must be polygon type, please try another one.", "Warning");
}
}
private void AddStyleSelectors(ShapeFileFeatureLayer featureLayer)
{
for (int i = Panel.Controls.Count - 1; i >= 0; i--)
{
StyleSelectorUserControl styleSelectorUserControl = Panel.Controls[i] as StyleSelectorUserControl;
if (styleSelectorUserControl != null)
{
Panel.Controls.Remove(styleSelectorUserControl);
}
}
int panelHeight = customDataSelector.Height + customDataSelector.Top;
List<DbfColumn> numericDbfColumns = GetNumericDbfColumns(featureLayer.QueryTools.GetColumns().OfType<DbfColumn>());
StyleSelectors.Clear();
foreach (DbfColumn column in numericDbfColumns)
{
StyleSelectorUserControl styleSelectorUserControl = new StyleSelectorUserControl();
styleSelectorUserControl.StyleUpdated += StyleSelectorUserControl_StyleUpdated;
panelHeight += styleSelectorUserControl.Height + styleSelectorUserControl.Top;
styleSelectorUserControl.Alias = column.ColumnName;
styleSelectorUserControl.ColumnName = column.ColumnName;
styleSelectorUserControl.LegendTitle = column.ColumnName;
styleSelectorUserControl.WithinPieChart = true;
StyleSelectors.Add(styleSelectorUserControl);
CompleteHeight += styleSelectorUserControl.Height;
Panel.Controls.Add(styleSelectorUserControl);
}
int height = 0;
foreach (Control control in Panel.Controls.OfType<Control>())
{
control.Location = new Point(control.Margin.Left, control.Margin.Top + height);
height = control.Location.Y + control.Height;
}
if (Panel.Controls.Count >= 2)
{
PieChartEnabled = true;
}
Panel.Height = panelHeight;
Height = HeaderHeight + panelHeight;
}
private static List<DbfColumn> GetNumericDbfColumns(IEnumerable<DbfColumn> dbfColumns)
{
return dbfColumns.Where(IsNumericColumn).ToList();
}
private static bool IsNumericColumn(DbfColumn column)
{
return column.ColumnType == DbfColumnType.Float ||
column.ColumnType == DbfColumnType.Numeric ||
column.ColumnType == DbfColumnType.Double ||
column.ColumnType == DbfColumnType.Integer;
}
}
}
DataSelectedCustomDataSelectorUserControlEventArgs.cs
using System;
using ThinkGeo.MapSuite.Core;
namespace ThinkGeo.MapSuite.USDemographicMap
{
public class DataSelectedCustomDataSelectorUserControlEventArgs : EventArgs
{
public DataSelectedCustomDataSelectorUserControlEventArgs()
: this(null)
{ }
public DataSelectedCustomDataSelectorUserControlEventArgs(ShapeFileFeatureLayer shapeFileFeatureLayer)
{
ShapeFileFeatureLayer = shapeFileFeatureLayer;
}
public ShapeFileFeatureLayer ShapeFileFeatureLayer { get; set; }
}
}
DataSelectorUserControl.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using ThinkGeo.MapSuite.USDemographicMap.Properties;
namespace ThinkGeo.MapSuite.USDemographicMap
{
// This is the data selector item on the left.
// It contains StyleSelectorUserControls where user can pick different styles for displaying.
public partial class DataSelectorUserControl : UserControl
{
private int headerHeight;
private int completeHeight;
private bool isActive;
private Panel panel;
private List<StyleSelectorUserControl> styleSelectors;
public event EventHandler<StyleUpdatedDataSelectorUserControlEventArgs> StyleUpdated;
public DataSelectorUserControl()
{
InitializeComponent();
HeaderHeight = Height;
Panel = new Panel();
Panel.Location = new Point(0, HeaderHeight);
Panel.BackColor = Color.White;
Panel.Width = Width;
styleSelectors = new List<StyleSelectorUserControl>();
picPie.Enabled = false;
picPie.Visible = false;
isActive = false;
ToolTip toolTipPie = new ToolTip();
toolTipPie.SetToolTip(picPie, "Display pie charts on the map representing the breakdown of all data points selected below.");
}
protected Panel Panel
{
get { return panel; }
set { panel = value; }
}
protected List<StyleSelectorUserControl> StyleSelectors
{
get { return styleSelectors; }
}
protected int HeaderHeight
{
get { return headerHeight; }
set { headerHeight = value; }
}
protected int CompleteHeight
{
get { return completeHeight; }
set { completeHeight = value; }
}
public Image Image
{
get { return picDataImage.Image; }
set { picDataImage.Image = value; }
}
public bool IsActive
{
get { return isActive; }
}
public bool PieChartEnabled
{
get { return picPie.Enabled; }
set { picPie.Enabled = value; }
}
public string Title
{
get { return lblTitle.Text; }
set { lblTitle.Text = value; }
}
public void AddStyleSelector(StyleSelectorUserControl styleSelector)
{
this.StyleSelectors.Add(styleSelector);
styleSelector.StyleUpdated += StyleSelectorUserControl_StyleUpdated;
styleSelector.Location = new Point(styleSelector.Margin.Left, styleSelector.Margin.Top + CompleteHeight);
CompleteHeight += styleSelector.Height;
Panel.Controls.Add(styleSelector);
}
public int GetStyleSelectorCount()
{
return StyleSelectors.Count;
}
public void SetActiveStatus(bool active)
{
if (isActive != active)
{
picPie.Visible = active;
isActive = active;
Panel.Height = CompleteHeight;
if (isActive)
{
this.Controls.Add(Panel);
this.Height = HeaderHeight + Panel.Height;
}
else
{
this.Controls.Remove(Panel);
this.Height = HeaderHeight;
}
}
}
protected void RaisePieChartUpdatedEvent()
{
StyleUpdatedDataSelectorUserControlEventArgs eventArgs = new StyleUpdatedDataSelectorUserControlEventArgs(DemographicStyleBuilderType.PieChart);
foreach (StyleSelectorUserControl item in StyleSelectors)
{
item.IsVisible = true;
if (item.WithinPieChart)
{
eventArgs.ActivatedStyleSelectors.Add(item);
}
}
if (eventArgs.ActivatedStyleSelectors.Count >= 2)
{
picPie.Enabled = true;
OnStyleUpdated(eventArgs);
}
}
protected virtual void OnStyleUpdated(StyleUpdatedDataSelectorUserControlEventArgs e)
{
EventHandler<StyleUpdatedDataSelectorUserControlEventArgs> handler = StyleUpdated;
if (handler != null)
{
handler(this, e);
}
}
private void StyleSelectorUserControl_StyleUpdated(object sender, StyleUpdatedStyleSelectorUserControlEventArgs e)
{
if (e.DemographicStyleBuilderType != DemographicStyleBuilderType.PieChart)
{
StyleUpdatedDataSelectorUserControlEventArgs eventArgs = new StyleUpdatedDataSelectorUserControlEventArgs(e.DemographicStyleBuilderType);
eventArgs.ActivatedStyleSelectors.Add((StyleSelectorUserControl)sender);
OnStyleUpdated(eventArgs);
}
else
{
RaisePieChartUpdatedEvent();
}
}
private void PieChartLegendItem_Click(object sender, EventArgs e)
{
RaisePieChartUpdatedEvent();
}
private void PictureBoxPie_EnabledChanged(object sender, EventArgs e)
{
picPie.Image = picPie.Enabled ? Resources.pie : Resources.pie_Disable;
}
private void SubControls_Click(object sender, EventArgs e)
{
OnClick(e);
}
private void DataCategoryUserControl_MouseEnter(object sender, EventArgs e)
{
BackColor = Color.FromArgb(100, Color.FromArgb(180, 180, 180));
Focus();
}
private void DataCategoryUserControl_MouseLeave(object sender, EventArgs e)
{
BackColor = Color.Transparent;
}
private void PieChartLegendItem_MouseEnter(object sender, EventArgs e)
{
((PictureBox)sender).BackColor = Color.FromArgb(80, Color.Red);
BackColor = Color.FromArgb(100, Color.FromArgb(180, 180, 180));
Focus();
}
private void PieChartLegendItem_MouseLeave(object sender, EventArgs e)
{
((PictureBox)sender).BackColor = Color.Transparent;
BackColor = Color.Transparent;
}
}
}
SelectCustomDataUserControl.cs
using System;
using System.IO;
using System.Windows.Forms;
namespace ThinkGeo.MapSuite.USDemographicMap
{
// This is the initial user control in CustomDataSelectorUserControl
// This would let user browse and choose a custom shape file.
public partial class SelectCustomDataUserControl : UserControl
{
public SelectCustomDataUserControl()
{
InitializeComponent();
}
public Action<string> FileSelected { get; set; }
public string SelectedPathFilename
{
get { return txtPathFilename.Text; }
}
private void BrowseButton_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Shape Files|*.shp";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
txtPathFilename.Text = openFileDialog.FileName;
if (File.Exists(openFileDialog.FileName))
{
OnFileSelected(openFileDialog.FileName);
}
}
}
protected void OnFileSelected(string pathFileName)
{
Action<string> handler = FileSelected;
if (handler != null)
{
handler(pathFileName);
}
}
}
}
StyleSelectorUserControl.cs
using System;
using System.Drawing;
using System.Windows.Forms;
using ThinkGeo.MapSuite.USDemographicMap.Properties;
namespace ThinkGeo.MapSuite.USDemographicMap
{
// This is a StyleSelector within each DataSelector, user can pick different style from here.
public partial class StyleSelectorUserControl : UserControl
{
private string columnName;
private string legendTitle;
public event EventHandler<StyleUpdatedStyleSelectorUserControlEventArgs> StyleUpdated;
public StyleSelectorUserControl()
: base()
{
InitializeComponent();
ToolTip legendItemToolTip = new ToolTip();
legendItemToolTip.SetToolTip(picDotDensity, "Present the data with Dot Density.");
legendItemToolTip.SetToolTip(picValueCircle, "Present the data in Value Circles.");
legendItemToolTip.SetToolTip(picThematic, "Present the data in Thematic Colors.");
ToolTip isSelectedToolTip = new ToolTip();
isSelectedToolTip.SetToolTip(chkIsSelected, "Select to include this data point in the map's pie charts.");
picDotDensity.Image = Resources.DotDensity;
picThematic.Image = Resources.Thematic;
picValueCircle.Image = Resources.ValueCircle;
picDotDensity.Cursor = Cursors.Hand;
picThematic.Cursor = Cursors.Hand;
picValueCircle.Cursor = Cursors.Hand;
chkIsSelected.Checked = true;
chkIsSelected.Visible = false;
}
public string Alias
{
get { return lblTitle.Text; }
set { lblTitle.Text = value; }
}
public bool IsVisible
{
get { return chkIsSelected.Visible; }
set { chkIsSelected.Visible = value; }
}
public string ColumnName
{
get { return columnName; }
set { columnName = value; }
}
public bool WithinPieChart
{
get { return chkIsSelected.Checked; }
set { chkIsSelected.Checked = value; }
}
public string LegendTitle
{
get { return legendTitle; }
set { legendTitle = value; }
}
private void SelectedCheckBox_CheckedChanged(object sender, EventArgs e)
{
OnStyleUpdated(new StyleUpdatedStyleSelectorUserControlEventArgs(DemographicStyleBuilderType.PieChart));
}
private void pictureBox_Click(object sender, System.EventArgs e)
{
DemographicStyleBuilderType StyleType = DemographicStyleBuilderType.DotDensity;
if (sender == picDotDensity)
{
StyleType = DemographicStyleBuilderType.DotDensity;
}
else if (sender == picThematic)
{
StyleType = DemographicStyleBuilderType.Thematic;
}
else if (sender == picValueCircle)
{
StyleType = DemographicStyleBuilderType.ValueCircle;
}
StyleUpdatedStyleSelectorUserControlEventArgs eventArgs = new StyleUpdatedStyleSelectorUserControlEventArgs(StyleType);
chkIsSelected.Checked = true;
OnStyleUpdated(eventArgs);
}
private void pictureBox_MouseEnter(object sender, EventArgs e)
{
PictureBox pictureBox = sender as PictureBox;
if (pictureBox != null)
{
pictureBox.BackColor = Color.FromArgb(50, Color.Red);
}
}
private void pictureBox_MouseLeave(object sender, EventArgs e)
{
PictureBox pictureBox = sender as PictureBox;
if (pictureBox != null)
{
pictureBox.BackColor = Color.Transparent;
}
}
private void OnStyleUpdated(StyleUpdatedStyleSelectorUserControlEventArgs e)
{
EventHandler<StyleUpdatedStyleSelectorUserControlEventArgs> handler = StyleUpdated;
if (handler != null)
{
handler(this, e);
}
}
}
}
StyleUpdatedDataSelectorUserControlEventArgs.cs
using System;
using System.Collections.Generic;
namespace ThinkGeo.MapSuite.USDemographicMap
{
public class StyleUpdatedDataSelectorUserControlEventArgs : EventArgs
{
private DemographicStyleBuilderType demographicStyleBuilderType;
private List<StyleSelectorUserControl> activatedStyleSelectors;
public StyleUpdatedDataSelectorUserControlEventArgs()
: this(DemographicStyleBuilderType.PieChart)
{ }
public StyleUpdatedDataSelectorUserControlEventArgs(DemographicStyleBuilderType demographicStyleBuilderType)
: base()
{
this.demographicStyleBuilderType = demographicStyleBuilderType;
this.activatedStyleSelectors = new List<StyleSelectorUserControl>();
}
public List<StyleSelectorUserControl> ActivatedStyleSelectors
{
get { return activatedStyleSelectors; }
}
public DemographicStyleBuilderType DemographicStyleBuilderType
{
get { return demographicStyleBuilderType; }
set { demographicStyleBuilderType = value; }
}
}
}
StyleUpdatedStyleSelectorUserControlEventArgs.cs
using System;
using System.Collections.Generic;
namespace ThinkGeo.MapSuite.USDemographicMap
{
public class StyleUpdatedStyleSelectorUserControlEventArgs : EventArgs
{
private DemographicStyleBuilderType demographicStyleBuilderType;
public StyleUpdatedStyleSelectorUserControlEventArgs()
: this(DemographicStyleBuilderType.PieChart)
{ }
public StyleUpdatedStyleSelectorUserControlEventArgs(DemographicStyleBuilderType demographicStyleBuilderType)
: base()
{
this.demographicStyleBuilderType = demographicStyleBuilderType;
}
public DemographicStyleBuilderType DemographicStyleBuilderType
{
get { return demographicStyleBuilderType; }
set { demographicStyleBuilderType = value; }
}
}
}