「Dotspatial」では、標準機能で、複数のマップを並べて表示する機能がなかったので、
プラグインを作成してみました。
マップを並べて表示する機能は、Devexpress社のTabbedViewクラスを利用します。ArcGIS Proでも同様の機能があり、操作方法がほぼ同じになっているので、内部でDevexpress社の部品を使っているかもしれません。
1.複数のマップを並べて表示するプラグイン(SubMapView)の作成
SubMapViewプラグインを作成しまます。プラグインでは、並べて表示ボタンを作成し、このボタンをクリックすると、メインのマップの定義からレイヤなど全ての情報を読み込み、サブマップを作成し、サブマップを含むパネルをDevexpress社のTabbedViewに追加することで、マップを並べて表示することができます。
TabbedViewへの追加処理は、DockingManagerクラスを少し編集します。
作成したサブマップ及び、メインマップに、地図移動時のイベントハンドラーを追加し、双方の地図が同期するようにします。サブマップのレイヤの編集はまだできないので、できたら後日、公開しようかと思います。
以下、SubMapViewプラグインのソースです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
using DevExpress.Utils; using DevExpress.XtraBars.Ribbon; using DevExpress.XtraEditors; using DevExpress.XtraTreeList.Nodes; using DotSpatial.Controls; using DotSpatial.Controls.Docking; using DotSpatial.Data; using DotSpatial.NTSExtension; using DotSpatial.Plugins.SubMapView.Properties; using DotSpatial.Serialization; using DotSpatial.Symbology; using GeoAPI.Geometries; using System; using System.Collections.Generic; using System.Configuration; using System.Drawing; using System.Drawing.Drawing2D; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Windows.Forms; using System.Xml; using System.Xml.Linq; using DevExpress.XtraTreeList; using DotSpatial.Controls.Header; using DotSpatial.Plugins.SubMapView.Properties; namespace DotSpatial.Plugins.SubMapView { public class SubMapViewPlugin : Extension { private const string ViewMenuKey = "ViewMenu"; private SimpleActionItem btnSubMapView; public SubMapViewPlugin() { DeactivationAllowed = false; } private SubMapAreaFunction SubMapAreaFunction { get; set; } private Map SubMap { get; set; } private bool IsBusy { get; set; } public override void Activate() { this.IsBusy = true; this.App.SerializationManager.NewProjectCreated += this.OnNewProjectCreated; this.AddButtons(); base.Activate(); this.IsBusy = false; } public override void Deactivate() { this.App.SerializationManager.NewProjectCreated -= OnNewProjectCreated; this.App.HeaderControl.RemoveAll(); this.App.DockManager.Remove("kMap2"); base.Deactivate(); } private void OnNewProjectCreated(object sender, SerializingEventArgs e) { this.App.DockManager.Remove("kMap2"); } private void AddButtons() { var groupCaption = "地図の表示"; this.App.HeaderControl.Add(new SeparatorItem(ViewMenuKey, groupCaption) { SortOrder = 11 }); this.btnSubMapView = new SimpleActionItem(ViewMenuKey, "並べて表示", this.OnSubMapViewClick) { GroupCaption = groupCaption, LargeImage = Resources.SplitMap_32x32, SmallImage = Resources.SplitMap_16x16 }; this.App.HeaderControl.Add(this.btnSubMapView); } private void OnSubMapViewClick(object sender, EventArgs e) { this.CreateSubMap(); base.App.Map.MapFrame.ViewExtentsChanged += OnMapViewExtentsChanged; this.SubMap.MapFrame.ViewExtentsChanged += OnSubMapViewExtentsChanged; this.btnSubMapView.Enabled = false; } private void CreateSubMap() { this.SubMap = new DotSpatial.Controls.Map(); this.SubMap.BackColor = System.Drawing.Color.White; this.SubMap.CollisionDetection = false; this.SubMap.ExtendBuffer = true; this.SubMap.FunctionMode = DotSpatial.Controls.FunctionMode.None; this.SubMap.IsBusy = false; this.SubMap.IsZoomedToMaxExtent = false; this.SubMap.Name = "subMap"; this.SubMap.ProjectionModeDefine = DotSpatial.Controls.ActionMode.Prompt; this.SubMap.ProjectionModeReproject = DotSpatial.Controls.ActionMode.Prompt; this.SubMap.RedrawLayersWhileResizing = false; this.SubMap.SelectionEnabled = true; this.SubMap.TabIndex = 4; this.SubMap.Tag = "SubMap"; this.SubMap.ZoomOutFartherThanMaxExtent = false; this.SubMap.FunctionMode = FunctionMode.Pan; this.SubMap.Projection = this.App.Map.Projection; this.SubMap.MapFrame.ProjectionModeDefine = ActionMode.Always; this.App.DockManager.Add(new DockablePanel("kMap2", "地図2", this.SubMap, DockStyle.Fill)); this.App.DockManager.PanelRemoved += this.OnPanelRemoved; this.LoadSubMap(); this.SubMap.Invalidate(); } private void OnPanelRemoved(object sender, DockablePanelEventArgs e) { if (e.ActivePanelKey == "kMap2") { this.btnSubMapView.Enabled = true; } } private void LoadSubMap() { var fileName = this.App.SerializationManager.CurrentProjectFile; var graph = new object[] { new string[0], this.App.Map, new Dictionary<string, object>() }; var serializer = new XmlSerializer(); var xml = serializer.Serialize(graph); var graph2 = new object[] { new string[0], this.SubMap, new Dictionary<string, object>() }; var deserializer = new XmlDeserializer(); deserializer.Deserialize(graph2, xml); } private void OnMapViewExtentsChanged(object sender, ExtentArgs args) { if (this.SubMap != null && !this.IsBusy) { this.IsBusy = true; this.SubMap.ViewExtents = this.App.Map.ViewExtents; this.IsBusy = false; } } private void OnSubMapViewExtentsChanged(object sender, ExtentArgs args) { if (!this.IsBusy) { this.IsBusy = true; this.App.Map.ViewExtents = this.SubMap.ViewExtents; this.IsBusy = false; } } } } |
2.サブマップを含むパネルをTabbedViewに追加
TabbedViewへの追加処理は、DockingManagerクラスのAddメソッドを少し編集します。サブマップのパネルが追加された際、DocumentGroupクラスも追加することで、パネルが並んで表示されます。
この処理は、Visual Studioでソースを並べて表示させる場合と同じ処理になります。
以下、DockingManagerクラスの変更箇所のソースです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public void Add( DockablePanel panel ) { // 省略 // サブマップのパネルが追加 if ( panel.Dock == DockStyle.Fill ) { var docs = this.tabbedView.Documents.ToList(); if (docs.Count == 0) { this.tabbedView.Controller.Dock(dockPanel); } else { var group = new DocumentGroup(); this.tabbedView.DocumentGroups.Add(group); this.tabbedView.Controller.Dock(dockPanel, group); } } // 省略 } |
これだけ、短いコードで実現できたのは、Devexpress社と、DotSpatialの機能が優れているからだと思います。本当に優れたソフトウェアです。
地理院タイルのレイヤでも試してみましたが、うまく動いています。よくあるのが、
航空写真を見ながら、図面を確認するといった業務に使えそうです。