google-code-prettify

顯示具有 程式開發 標籤的文章。 顯示所有文章
顯示具有 程式開發 標籤的文章。 顯示所有文章

星期四, 9月 15, 2022

【Python】將 Python Script 編譯成 執行檔(Executable File)

 口白:

流動的水沒有形狀,漂流的風找不到蹤跡,任何案件的 Coding 都取決於心
唯一看透真相的是,外表看似卜朧共,智慧卻低於常人的 名卜朧共 刻爛
(謎之音:把 Code 刻到爛簡稱刻爛.爛..爛...)
Music:
#表升半音 []表高八度
4 3 2 6 4 2 3 #6 6 5 4 5 4 5 6 4 3 2 5 4 3 4 2 6 4 5 [2] [1] #6 6 5 6
4 3 2 6 4 2 3 #6 6 5 4 5 4 5 6 4 3 2 4 3 2 4 2 6 4 5 [2] #6 6 5 6
口白:
刻爛:真実はいつも一つ!

環境:
Linux Mint 下使用 Python 3.8.10
Windows X下使用 Python 3.10 .6

狀況:
將 .Py 的 Python Script 編譯成 執行檔(Executable File)

要如何實做?問問谷哥吧…沒有谷哥罩…我就廢了…
以下就以 MS Windows X 的環境進行吧

流程:
1. 安裝 軟體
1.1 PYTHON3.X
1.2 chrome
2. 更新 與 安裝 Python 的套件
2.1 編譯執行檔需要的套件
2.2 專案需要的套件
3. Python Script 編譯成 執行檔(Executable File)

參考文獻:

那我們開始吧...
1. 安裝 軟體
     去官網下載並安裝軟體吧
1.1 PYTHON3.X
安裝吧,就讓我們向那些寫書的大師致敬
(謎之音:你就懶吧…光安裝就佔了三分之一篇幅)

選擇自訂安裝
就裝想裝的東西吧
基本要裝有 pip ...如果不喜歡 notepad 那就裝 IDLE 開發工具吧

必勾選 將 Python 加入環境變數
(目的是可以在 MSDOS Command line 下執行 Python)

Python 安裝完成

1.2 chrome
要谷哥罩...必裝
安裝 Chrome

2. 更新 與 安裝 Python 的套件
用下列指令安裝需要的套件

2.1 編譯執行檔需要的套件
py -m pip install --upgrade pip
py -m pip install --upgrade pyinstaller
py -m pip install --upgrade auto-py-to-exe

2.2 專案需要的套件
py -m pip install --upgrade matplotlib
py -m pip install --upgrade ezdxf

用檔案總管 在 Python 專案目錄下,路徑列中下 cmd 開啟命令提示字元

命令提示字元 開啟囉

裝裝裝...



(謎之音:你再懶吧…)

3. Python Script 編譯成 執行檔(Executable File)

使用 auto-py-to-exe ,在命令提示字元下 輸入auto-py-to-exe
它將會使用 Chrome 來開啟,這就是為什麼要裝它了

使用參數 --hidden-import 加入專案需要的套件
(我第一次編譯出錯,再把出錯的套件加入)

可輸出成單檔,CLI 程式
並產生編譯指令
(謎之音:就是懶的打字吧…)

編譯中...

編譯完成...

完...
(未完待續)



星期五, 2月 14, 2020

【GIS】MapWinGIS ocx 建置

口白:
流動的水沒有形狀,漂流的風找不到蹤跡,任何案件的 Coding 都取決於心
唯一看透真相的是,外表看似卜朧共,智慧卻低於常人的 名卜朧共 刻爛
(謎之音:把 Code 刻到爛簡稱刻爛.爛..爛...)
Music:
#表升半音 []表高八度
4 3 2 6 4 2 3 #6 6 5 4 5 4 5 6 4 3 2 5 4 3 4 2 6 4 5 [2] [1] #6 6 5 6
4 3 2 6 4 2 3 #6 6 5 4 5 4 5 6 4 3 2 4 3 2 4 2 6 4 5 [2] #6 6 5 6
口白:
刻爛:真実はいつも一つ!

流程主軸:
1. 下載檔案( MapWinGIS V5.1.1、gdal and mapserver 需選擇對應開發工具及版本)
2. 環境說明
2.1 基礎環境
2.2 必要安裝
3. 原碼編譯
3.1 解壓縮
3.2 編譯 SupportLibs
3.3 編譯 MapWinGIS

1. 下載檔案
下載 MapWinGIS V5.1.1


下載  GDAL and Mapserver
有分 64bit  or 32bit  版本並且有對應開發工具 MSVC 2017 與 MSVC 2015 等等版本,
依據開發工具對應下載吧

使用 VS2015
release-1900-gdal-2-4-2-mapserver-7-4-0.zip、
release-1900-gdal-2-4-2-mapserver-7-4-0-libs.zip
使用 VS2017、VS2019(2017 老子不爽裝,2019 硬幹啦)
release-1911-gdal-2-4-2-mapserver-7-4-0.zip、
release-1911-gdal-2-4-2-mapserver-7-4-0-libs.zip
(有很多對應版本,只測成功過VS2015 x86 對 1900;VS2019 對 1911)

在 [Tutorial] Compiling MWGis in VS2017 有說了一段話
所以,只測過 32bit 版本囉(謎之音:有病嗎?頻寬很多嗎?抓那麼多檔案是有收集癖)

2. 環境說明
2.1 基礎環境
作業系統:Windows 10 64Bit
開發工具:Microsoft Visual Studio Enterprise 2019
2.2 必要安裝
安裝完 Visual Studio 2019 後,使用 Visual Studio Installer 安裝環境
需要安裝 【.NET 桌面開發】
【使用 C++ 的桌面開發】 需要 v142 建置工具的 C++ MFC(x86 & x64...)
【使用 C++ 的桌面開發】 需要 Windows 10 SDK (10.0.17...)

3. 原碼編譯
3.1 解壓縮
分別解壓縮兩個壓縮檔
release-1900-gdal-2-4-2-mapserver-7-4-0.zip
release-1900-gdal-2-4-2-mapserver-7-4-0-libs.zip

release-1911-gdal-2-4-2-mapserver-7-4-0.zip
release-1911-gdal-2-4-2-mapserver-7-4-0-libs.zip

Visual Studio 2015 對的版本號是 v140( MapWinGIS-4.9.3.6编译方法 ) ;
Visual Studio 2017 對的版本號是 v141( youtube 上是這樣教的);
Visual Studio 2019 對的版本號是 v142(嘗試把v142目錄建立起來,編譯是成功的)
將 release-1900-gdal-2-4-2-mapserver-7-4-0 壓說檔內的 bin 資料夾的檔案複製到
MapWinGIS-5.1.1.1\support\GDAL_SDK\v140\bin\win32\ 資料夾中



將 release-1900-gdal-2-4-2-mapserver-7-4-0-libs 壓說檔內
include 資料夾的檔案複製到
MapWinGIS-5.1.1.1\support\GDAL_SDK\v142\include\win32\ 資料夾中

lib 資料夾的檔案複製到
MapWinGIS-5.1.1.1\support\GDAL_SDK\v142\lib\win32\ 資料夾中


3.2 編譯 SupportLibs
以管理員身份使用 VS2019 打開 MapWinGIS-5.1.1.1\support\ 資料夾裡的 SupportLibs.sln
編譯 cqlib.lib 和 spatialindex-mw.lib

在【解決方案】上,按右鍵  打開【屬性】 設定界面,將【通用屬性】中的【起始專案】
改成多個啟始專案

在【解決方案】上,點選它,然後點選【屬性】頁籤,
將【使用中的組態】的屬性改成 Release|Win32

完成以上設定後,就可以按下 F6  來建置方案
建置完成就會產生 spatialindex-mw.lib、cqlib.lib

3.3 編譯 MapWinGIS
以管理員身份使用 VS2019 打開 MapWinGIS-5.1.1.1\src 資料夾裡的 MapWinGIS.sln
修改 AngleHelper.cpp 檔案

