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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
|
/*
* 一覧画面に地図を表示するサンプルプログラム
* Copyright (c) 2024 Cybozu
*
* Licensed under the MIT License
* https://opensource.org/license/mit/
*/
(() => {
'use strict';
// APIキー
const api_key = 'Your Google API key';
// 緯度、経度を空にします
const emptyLatLng = (event) => {
// eventよりレコード情報を取得します
const rec = event.record;
// 保存の際に緯度、経度を空にします
rec.lat.value = '';
rec.lng.value = '';
return event;
};
// 地図をスペースフィールドに表示します。
// 緯度、経度フィールドを住所を基に算出した値で更新し、
// 画面をリロードします
const setLatLng = async (rec) => {
// Google Geocoderを定義します
const {Geocoder} = await google.maps.importLibrary('geocoding');
const gc = new Geocoder();
// Geocoding APIを実行します
gc.geocode({
address: rec['住所'].value,
language: 'ja',
country: 'JP'
}, (results, status) => {
// 住所が検索できた場合、開いているレコードに対して
// 緯度・経度を埋め込んで更新します
if (status === google.maps.GeocoderStatus.OK) {
// 更新するデータのObjectを作成します
const objParam = {
app: kintone.app.getId(), // アプリ番号
id: kintone.app.record.getId(), // レコードID
record: {
lat: {value: results[0].geometry.location.lat()}, // 緯度
lng: {value: results[0].geometry.location.lng()} // 経度
}
};
// レコードを更新します
kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', objParam, (resp) => {
// 成功時は画面をリロードします
location.reload(true);
}, (resp) => {
// エラー時はメッセージを表示して、処理を中断します
alert('error->' + resp);
});
}
});
};
// 地図を「住所」フィールドの下に表示します
// 緯度・経度がない場合は、住所をもとに緯度・経度を算出し、
// フィールドに値を入れた後、レコードを更新します
const setLocationDetail = async (event) => {
const {AdvancedMarkerView} = await google.maps.importLibrary('marker');
// レコード情報を取得します
const rec = event.record;
// 住所が入力されていなければ、ここで処理を終了します
if (!rec['住所'].value) {
return;
}
// 緯度・経度が入力されていなければ、住所から緯度・経度を算出して、
// フィールドに追加し、レコードを更新する
if (!rec.lat.value || !rec.lng.value) {
await setLatLng(rec);
return;
}
// 地図を表示するdiv要素を作成します
const mapEl_address = document.createElement('div');
mapEl_address.setAttribute('id', 'map');
mapEl_address.setAttribute('name', 'map');
mapEl_address.setAttribute('style', 'width: 300px; height: 250px');
// 「Map」スペース内にmapEl_addressで設定した要素を追加します
const elMap = kintone.app.record.getSpaceElement('Map');
elMap.appendChild(mapEl_address);
// 「Map」スペースの親要素のサイズを変更します
const elMapParent = elMap.parentNode;
elMapParent.setAttribute('style', 'width: 300px; height: 250px');
// ポイントする座標を指定します
const point = new google.maps.LatLng(rec.lat.value, rec.lng.value);
// 地図の表示の設定(中心の位置、ズームサイズ等)を設定します
const opts = {
zoom: 15,
center: point,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scaleControl: true,
mapId: 'DEMO_MAP_ID'
};
// 地図を表示する要素を呼び出します
const map_address = new google.maps.Map(document.getElementById('map'), opts);
// マーカーを設定します
const marker = new google.maps.marker.AdvancedMarkerElement({
position: point,
map: map_address,
title: rec['住所'].value
});
};
// 地図を一覧画面のメニュー下のスペースに表示します
const setLocationIndex = async (event) => {
const locations = [];
// レコード情報を取得します
const recs = event.records;
// 一覧に表示されているすべてのレコードの緯度・経度とレコードIDを配列に格納します
recs.forEach(rec => {
if (rec.lat.value && rec.lng.value) {
locations.push({
lat: parseFloat(rec.lat.value), // 緯度
lng: parseFloat(rec.lng.value), // 経度
recno: rec.$id.value // レコードID
});
}
});
if (locations.length === 0) {
return;
}
// 一覧の上部部分にあるスペース部分を定義します
const elAction = kintone.app.getHeaderSpaceElement();
// すでに地図要素が存在する場合は、削除します
// ※ ページ切り替えや一覧のソート順を変更した時などが該当します
const existingMap = document.getElementById('map');
if (existingMap) {
elAction.removeChild(existingMap);
}
// 地図を表示する要素を定義し、スペース部分の要素に追加します
const mapEl = document.createElement('div');
mapEl.setAttribute('id', 'map');
mapEl.setAttribute('name', 'map');
mapEl.setAttribute('style', 'width: auto; height: 300px; margin: 30px; border: solid 2px #c4b097');
elAction.appendChild(mapEl);
const {Map} = await google.maps.importLibrary('maps');
const {AdvancedMarkerView} = await google.maps.importLibrary('marker');
// マップの中心を指定
const position = {lat: locations[0].lat, lng: locations[0].lng};
const map = new Map(document.getElementById('map'), {
zoom: 12,
center: position,
mapId: 'DEMO_MAP_ID'
});
const marker = [];
const m_latlng = [];
// 緯度・経度をもとに、地図にポインタを打ち込みます
locations.forEach((location) => {
if (!isNaN(location.lat) && !isNaN(location.lng)) {
const pinView = new google.maps.marker.PinView({
background: '#FBBC04',
borderColor: '#111111',
scale: 1.5,
glyph: `${location.recno}`
});
new AdvancedMarkerView({
map: map,
position: {lat: location.lat, lng: location.lng},
content: pinView.element,
});
}
});
};
const isGoogleMapsLoaded = () => {
return typeof google === 'object' && typeof google.maps === 'object';
};
const initMap = async () => {
if (isGoogleMapsLoaded()) {
return Promise.resolve();
}
// ライブラリの読み込み
// Google Maps JavaScript APIの読み込み
return Promise.resolve();
};
// 一覧画面で編集モードになった時に実行されます
const indexEditShow = (event) => {
const record = event.record;
// 住所フィールドを使用不可にします
record['住所'].disabled = true;
return event;
};
// 登録・更新イベント(新規レコード、編集レコード、一覧上の編集レコード)
kintone.events.on(['app.record.create.submit',
'app.record.edit.submit',
'app.record.index.edit.submit'], emptyLatLng);
// 詳細画面が開いた時のイベント
kintone.events.on('app.record.detail.show', async (event)=>{
await initMap();
setLocationDetail(event);
});
// 一覧画面が開いた時のイベント
kintone.events.on('app.record.index.show', async (event)=> {
await initMap();
setLocationIndex(event);
});
// 一覧画面で編集モードにした時のイベント
kintone.events.on('app.record.index.edit.show', indexEditShow);
})();
|