ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
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()); } } }
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); } } }
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>()); } } } }
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>()); } } }
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); } }
namespace ThinkGeo.MapSuite.USDemographicMap { public enum DemographicStyleBuilderType { Thematic = 0, ValueCircle = 1, DotDensity = 2, PieChart = 3 } }
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 }; } } }
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(); } } }
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; } } } }
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; } } }
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(); } } }
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}; } } }
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; } } }
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()); } } } }
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(); } } } } }
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; } } }
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; } } }
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; } } }
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); } } } }
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); } } } }
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; } } } }
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; } } } }