s.Format(format + L"?, angle); //L"%.1f?
改成
s.Format(format + L"%.1f", angle); //L"%.1f?

接下來就可以建置它囉
完成後會產出 MapWinGIS.ocx

建置是成功了能不能用不知道啦
下次搭配 MapWindow 試看看好了
下回可能跟冨樫 yoshirin 的獵人一樣不知何時才會有下ㄧ回不要期待吧

                                                                                                                                                 (未完待續…)

參考文獻:
【Github】MapWinGIS v5.1.1
GDAL and MapServer Older Releases
【Blog】MapWinGIS-4.9.3.6编译方法
[Tutorial] Compiling MWGis in VS2017
【Youtube】Compiling MWGis in VS2017






星期六, 11月 09, 2019

【EF】EntityFrameworkCore 存取空間資料 Geometry 欄位…私、失敗しないので(我,絕對不會失敗)

劇情講述的是:
直言敢諫的派遣工 EntityFrameworkCore,討厭結群、討厭權力、討厭束縛,以其專業以及高超的技術作為武器,勇於挑戰白色巨塔封建體系的故事。

不需要資料庫的事情 EntityFrameworkCore 一律不做,
像是幫教授寫論文… いたしません(不幹)、
參加院長巡房… いたしません(不幹)、
配合掩護小三等等全都… いたしません(不幹),
且一定要準時下班,若要額外加班、要另外收高額費用…

自從 EntityFramework 誕生,也過了好幾個年頭…

維基百科:
Entity Framework (又稱ADO.NET Entity Framework)
是微軟以 ADO.NET 為基礎所發展出來的物件關聯對應 (O/R Mapping) 解決方案,
早期被稱為 ObjectSpace,
ADO.NET Entity Framework 以 Entity Data Model (EDM) 為主,
將資料邏輯層切分為三塊,
分別為 Conceptual Schema, Mapping Schema 與 Storage Schema 三層,
其上還有 Entity Client,Object Context 以及 LINQ 可以使用。

第一版 發行日期:2008-8-11 Entity Framework (EFv1) 包含在 Visual Studio 2008 Service Pack 1 以及 .NET Framework 3.5 Service Pack 1 中發表。
第二版 發行日期:2010-4-12 名為:Entity Framework 4.0 (EFv4) 。
第三版 發行日期:2011-4-12 名為:Entity Framework 4.1  開始支援 Code First。
…  光陰似箭,歲月如梭 …(謎之音:偷懶…)
第6版 發行日期:2013-10-17

微軟隨後決定對 .NET 跨平台化,並將其引入Linux,OSX和其他地方,
這意味著 Entity Framework 的下一個版本將被完全重寫。
2016-6-27 作為 Entity Framework Core 1.0 與 ASP.NET Core 1.0 和.NET Core 1.0 發布。
它最初命名為Entity Framework 7,但經過重命名以強調它是完全重寫而不是增量升級,並且不替代EF6。

2017-8-14 發布 EF Core 2.0、Visual Studio 2017 15.3、ASP.NET Core 2.0
2019-9-23 發佈 EF Core 3.0、Visual Studio 2019 16.3、ASP.NET Core 3.0

如何讓 EF Core 讀取 Geometry or Geography?
NetFramework 4.7.2,.NetCore 2.0,.NetStarndard 2.0:
===================================================================
Step 0: 專案檔修改
修改 .csproj,使其支援 .NetFramework、.NetCore、.NetStarndard多個版本框架,
netstandard 要放在最後面,不然會說沒有 runtime,無法執行
修改範例如下:
<TargetFrameworks>net472;netcoreapp2.0;netstandard2.0;</TargetFrameworks>

Step 1: 需先從Nuget安裝 or 用 PackageManager 下指令安裝
Nuget安裝 要對應 EF Core 2.0 使用的版本套件
1.Microsoft.EntityFrameworkCore
2.Microsoft.EntityFrameworkCore.Design
3.Microsoft.EntityFrameworkCore.SqlServer
4.Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite
5.Microsoft.EntityFrameworkCore.Tools
6.NetTopologySuite
7.NetTopologySuite.Core

用 PackageManager 下指令安裝:
打開套件管理員主控台:Visual Studio → 工具 → NuGet套件管理員 → 套件管理員主控台
PM> Install-Package Microsoft.EntityFrameworkCore -Version 2.2.6
PM> Install-Package Microsoft.EntityFrameworkCore.Design -Version 2.2.6
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 2.2.6
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite -Version 2.2.6
PM> Install-Package Microsoft.EntityFrameworkCore.Tools -Version 2.2.6
PM> Install-Package NetTopologySuite -Version 1.15.3
PM> Install-Package NetTopologySuite.Core -Version 1.15.3

Step 2: 將目錄移到有 .csproj 檔案的目錄位置
打開套件管理員主控台:Visual Studio → 工具 → NuGet套件管理員 → 套件管理員主控台
輸入
PM> ls 指令 (好親切…微軟 UNIX/Linux 化…)
PM> cd 指令將目錄移到有 .csproj 檔案的目錄位置

Step 3:(只需做一次)
"dotnet ef" 必須安裝為全域或本機工具。 大部分的開發人員會使用下列命令,以全域工具的形式安裝 dotnet ef:
打開套件管理員主控台:Visual Studio → 工具 → NuGet套件管理員 → 套件管理員主控台
PM> dotnet tool install --global dotnet-ef --version 3.0.0
(就是裝最新版…就是可以用咧…)

Step 4:由資料庫反向工程,產生資料庫存取類別庫
PM> dotnet ef dbcontext scaffold "Data Source=伺服器;Initial Catalog=資料庫;User ID=填帳號;Password=填密碼;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" Microsoft.EntityFrameworkCore.SqlServer -d -f -o 輸出目錄

這樣就搞定囉

.NetCore 3.0,.NetStarndard 2.1:
===================================================================
Step 0: 專案檔修改
修改 .csproj,使其支援 .NetFramework、.NetCore、.NetStarndard多個版本框架,
netstandard 要放在最後面,不然會說沒有 runtime,無法執行
修改範例如下:
<TargetFrameworks>netcoreapp3.0;netstandard2.1;</TargetFrameworks>

Step 1: 需先從Nuget安裝 or 用 PackageManager 下指令安裝
Nuget安裝 要對應 EF Core 2.0 使用的版本套件
1.Microsoft.EntityFrameworkCore
2.Microsoft.EntityFrameworkCore.Design
3.Microsoft.EntityFrameworkCore.SqlServer
4.Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite
5.Microsoft.EntityFrameworkCore.Tools
6.NetTopologySuite

用 PackageManager 下指令安裝:
打開套件管理員主控台:Visual Studio → 工具 → NuGet套件管理員 → 套件管理員主控台
PM> Install-Package Microsoft.EntityFrameworkCore -Version 3.0.0
PM> Install-Package Microsoft.EntityFrameworkCore.Design -Version 3.0.0
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 3.0.0
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite -Version 3.0.0
PM> Install-Package Microsoft.EntityFrameworkCore.Tools -Version 3.0.0
PM> Install-Package NetTopologySuite -Version 2.0.0

Step 2: 將目錄移到有 .csproj 檔案的目錄位置
打開套件管理員主控台:Visual Studio → 工具 → NuGet套件管理員 → 套件管理員主控台
輸入
PM> ls 指令 (好親切…微軟 UNIX/Linux 化…)
PM> cd 指令將目錄移到有 .csproj 檔案的目錄位置

Step 3:(只需做一次)
"dotnet ef" 必須安裝為全域或本機工具。 大部分的開發人員會使用下列命令,以全域工具的形式安裝 dotnet ef:
打開套件管理員主控台:Visual Studio → 工具 → NuGet套件管理員 → 套件管理員主控台
PM> dotnet tool install --global dotnet-ef --version 3.0.0
(謎之音:你除了會複製貼上…你還會啥)

Step 4:由資料庫反向工程,產生資料庫存取類別庫
PM> dotnet ef dbcontext scaffold "Data Source=伺服器;Initial Catalog=資料庫;User ID=填帳號;Password=填密碼;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" Microsoft.EntityFrameworkCore.SqlServer -d -f -o 輸出目錄

這樣就搞定囉…
就會產生 包含 Geometry or Geography 類別囉

接下來怎麼用…小愛同學努力了解中…

未完待續…

【參考文獻】
維基百科 中文 Entity_Framework
維基百科 英文 Entity_Framework
微軟繁中 空間資料
微軟英文 空間資料
安裝 Entity Framework Core
.NET standard
Spatial Mapping with NetTopologySuite
NetTopologySuite: InvalidOperationException #18172
Finding Nearby Users with Entity Framework Core Spatial Data
Entity Framework Core support for SQL Spatial Data Types - DBGeography?


星期一, 3月 30, 2015

[EF] 如何用 Entity Framework 給 Date 欄位 Default Date

口白:
流動的水沒有形狀,漂流的風找不到蹤跡,任何案件的 Coding 都取決於心
唯一看透真相的是,外表看似卜朧共,智慧卻低於常人的 名卜朧共 刻爛
(謎之音:把 Code 刻到爛簡稱刻爛.爛..爛...)
Music:
#表升半音 []表高八度
4 3 2 6 4 2 3 #6 6 5 4 5 4 5 6 4 3 2 5 4 3 4 2 6 4 5 [2] [1] #6 6 5 6
4 3 2 6 4 2 3 #6 6 5 4 5 4 5 6 4 3 2 4 3 2 4 2 6 4 5 [2] #6 6 5 6
口白:
刻爛:真実はいつも一つ!

1. 打開 edmx (用 ADO.NET 實體資料模型設計工具打開)
2. 選擇你的 DateTime 欄位
3. 到屬性視窗,並改變 StoreGeneratedPattern 屬性值,從 None 改成 Computed

記得要把資料庫中的欄位定義預設值喔!

參考文獻:stackoverflow blog(code-first)

星期一, 2月 16, 2015

[ArcGIS Server API for JavaScript] 利用 Dojo 框架加入頁籤容器 TabContainer

繼上次案件 [ArcGIS Server API for JavaScript] 利用 Dojo 框架加入手風琴容器 AccordionContainer後, 接下來的案件一樣是繼續 Dojo 基本,加入 頁籤容器 TabContainer
甘她媽︰Life was like a box of chocolates. You never know what you're gonna get.(謎之音:聽媽媽的話...)

口白:
流動的水沒有形狀,漂流的風找不到蹤跡,任何案件的 Coding 都取決於心
唯一看透真相的是,外表看似卜朧共,智慧卻低於常人的 名卜朧共 刻爛
(謎之音:把 Code 刻到爛簡稱刻爛.爛..爛...)
Music:
#表升半音 []表高八度
4 3 2 6 4 2 3 #6 6 5 4 5 4 5 6 4 3 2 5 4 3 4 2 6 4 5 [2] [1] #6 6 5 6
4 3 2 6 4 2 3 #6 6 5 4 5 4 5 6 4 3 2 4 3 2 4 2 6 4 5 [2] #6 6 5 6
口白:
刻爛:真実はいつも一つ!

延續了前案件[ArcGIS Server API for JavaScript] 利用 Dojo 框架加入手風琴容器 AccordionContainer
這次是在這篇的基礎上,加入 頁籤容器 TabContainer,再次回到 Dojo 基本吧!

Html:
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
    <link href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css" rel="stylesheet" type="text/css"></link>
    <script src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js" type="text/javascript">
    </script>
    <title>dijit layout AccordionContainer</title>
    <link rel="stylesheet" href="http://js.arcgis.com/3.12/dijit/themes/claro/claro.css">
    <link rel="stylesheet" href="http://js.arcgis.com/3.12/esri/css/esri.css">    
    <script src="http://js.arcgis.com/3.12/"></script>
  </head>
  <body class="claro" expr:class='&quot;loading&quot; + data:blog.mobileClass' onload='prettyPrint();'>
    <!-- MenuBar div#navMenu -->
    <div data-dojo-type="dijit/MenuBar" id="navMenu">
      <div data-dojo-type="dijit/PopupMenuBarItem">
        <span>地圖</span>
        <div data-dojo-type="dijit/DropDownMenu" id="mapMenu">
          <div data-dojo-type="dijit/MenuItem" data-dojo-props="onClick:function(){alert('地圖操作')}">地圖操作</div>
        </div>
      </div>
    </div>
    <!-- MenuBar div#navMenu -->

    <div style="width: 300px; height: 300px; position: absolute; z-index: 999; top: 60px; right: 50px;">
      <div data-dojo-type="dijit/layout/AccordionContainer" style="height: 300px;">
        <div data-dojo-type="dijit/layout/ContentPane" selected="true" title="工具列">
          <div id="navToolbar" data-dojo-type="dijit/Toolbar" style="width:50%;">
            <div data-dojo-type="dijit/form/Button" id="zoomin"  data-dojo-props="iconClass:'zoominIcon'">Zoom In</div>
            <div data-dojo-type="dijit/form/Button" id="zoomout" data-dojo-props="iconClass:'zoomoutIcon'">Zoom Out</div>
            <div data-dojo-type="dijit/form/Button" id="zoomfullext" data-dojo-props="iconClass:'zoomfullextIcon'">Full Extent</div>
            <div data-dojo-type="dijit/form/Button" id="zoomprev" data-dojo-props="iconClass:'zoomprevIcon'">Prev Extent</div>
            <div data-dojo-type="dijit/form/Button" id="zoomnext" data-dojo-props="iconClass:'zoomnextIcon'">Next Extent</div>
            <div data-dojo-type="dijit/form/Button" id="pan" data-dojo-props="iconClass:'panIcon'">Pan</div>
            <div data-dojo-type="dijit/form/Button" id="deactivate" data-dojo-props="iconClass:'deactivateIcon'">Deactivate</div>
          </div>            
        </div>
        <div data-dojo-type="dijit/layout/ContentPane" title="圖例">
          <div data-dojo-type="dijit/layout/ContentPane" id="legendPane"
                 data-dojo-props="title:'Legend', selected:true" style="height:50px;" >
            <div id="legendDiv"></div>
          </div>
        </div>
      </div>
    </div>
        <div data-dojo-type="dijit/layout/ContentPane" title="頁籤" style="padding: 0px; width: 100%; height: 180px;">
          <div data-dojo-type="dijit/layout/ContentPane" id="DivTabContainerPane1"
                 data-dojo-props="title:'TabContainer', selected:true" style="padding: 0px; width: 100%; height: 180px;" >
            <div style="width: 100%; height: 100%; ">
              <div data-dojo-type="dijit/layout/TabContainer" style="width: 100%; height: 100%;">
                <div data-dojo-type="dijit/layout/ContentPane" title="甘他媽說" data-dojo-props="selected:true">
                    Life was like a box of chocolates. You never know what you're gonna get.
                </div>
                <div data-dojo-type="dijit/layout/ContentPane" title="甘他媽又說">
                    My momma always said you could tell a lot about a person by the shoes they wear.
                </div>
                <div data-dojo-type="dijit/layout/ContentPane" title="甘:" data-dojo-props="closable:true">
                    Now you wouldn't believe me if I told you, but I could run like the wind blows. From that day on, if I was ever going somewhere, I was running!
                </div>
              </div>
            </div>
          </div>
        </div>

        <div data-dojo-type="dijit/layout/ContentPane" title="頁籤(code)" style="padding: 0px; width: 100%; height: 180px;">
          <div data-dojo-type="dijit/layout/ContentPane" id="DivTabContainerPane2"
                 data-dojo-props="title:'TabContainer', selected:true" style="padding: 0px; width: 100%; height: 180px;" >
            <div style="width: 100%; height: 100%; margin:0px; ">
              <div id="tc1-prog"></div>
            </div>
          </div>
        </div>

    <div id="mapDiv" 
         data-dojo-type="dijit/layout/ContentPane" 
         data-dojo-props="region:'center'" 
         style="padding:0">
    </div>

  </body>
</html>
說明:
1. 引用 CSS:claro.css、esri.css 引用參考位置如下:
   <link rel="stylesheet" href="http://js.arcgis.com/3.12/dijit/themes/claro/claro.css">
   <link rel="stylesheet" href="http://js.arcgis.com/3.12/esri/css/esri.css">  為了中文化排版被擠壓 修改 CSS

2. 引用 Javascript 需插入  <script src="http://js.arcgis.com/3.12/"></script> 其中已包含了Dojo框架囉

3. <body> 標籤中 加入 class 樣式定義為 "claro" 如: <body class="claro">

4. 加入 div 區塊 當作 MenuBar,如:<div data-dojo-type="dijit/MenuBar" id="navMenu"></div>

5. 加入 div 區塊 當作 PopupMenuBarItem,將該物件放在 MenuBar Div 區塊內 如:
   <div data-dojo-type="dijit/PopupMenuBarItem">
   </div>
   給該選單名稱,則是在 PopupMenuBarItem div 區塊 內加入 <span>地圖</span> 來定義
   加入 div 區塊 當作 DropDownMenu,將該物件放在 PopupMenuBarItem Div 區塊內 如:
   <div data-dojo-type="dijit/DropDownMenu" id="mapMenu">
   </div>
   加入 div 區塊 當作 MenuItem,將該物件放在 DropDownMenu Div 區塊內 如:
   <div data-dojo-type="dijit/MenuItem" data-dojo-props="onClick:function(){alert('地圖操作')}">地圖操作</div>

6. 加入 div 區塊 當作 dijit/layout/AccordionContainer 容器 外框,
   並定義樣式 style="width: 300px; height: 300px; position: absolute; z-index: 999; top: 60px; right: 50px;"
   於該 div 區塊 內加入 div 區塊 當作 dijit/layout/AccordionContainer 容器 ,
   並將 dijit/layout/ContentPane 物件放在 dijit/layout/AccordionContainer Div 區塊內,如:
   <div style="width: 300px; height: 300px; position: absolute; z-index: 999; top: 60px; right: 50px;">
     <div data-dojo-type="dijit/layout/AccordionContainer" style="height: 300px;">
       <div data-dojo-type="dijit/layout/ContentPane" selected="true" title="工具列">
    ... 略...
       </div>
     </div>
   </div>
   dijit/layout/AccordionContainer 為手風琴主要框架,
   而在 dijit/layout/AccordionContainer 內的 dijit/layout/ContentPane 為手風琴的每一節,
   故我們可以定義 title="名稱";selected="預設顯示"(只能設在單一節點上)

7. 接著我們可以把工具擺放進手風琴節點內,主要是將 DOM 物件擺入 dijit/layout/AccordionContainer DIV 區塊內
   因此我們可以把之前寫過的 Toolbar、legendPane 分別放入不同的 dijit/layout/ContentPane 內
   於 第一個 dijit/layout/ContentPane div 區塊 內 加入 div 區塊 當作 dijit/Toolbar 容器,
   並將 dijit/form/Button 物件放在 navToolbar Div 區塊內 如:
   <div id="navToolbar" data-dojo-type="dijit/Toolbar" >
     <div data-dojo-type="dijit/form/Button" id="zoomin"  data-dojo-props="iconClass:'zoominIcon'">Zoom In</div>
   ...略....
   </div>

   於 第二個 dijit/layout/ContentPane div 區塊 內 加入 div 區塊 當作 legendPane 區塊,如:<div id="legendPane" ...略.../div>,
   於 div 區塊 legendPane 中,加入 當作 legendDiv 區塊,如:<div id="legendDiv" ...略.../div>
   此 div 區塊 legendDiv 區塊,是用來展現 legend 用

8. 加入 div 區塊 當作主要頁籤 dijit/layout/ContentPane 容器 外框,這裡分為兩部份,一種為html來實現、另一種透過code來實現,
   基本上就是大腸包小腸的概念.就是在dijit/layout/ContentPane 容器 裡面 包頁籤 dijit/layout/TabContainer 容器,
   在 dijit/layout/TabContainer 容器 裡面 包頁籤 dijit/layout/ContentPane 容器…就像無間地獄一樣

9. 加入 div 區塊 當作地圖區塊,如:<div id="mapDiv"></div>

CSS:
.esriScalebarLabel.esriScalebarLineLabel.esriScalebarSecondNumber {
  font-size: 11px;
  position: absolute;
  width: 50%;
  text-align: center;
  color: #666666;
  font: Verdana;
  font-weight: bolder;
  height: 5px;
  top: -1px;
}
html, body, #mapDiv {
  padding: 0;
  margin: 0;
  height: 100%;
}
.zoominIcon 
{
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_zoomin.png);
  width: 16px;
  height: 16px;
}

.zoomoutIcon 
{
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_zoomout.png);
  width: 16px;
  height: 16px;
}

.zoomfullextIcon 
{
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_fullextent.png);
  width: 16px;
  height: 16px;
}

.zoomprevIcon 
{
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_previous.png);
  width: 16px;
  height: 16px;
}

.zoomnextIcon 
{ 
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_next.png);
  width: 16px;
  height: 16px;
}

.panIcon 
{
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_pan.png);
  width: 16px;
  height: 16px;
}

.deactivateIcon 
{
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_decline.png);
  width: 16px;
  height: 16px;
}
.NavToolBar 
{
  width: 120px; position: absolute; z-index: 999; height: auto; top: 60px; right: 50px;
}
.LegendTool
{
  width: 200px; position: absolute; z-index: 999; height: 600px; top: 60px; left: 50px;
}
說明:
1. 定義 mapDiv 區塊的 CSS 樣式
2. 中文化 排版被擠壓 .esriScalebarLabel.esriScalebarLineLabel.esriScalebarSecondNumber 調整width 改成 50%
3. 定義 zoominIcon、zoomoutIcon、zoomfullextIcon、zoomprevIcon、zoomnextIcon、panIcon、deactivateIcon 樣式,其中包含工具圖示
4. 定義 LegendTool、NavToolBar 樣式,定義大小位置(放入手風琴後不使用,避免干擾版型)

JavaScript:
var map;
require([
  "esri/map",
  "dojo/parser",

  // Modules referenced by the parser
  "dijit/DropDownMenu",
  "dijit/MenuBar",
  "dijit/MenuBarItem",
  "dijit/MenuItem",
  "dijit/PopupMenuBarItem",

  // ArcGISDynamicMapServiceLayer 會使用到的模組 
  "esri/layers/ArcGISDynamicMapServiceLayer", // 加入 Arcgis Server 發布ArcGISDynamicMapServiceLayer圖層 Package
  // ArcGISDynamicMapServiceLayer 會使用到的模組 

  // Legend 會使用到的模組 
  "dojo/_base/array",       // 加入 dojo/_base/array Package 
  "esri/dijit/Legend",      // 加入 esri/dijit/Legend Package 
  // Legend 會使用到的模組 

  // Overview 會使用到的模組 
  "esri/dijit/OverviewMap", // 加入 Overview Package 
  // Overview 會使用到的模組 

  // Scalebar 會使用到的模組 
  "esri/dijit/Scalebar",    // 加入 Scalebar Package 
  // Scalebar 會使用到的模組 

  // TabContainer 會使用到的模組
  "dijit/layout/ContentPane",
  "dijit/layout/TabContainer",
  // TabContainer 會使用到的模組

  // navigation ToolBar 會使用到的模組 
  // "dojo/parser", navigation ToolBar 會使用到的模組 也會使用到前面已經宣告過就不重覆載入
  "esri/toolbars/navigation",
  "dojo/on",
  "dijit/registry",
  "dijit/Toolbar",              // 因為本身並沒有針對對應物件操作,故不設定 載入對應 變數
  "dijit/form/Button",          // 因為本身並沒有針對對應物件操作,故不設定 載入對應 變數
  // navigation ToolBar 會使用到的模組 

  // AccordionContainer 會使用到的模組 
  // "dojo/parser", AccordionContainer 會使用到的模組 也會使用到前面已經宣告過就不重覆載入
  "dijit/layout/AccordionContainer", 
  //"dijit/layout/ContentPane", // AccordionContainer 會使用到的模組 也會使用到前面已經宣告過就不重覆載入
  // AccordionContainer 會使用到的模組 

  "dojo/domReady!"
], function (
  Map,
  parser,

  DropDownMenu,
  MenuBar,
  MenuBarItem,
  MenuItem,
  PopupMenuBarItem,

  // ArcGISDynamicMapServiceLayer 會使用到的模組 對應變數
  ArcGISDynamicMapServiceLayer, // 加入 ArcGISDynamicMapServiceLayer 承接 對應 "esri/layers/ArcGISDynamicMapServiceLayer" ArcGISDynamicMapServiceLayer Package  變數
  // ArcGISDynamicMapServiceLayer 會使用到的模組 對應變數

  // Legend 會使用到的模組 對應變數
  arrayUtils,    // 加入 arrayUtils 承接 對應 "dojo/_base/array" Package  變數
  Legend,        // 加入 Legend 承接 對應 "esri/dijit/Legend" Package  變數
  // Legend 會使用到的模組 對應變數

  // OverviewMap 會使用到的模組 對應變數
  OverviewMap,   // 加入 OverviewMap 承接 對應 "esri/dijit/OverviewMap" OverviewMap Package  變數
  // OverviewMap 會使用到的模組 對應變數

  // Scalebar 會使用到的模組 對應變數
  Scalebar,      // 加入 Scalebar 承接 對應 "esri/dijit/Scalebar" Scalebar Package  變數
  // Scalebar 會使用到的模組 對應變數

  // TabContainer 會使用到的模組 對應變數
  ContentPane,
  TabContainer,
  // TabContainer 會使用到的模組 對應變數

  // navigation ToolBar 會使用到的模組 對應變數
  // parser,, navigation ToolBar 會使用到的模組 也會使用到前面已經宣告過就不重覆載入
  Navigation,
  on,        
  registry        
  // navigation ToolBar 會使用到的模組 對應變數 

  )
{
  parser.parse();

  var navToolbar;
        
  var layer;
        
  var tc; // TabContainer
  var cp1, cp2;

  function extentHistoryChangeHandler() {
    registry.byId("zoomprev").disabled = navToolbar.isFirstExtent();
    registry.byId("zoomnext").disabled = navToolbar.isLastExtent();
  }

  // 中文化 S
  //console.log(esri.bundle.widgets.scalebar);
  esri.bundle.widgets.scalebar = { ft: "英呎", km: "公里", mi: "英里", m: "公尺" }; // 目前無作用
  window.esri.dijit.Scalebar.prototype.localStrings.km = '公里';
  window.esri.dijit.Scalebar.prototype.localStrings.m = '公尺';
  window.esri.dijit.Scalebar.prototype.localStrings.mi = '英里';
  window.esri.dijit.Scalebar.prototype.localStrings.ft = '英呎';
  //console.log(domStyle.getComputedStyle(dojo.query('.esriScalebarLabel.esriScalebarLineLabel.esriScalebarSecondNumber')).width);
  //domStyle.set(dojo.query('.esriScalebarLabel.esriScalebarLineLabel.esriScalebarSecondNumber'), "width", "50%");
  /*
  esri.css 
  修改 .esriScalebarLabel.esriScalebarLineLabel.esriScalebarSecondNumber 
  width:10% 改 width:50%
  */
  //console.log(esri.bundle.widgets.scalebar);
  // 中文化 E

         map = new Map("mapDiv",
    {
      //center: [182367.85715, 2561474.641595]
      //zoom: 8,
      //basemap: "streets",
      //sliderStyle:'large'
      basemap:"satellite",
      center :[-97.031, 37.638],
      zoom   :4,
      //slider :false
    sliderStyle:'large'
    });
  
  layer = new esri.layers.ArcGISDynamicMapServiceLayer(
    'http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Median_Net_Worth/MapServer', 
    {opacity: 1.0});
  //console.log('ArcGISDynamicMapServiceLayer');
  
  
  //add the legend
  map.on("layers-add-result", function (evt) {
    var layerInfo = arrayUtils.map(evt.layers, function (layer, index) {
      return { layer: layer.layer, title: layer.layer.name };
    });
    if (layerInfo.length > 0) {
      var legendDijit = new Legend({
        map: map,
        layerInfos: layerInfo
      }, "legendDiv");
      legendDijit.startup();
    }
  });
  //add the legend
  map.addLayers([layer]);

  // 加入 OverviewMap 地圖上顯示鷹眼 開始
  var overviewMapDijit = new OverviewMap({
    map: map,
    attachTo: "bottom-right",
    visible: true
  });
  overviewMapDijit.startup();
  // 加入 OverviewMap 地圖上顯示鷹眼 結束

  // 加入 scalebar 地圖上顯示比例尺 開始
  var scalebar = new Scalebar({
    map: map,
    // "dual" displays both miles and kilmometers
    // "english" is the default, which displays miles
    // use "metric" for kilometers
    scalebarUnit: "dual"
  });
  scalebar.hide();
  scalebar.show();
  // 加入 scalebar 地圖上顯示比例尺 結束

  navToolbar = new Navigation(map);
  on(navToolbar, "onExtentHistoryChange", extentHistoryChangeHandler);

  registry.byId("zoomin").on("click", function () {
    navToolbar.activate(Navigation.ZOOM_IN);
  });

  registry.byId("zoomout").on("click", function () {
    navToolbar.activate(Navigation.ZOOM_OUT);
  });

  registry.byId("zoomfullext").on("click", function () {
    navToolbar.zoomToFullExtent();
  });

  registry.byId("zoomprev").on("click", function () {
    navToolbar.zoomToPrevExtent();
  });

  registry.byId("zoomnext").on("click", function () {
    navToolbar.zoomToNextExtent();
  });

  registry.byId("pan").on("click", function () {
    navToolbar.activate(Navigation.PAN);
  });

  registry.byId("deactivate").on("click", function () {
    navToolbar.deactivate();
  });

  tc = new TabContainer({
    style: "height: 100%; width: 100%;"
  }, "tc1-prog");
  
  cp1 = new ContentPane({
    title: "Jenny",
    content: "Run! Forrest! Run!"
  });
  tc.addChild(cp1);
  
  cp2 = new ContentPane({
    title: "Recruit Officer",
    content: "Nobody gives a hunk of shit who you are, pussball! You're not even a low-life, scum-sucking maggot! Get your faggoty ass on the bus, you're in the Army now![Forrest quickly gets on the Army bus]"
  });
  tc.addChild(cp2);
  
  tc.startup();

});

說明:
1. 定義 弱型別的變數 map
   .require 是 Dojo 方法,利用該方法,
   載入 esri/map、dojo/parser、dijit/DropDownMenu、MenuBar、MenuBarItem、MenuItem、PopupMenuBarItem、esri/dijit/Scalebar、dojo/domReady! 
   Navigation 瀏覽工具 需用到的模組 esri/toolbars/navigation,dojo/on,dijit/registry,
   Navigation 瀏覽工具 也需要 dojo/parser (載入模組不需重複載入)
   而 dijit/Toolbar,dijit/form/Button,因為本身並沒有針對對應物件操作,故不設定 載入對應 變數
   要加入 ArcGISDynamicMapServiceLayer 圖層,需用到的模組 esri/layers/ArcGISDynamicMapServiceLayer,
   要加入 AccordionContainer 手風琴容器,需用到的模組 dijit/layout/AccordionContainer、dijit/layout/ContentPane,
   因為本身並沒有針對對應物件操作,故不設定 載入對應 變數

   根據 Dojo API 參考文件來說,
   載入模組後,需用一個 變數來接收該模組,以便於操作 
   例如 function(Map) {}  用一個 拋棄式的函數,
   裡面定義變數: Map、parser、DropDownMenu、MenuBar、MenuBarItem、MenuItem、PopupMenuBarItem、Scalebar,
   Navigation 定義對應變數: Navigation、on、registry。
   ArcGISDynamicMapServiceLayer 定義對應變數: ArcGISDynamicMapServiceLayer。        

2. function(Map...略...) {}  用一個 拋棄式的函數 裡面定義 map 變數,
   透過傳入的 Map 類別可以 宣告成一個 esri/map 的物件,其他載入的亦同方式
   parser.parse() 主要是將 dom 轉換成 dijit 物件或是 widget
   (new Map 宣告方法 就要查 https://developers.arcgis.com/javascript/jsapi/map-amd.html )
   另外因為載入 ArcGISDynamicMapServiceLayer 圖層與 basemap 坐標系統不一樣,故 new Map(...,OPTIONS),
   物件 OPTIONS 中,定義的center 原本為 WGS84 經緯度,要改成 TWD97:EPSG定義為3826 或 102443,的坐標
   並且把 basemap、zoom(可以不用註解) 參數註解掉,原因是坐標系統不一致套疊會有問題
   定義 弱型別的變數 layer  並將他 建立成 esri.layers.ArcGISDynamicMapServiceLayer 物件
   (new ArcGISDynamicMapServiceLayer 宣告方法 就要查 https://developers.arcgis.com/javascript/jsapi/arcgisdynamicmapservicelayer-amd.html" )
    ArcGISDynamicMapServiceLayer 範例 
   Url 部分,就是設定 ArcGIS Server 發布服務的位置
   options 部分,就是針對載入圖層相關設定,例如:透明度:opacity,顯示與否:visible。
   定義 弱型別的變數 overviewMapDijit  並將他 建立成 esri/dijit/OverviewMap 物件
   (new overviewMapDijit 宣告方法 就要查 https://developers.arcgis.com/javascript/jsapi/overviewmap-amd.html" )
   widget overviewmap 範例 
   定義 弱型別的變數 scalebar 並將他 建立成 esri/dijit/Scalebar 物件
   (new Scalebar 宣告方法 就要查 https://developers.arcgis.com/javascript/jsapi/scalebar-amd.html )
   widget scalebar 範例 
   定義 弱型別的變數 navToolbar  並將他 建立成 esri/toolbars/navigation 模組 Navigation 物件
   (new navToolbar 宣告方法 就要查 https://developers.arcgis.com/javascript/jsapi/navigation-amd.html )
   widget navToolbar 範例 
   on 是 Dojo 模組 dojo/on 的事件監測方法,利用該方法,捕捉操作事件
   (on 宣告方法 就要查 http://dojotoolkit.org/api/?qs=1.10/dojo/on )
   target 的 DOM 是 navToolbar,type 用來偵聽或擴展事件類型 onExtentHistoryChange,listener 發生事件所呼叫的函數 extentHistoryChangeHandler
   函數 extentHistoryChangeHandler 內,註冊防呆機制,確保在第一筆與最後一筆時不作動!
   registry 是 Dojo 模組 dijit/registry 的事件註冊方法,利用該方法,擴展操作事件
   (registry 宣告方法 就要查 registry  宣告方法 就要查 http://dojotoolkit.org/api/?qs=1.10/http://dojotoolkit.org/api/?qs=1.10/dijit/registry )

3. Legend 宣告載入一樣是放在 function(Map...略...) {}  中,用一個 主要是透過 map.on 建立一個事件,
   (而 map 宣告方法  Class:Map 並沒有找到該函數 map.on)
   該方法推論是繼承 on 精神(使用方法不同),宣告方法 就要查 dojo/on 
   在 events 的說明,就把 物件.on 當成是一種事件監測器的方法來使用吧!
   透過 map.on 建立一個 layers-add-result 事件處理方法
   使用一個拋棄式函數,來取得加入 map 圖層的 layerInfo 屬性
   定義 弱型別的變數 legendDijit  並將他 建立成 legendDijit 模組 legend 物件
   手動 Hoisting ,寫到上方
   (new legend 宣告方法 就要查 https://developers.arcgis.com/javascript/jsapi/legend-amd.html )
    legend 範例 

4. 用 code 方式宣告 TabContainer
   於 require 中的 call back 函數中,
   定義 三個變數 tc(當作TabContainer)、cp1(ContentPane)、cp2(ContentPane)
   (new TabContainer 宣告方法 就要查 http://dojotoolkit.org/api/?qs=1.10/dijit/layout/TabContainer )
   TabContainer 範例
   (new ContentPane 宣告方法 就要查 http://dojotoolkit.org/api/?qs=1.10/dijit/layout/ContentPane )
   ContentPane 範例
   透過 TabContainer.addChild() 函數,就可以把ContentPane 加入 TabContainer 中 ,
   TabContainer.startup() 函數不知道在幹嘛的,有無使用函數視乎沒有差別,範例上有寫還是造著用吧!

JSBin Demo(http://goo.gl/5NYcbX)

參考文獻︰
TabContainer
TabContainer 範例
ContentPane
ContentPane 範例



星期四, 2月 12, 2015

[ArcGIS Server API for JavaScript] 利用 Dojo 框架加入手風琴容器 AccordionContainer


繼上次案件 [ArcGIS Server API for JavaScript] 地圖中加入 圖層圖例 Legend 後,再次回到 Dojo 基本 接下來的案件是 加入 手風琴容器 AccordionContainer

口白:
流動的水沒有形狀,漂流的風找不到蹤跡,任何案件的 Coding 都取決於心
唯一看透真相的是,外表看似卜朧共,智慧卻低於常人的 名卜朧共 刻爛
(謎之音:把 Code 刻到爛簡稱刻爛.爛..爛...)
Music:
#表升半音 []表高八度
4 3 2 6 4 2 3 #6 6 5 4 5 4 5 6 4 3 2 5 4 3 4 2 6 4 5 [2] [1] #6 6 5 6
4 3 2 6 4 2 3 #6 6 5 4 5 4 5 6 4 3 2 4 3 2 4 2 6 4 5 [2] #6 6 5 6
口白:
刻爛:真実はいつも一つ!

延續了前案件[ArcGIS Server API for JavaScript] 地圖中加入 圖層圖例 Legend
這次是在這篇的基礎上,加入手風琴容器 AccordionContainer ,再次回到 Dojo 基本吧!

Html:
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
    <link href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css" rel="stylesheet" type="text/css"></link>
    <script src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js" type="text/javascript">
    </script>
    <title>dijit layout AccordionContainer</title>
    <link rel="stylesheet" href="http://js.arcgis.com/3.12/dijit/themes/claro/claro.css">
    <link rel="stylesheet" href="http://js.arcgis.com/3.12/esri/css/esri.css">    
    <script src="http://js.arcgis.com/3.12/"></script>
  </head>
  <body class="claro" expr:class='&quot;loading&quot; + data:blog.mobileClass' onload='prettyPrint();'>
    <!-- MenuBar div#navMenu -->
    <div data-dojo-type="dijit/MenuBar" id="navMenu">
      <div data-dojo-type="dijit/PopupMenuBarItem">
        <span>地圖</span>
        <div data-dojo-type="dijit/DropDownMenu" id="mapMenu">
          <div data-dojo-type="dijit/MenuItem" data-dojo-props="onClick:function(){alert('地圖操作')}">地圖操作</div>
        </div>
      </div>
    </div>
    <!-- MenuBar div#navMenu -->

    <div style="width: 300px; height: 300px; position: absolute; z-index: 999; top: 60px; right: 50px;">
      <div data-dojo-type="dijit/layout/AccordionContainer" style="height: 300px;">
        <div data-dojo-type="dijit/layout/ContentPane" selected="true" title="工具列">
          <div id="navToolbar" data-dojo-type="dijit/Toolbar" style="width:50%;">
            <div data-dojo-type="dijit/form/Button" id="zoomin"  data-dojo-props="iconClass:'zoominIcon'">Zoom In</div>
            <div data-dojo-type="dijit/form/Button" id="zoomout" data-dojo-props="iconClass:'zoomoutIcon'">Zoom Out</div>
            <div data-dojo-type="dijit/form/Button" id="zoomfullext" data-dojo-props="iconClass:'zoomfullextIcon'">Full Extent</div>
            <div data-dojo-type="dijit/form/Button" id="zoomprev" data-dojo-props="iconClass:'zoomprevIcon'">Prev Extent</div>
            <div data-dojo-type="dijit/form/Button" id="zoomnext" data-dojo-props="iconClass:'zoomnextIcon'">Next Extent</div>
            <div data-dojo-type="dijit/form/Button" id="pan" data-dojo-props="iconClass:'panIcon'">Pan</div>
            <div data-dojo-type="dijit/form/Button" id="deactivate" data-dojo-props="iconClass:'deactivateIcon'">Deactivate</div>
          </div>            
        </div>
        <div data-dojo-type="dijit/layout/ContentPane" title="圖例">
          <div data-dojo-type="dijit/layout/ContentPane" id="legendPane"
                 data-dojo-props="title:'Legend', selected:true" style="height:50px;" >
            <div id="legendDiv"></div>
          </div>
        </div>
      </div>
    </div>

    <div id="mapDiv" 
         data-dojo-type="dijit/layout/ContentPane" 
         data-dojo-props="region:'center'" 
         style="padding:0">
    </div>

  </body>
</html>
說明:
1. 引用 CSS:claro.css、esri.css 引用參考位置如下:
   <link rel="stylesheet" href="http://js.arcgis.com/3.12/dijit/themes/claro/claro.css">
   <link rel="stylesheet" href="http://js.arcgis.com/3.12/esri/css/esri.css">  為了中文化排版被擠壓 修改 CSS

2. 引用 Javascript 需插入  <script src="http://js.arcgis.com/3.12/"></script> 其中已包含了Dojo框架囉

3. <body> 標籤中 加入 class 樣式定義為 "claro" 如: <body class="claro">

4. 加入 div 區塊 當作 MenuBar,如:<div data-dojo-type="dijit/MenuBar" id="navMenu"></div>

5. 加入 div 區塊 當作 PopupMenuBarItem,將該物件放在 MenuBar Div 區塊內 如:
   <div data-dojo-type="dijit/PopupMenuBarItem">
   </div>
   給該選單名稱,則是在 PopupMenuBarItem div 區塊 內加入 <span>地圖</span> 來定義
   加入 div 區塊 當作 DropDownMenu,將該物件放在 PopupMenuBarItem Div 區塊內 如:
   <div data-dojo-type="dijit/DropDownMenu" id="mapMenu">
   </div>
   加入 div 區塊 當作 MenuItem,將該物件放在 DropDownMenu Div 區塊內 如:
   <div data-dojo-type="dijit/MenuItem" data-dojo-props="onClick:function(){alert('地圖操作')}">地圖操作</div>

6. 加入 div 區塊 當作 dijit/layout/AccordionContainer 容器 外框,
   並定義樣式 style="width: 300px; height: 300px; position: absolute; z-index: 999; top: 60px; right: 50px;"
   於該 div 區塊 內加入 div 區塊 當作 dijit/layout/AccordionContainer 容器 ,
   並將 dijit/layout/ContentPane 物件放在 dijit/layout/AccordionContainer Div 區塊內,如:
   <div style="width: 300px; height: 300px; position: absolute; z-index: 999; top: 60px; right: 50px;">
     <div data-dojo-type="dijit/layout/AccordionContainer" style="height: 300px;">
       <div data-dojo-type="dijit/layout/ContentPane" selected="true" title="工具列">
    ... 略...
       </div>
     </div>
   </div>
   dijit/layout/AccordionContainer 為手風琴主要框架,
   而在 dijit/layout/AccordionContainer 內的 dijit/layout/ContentPane 為手風琴的每一節,
   故我們可以定義 title="名稱";selected="預設顯示"(只能設在單一節點上)

7. 接著我們可以把工具擺放進手風琴節點內,主要是將 DOM 物件擺入 dijit/layout/AccordionContainer DIV 區塊內
   因此我們可以把之前寫過的 Toolbar、legendPane 分別放入不同的 dijit/layout/ContentPane 內
   於 第一個 dijit/layout/ContentPane div 區塊 內 加入 div 區塊 當作 dijit/Toolbar 容器,
   並將 dijit/form/Button 物件放在 navToolbar Div 區塊內 如:
   <div id="navToolbar" data-dojo-type="dijit/Toolbar" >
     <div data-dojo-type="dijit/form/Button" id="zoomin"  data-dojo-props="iconClass:'zoominIcon'">Zoom In</div>
   ...略....
   </div>

   於 第二個 dijit/layout/ContentPane div 區塊 內 加入 div 區塊 當作 legendPane 區塊,如:<div id="legendPane" ...略.../div>,
   於 div 區塊 legendPane 中,加入 當作 legendDiv 區塊,如:<div id="legendDiv" ...略.../div>
   此 div 區塊 legendDiv 區塊,是用來展現 legend 用

8. 加入 div 區塊 當作地圖區塊,如:<div id="mapDiv"></div>

CSS:
.esriScalebarLabel.esriScalebarLineLabel.esriScalebarSecondNumber {
  font-size: 11px;
  position: absolute;
  width: 50%;
  text-align: center;
  color: #666666;
  font: Verdana;
  font-weight: bolder;
  height: 5px;
  top: -1px;
}
html, body, #mapDiv {
  padding: 0;
  margin: 0;
  height: 100%;
}
.zoominIcon 
{
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_zoomin.png);
  width: 16px;
  height: 16px;
}

.zoomoutIcon 
{
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_zoomout.png);
  width: 16px;
  height: 16px;
}

.zoomfullextIcon 
{
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_fullextent.png);
  width: 16px;
  height: 16px;
}

.zoomprevIcon 
{
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_previous.png);
  width: 16px;
  height: 16px;
}

.zoomnextIcon 
{ 
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_next.png);
  width: 16px;
  height: 16px;
}

.panIcon 
{
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_pan.png);
  width: 16px;
  height: 16px;
}

.deactivateIcon 
{
  background-image: url(http://developers.arcgis.com/javascript/samples/toolbar_navigation/images/nav_decline.png);
  width: 16px;
  height: 16px;
}
.NavToolBar 
{
  width: 120px; position: absolute; z-index: 999; height: auto; top: 60px; right: 50px;
}
.LegendTool
{
  width: 200px; position: absolute; z-index: 999; height: 600px; top: 60px; left: 50px;
}
說明:
1. 定義 mapDiv 區塊的 CSS 樣式
2. 中文化 排版被擠壓 .esriScalebarLabel.esriScalebarLineLabel.esriScalebarSecondNumber 調整width 改成 50%
3. 定義 zoominIcon、zoomoutIcon、zoomfullextIcon、zoomprevIcon、zoomnextIcon、panIcon、deactivateIcon 樣式,其中包含工具圖示
4. 定義 LegendTool、NavToolBar 樣式,定義大小位置(放入手風琴後不使用,避免干擾版型)

JavaScript:
var map;
require([
  "esri/map",
  "dojo/parser",

  // Modules referenced by the parser
  "dijit/DropDownMenu",
  "dijit/MenuBar",
  "dijit/MenuBarItem",
  "dijit/MenuItem",
  "dijit/PopupMenuBarItem",

  // ArcGISDynamicMapServiceLayer 會使用到的模組 
  "esri/layers/ArcGISDynamicMapServiceLayer", // 加入 Arcgis Server 發布ArcGISDynamicMapServiceLayer圖層 Package
  // ArcGISDynamicMapServiceLayer 會使用到的模組 

  // Legend 會使用到的模組 
  "dojo/_base/array",       // 加入 dojo/_base/array Package 
  "esri/dijit/Legend",      // 加入 esri/dijit/Legend Package 
  // Legend 會使用到的模組 

  // Overview 會使用到的模組 
  "esri/dijit/OverviewMap", // 加入 Overview Package 
  // Overview 會使用到的模組 

  // Scalebar 會使用到的模組 
  "esri/dijit/Scalebar",    // 加入 Scalebar Package 
  // Scalebar 會使用到的模組 

  // navigation ToolBar 會使用到的模組 
  // "dojo/parser", navigation ToolBar 會使用到的模組 也會使用到前面已經宣告過就不重覆載入
  "esri/toolbars/navigation",
  "dojo/on",
  "dijit/registry",
  "dijit/Toolbar",              // 因為本身並沒有針對對應物件操作,故不設定 載入對應 變數
  "dijit/form/Button",          // 因為本身並沒有針對對應物件操作,故不設定 載入對應 變數
  // navigation ToolBar 會使用到的模組 

  // AccordionContainer 會使用到的模組 
  // "dojo/parser", AccordionContainer 會使用到的模組 也會使用到前面已經宣告過就不重覆載入
  "dijit/layout/AccordionContainer", 
  "dijit/layout/ContentPane",
  // AccordionContainer 會使用到的模組 
  
  "dojo/domReady!"
], function (
  Map,
  parser,

  DropDownMenu,
  MenuBar,
  MenuBarItem,
  MenuItem,
  PopupMenuBarItem,

  // ArcGISDynamicMapServiceLayer 會使用到的模組 對應變數
  ArcGISDynamicMapServiceLayer, // 加入 ArcGISDynamicMapServiceLayer 承接 對應 "esri/layers/ArcGISDynamicMapServiceLayer" ArcGISDynamicMapServiceLayer Package  變數
  // ArcGISDynamicMapServiceLayer 會使用到的模組 對應變數

  // Legend 會使用到的模組 對應變數
  arrayUtils,    // 加入 arrayUtils 承接 對應 "dojo/_base/array" Package  變數
  Legend,        // 加入 Legend 承接 對應 "esri/dijit/Legend" Package  變數
  // Legend 會使用到的模組 對應變數

  // OverviewMap 會使用到的模組 對應變數
  OverviewMap,   // 加入 OverviewMap 承接 對應 "esri/dijit/OverviewMap" OverviewMap Package  變數
  // OverviewMap 會使用到的模組 對應變數

  // Scalebar 會使用到的模組 對應變數
  Scalebar,      // 加入 Scalebar 承接 對應 "esri/dijit/Scalebar" Scalebar Package  變數
  // Scalebar 會使用到的模組 對應變數

  // navigation ToolBar 會使用到的模組 對應變數
  // parser,, navigation ToolBar 會使用到的模組 也會使用到前面已經宣告過就不重覆載入
  Navigation,
  on,        
  registry        
  // navigation ToolBar 會使用到的模組 對應變數 
   
  )
{
  parser.parse();

  var navToolbar;
  var layer;

  // 中文化 S
  //console.log(esri.bundle.widgets.scalebar);
  esri.bundle.widgets.scalebar = { ft: "英呎", km: "公里", mi: "英里", m: "公尺" }; // 目前無作用
  window.esri.dijit.Scalebar.prototype.localStrings.km = '公里';
  window.esri.dijit.Scalebar.prototype.localStrings.m = '公尺';
  window.esri.dijit.Scalebar.prototype.localStrings.mi = '英里';
  window.esri.dijit.Scalebar.prototype.localStrings.ft = '英呎';
  //console.log(domStyle.getComputedStyle(dojo.query('.esriScalebarLabel.esriScalebarLineLabel.esriScalebarSecondNumber')).width);
  //domStyle.set(dojo.query('.esriScalebarLabel.esriScalebarLineLabel.esriScalebarSecondNumber'), "width", "50%");
  /*
  esri.css 
  修改 .esriScalebarLabel.esriScalebarLineLabel.esriScalebarSecondNumber 
  width:10% 改 width:50%
  */
  //console.log(esri.bundle.widgets.scalebar);
  // 中文化 E

  map = new Map("mapDiv",
    {
      //center: [182367.85715, 2561474.641595]
      //zoom: 8,
      //basemap: "streets",
      //sliderStyle:'large'
      basemap:"satellite",
      center :[-97.031, 37.638],
      zoom   :4,
      //slider :false
    sliderStyle:'large'
    });

  layer = new esri.layers.ArcGISDynamicMapServiceLayer(
    'http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Median_Net_Worth/MapServer', 
    {opacity: 1.0});
  //console.log('ArcGISDynamicMapServiceLayer');
  

  //add the legend
  map.on("layers-add-result", function (evt) {
    var layerInfo = arrayUtils.map(evt.layers, function (layer, index) {
      return { layer: layer.layer, title: layer.layer.name };
    });
    if (layerInfo.length > 0) {
      var legendDijit = new Legend({
        map: map,
        layerInfos: layerInfo
      }, "legendDiv");
      legendDijit.startup();
    }
  });
  //add the legend
  map.addLayers([layer]);
  
  
  // 加入 OverviewMap 地圖上顯示鷹眼 開始
  var overviewMapDijit = new OverviewMap({
    map: map,
    attachTo: "bottom-right",
    visible: true
  });
  overviewMapDijit.startup();
  // 加入 OverviewMap 地圖上顯示鷹眼 結束

  // 加入 scalebar 地圖上顯示比例尺 開始
  var scalebar = new Scalebar({
    map: map,
    // "dual" displays both miles and kilmometers
    // "english" is the default, which displays miles
    // use "metric" for kilometers
    scalebarUnit: "dual"
  });
  scalebar.hide();
  scalebar.show();
  // 加入 scalebar 地圖上顯示比例尺 結束

  navToolbar = new Navigation(map);
  on(navToolbar, "onExtentHistoryChange", extentHistoryChangeHandler);

  registry.byId("zoomin").on("click", function () {
    navToolbar.activate(Navigation.ZOOM_IN);
  });

  registry.byId("zoomout").on("click", function () {
    navToolbar.activate(Navigation.ZOOM_OUT);
  });

  registry.byId("zoomfullext").on("click", function () {
    navToolbar.zoomToFullExtent();
  });

  registry.byId("zoomprev").on("click", function () {
    navToolbar.zoomToPrevExtent();
  });

  registry.byId("zoomnext").on("click", function () {
    navToolbar.zoomToNextExtent();
  });

  registry.byId("pan").on("click", function () {
    navToolbar.activate(Navigation.PAN);
  });

  registry.byId("deactivate").on("click", function () {
    navToolbar.deactivate();
  });

  function extentHistoryChangeHandler () {
    registry.byId("zoomprev").disabled = navToolbar.isFirstExtent();
    registry.byId("zoomnext").disabled = navToolbar.isLastExtent();
  }

});

說明:
1. 定義 弱型別的變數 map
   .require 是 Dojo 方法,利用該方法,
   載入 esri/map、dojo/parser、dijit/DropDownMenu、MenuBar、MenuBarItem、MenuItem、PopupMenuBarItem、esri/dijit/Scalebar、dojo/domReady! 
   Navigation 瀏覽工具 需用到的模組 esri/toolbars/navigation,dojo/on,dijit/registry,
   Navigation 瀏覽工具 也需要 dojo/parser (載入模組不需重複載入)
   而 dijit/Toolbar,dijit/form/Button,因為本身並沒有針對對應物件操作,故不設定 載入對應 變數
   要加入 ArcGISDynamicMapServiceLayer 圖層,需用到的模組 esri/layers/ArcGISDynamicMapServiceLayer,
   要加入 AccordionContainer 手風琴容器,需用到的模組 dijit/layout/AccordionContainer、dijit/layout/ContentPane,
   因為本身並沒有針對對應物件操作,故不設定 載入對應 變數

   根據 Dojo API 參考文件來說,
   載入模組後,需用一個 變數來接收該模組,以便於操作 
   例如 function(Map) {}  用一個 拋棄式的函數,
   裡面定義變數: Map、parser、DropDownMenu、MenuBar、MenuBarItem、MenuItem、PopupMenuBarItem、Scalebar,
   Navigation 定義對應變數: Navigation、on、registry。
   ArcGISDynamicMapServiceLayer 定義對應變數: ArcGISDynamicMapServiceLayer。        

2. function(Map...略...) {}  用一個 拋棄式的函數 裡面定義 map 變數,
   透過傳入的 Map 類別可以 宣告成一個 esri/map 的物件,其他載入的亦同方式
   parser.parse() 主要是將 dom 轉換成 dijit 物件或是 widget
   (new Map 宣告方法 就要查 https://developers.arcgis.com/javascript/jsapi/map-amd.html )
   另外因為載入 ArcGISDynamicMapServiceLayer 圖層與 basemap 坐標系統不一樣,故 new Map(...,OPTIONS),
   物件 OPTIONS 中,定義的center 原本為 WGS84 經緯度,要改成 TWD97:EPSG定義為3826 或 102443,的坐標
   並且把 basemap、zoom(可以不用註解) 參數註解掉,原因是坐標系統不一致套疊會有問題
   定義 弱型別的變數 layer  並將他 建立成 esri.layers.ArcGISDynamicMapServiceLayer 物件
   (new ArcGISDynamicMapServiceLayer 宣告方法 就要查 https://developers.arcgis.com/javascript/jsapi/arcgisdynamicmapservicelayer-amd.html" )
    ArcGISDynamicMapServiceLayer 範例 
   Url 部分,就是設定 ArcGIS Server 發布服務的位置
   options 部分,就是針對載入圖層相關設定,例如:透明度:opacity,顯示與否:visible。
   定義 弱型別的變數 overviewMapDijit  並將他 建立成 esri/dijit/OverviewMap 物件
   (new overviewMapDijit 宣告方法 就要查 https://developers.arcgis.com/javascript/jsapi/overviewmap-amd.html" )
   widget overviewmap 範例 
   定義 弱型別的變數 scalebar 並將他 建立成 esri/dijit/Scalebar 物件
   (new Scalebar 宣告方法 就要查 https://developers.arcgis.com/javascript/jsapi/scalebar-amd.html )
   widget scalebar 範例 
   定義 弱型別的變數 navToolbar  並將他 建立成 esri/toolbars/navigation 模組 Navigation 物件
   (new navToolbar 宣告方法 就要查 https://developers.arcgis.com/javascript/jsapi/navigation-amd.html )
   widget navToolbar 範例 
   on 是 Dojo 模組 dojo/on 的事件監測方法,利用該方法,捕捉操作事件
   (on 宣告方法 就要查 http://dojotoolkit.org/api/?qs=1.10/dojo/on )
   target 的 DOM 是 navToolbar,type 用來偵聽或擴展事件類型 onExtentHistoryChange,listener 發生事件所呼叫的函數 extentHistoryChangeHandler
   函數 extentHistoryChangeHandler 內,註冊防呆機制,確保在第一筆與最後一筆時不作動!
   registry 是 Dojo 模組 dijit/registry 的事件註冊方法,利用該方法,擴展操作事件
   (registry 宣告方法 就要查 registry  宣告方法 就要查 http://dojotoolkit.org/api/?qs=1.10/http://dojotoolkit.org/api/?qs=1.10/dijit/registry )

3. Legend 宣告載入一樣是放在 function(Map...略...) {}  中,用一個 主要是透過 map.on 建立一個事件,
   (而 map 宣告方法  Class:Map 並沒有找到該函數 map.on)
   該方法推論是繼承 on 精神(使用方法不同),宣告方法 就要查 dojo/on 
   在 events 的說明,就把 物件.on 當成是一種事件監測器的方法來使用吧!
   透過 map.on 建立一個 layers-add-result 事件處理方法
   使用一個拋棄式函數,來取得加入 map 圖層的 layerInfo 屬性
   定義 弱型別的變數 legendDijit  並將他 建立成 legendDijit 模組 legend 物件
   (new legend 宣告方法 就要查 https://developers.arcgis.com/javascript/jsapi/legend-amd.html )
    legend 範例 

JSBin Demo(http://goo.gl/3eDLzX)

參考文獻︰
dijit/layout/AccordionContainer
dijit/layout/AccordionContainer.html範例