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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
|
/**
* Sample program
* Copyright (c) 2014 Cybozu
*
* Licensed under the MIT License
*/
(function() {
'use strict';
const api_key = 'YOUR_GOOGLE_MAPS_JAVASCRIPT_API_KEY';
// ヘッダに要素を追加
function load(src) {
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = src;
let head;
// PC用の場合(一覧画面)
if (kintone.app.getHeaderSpaceElement()) {
try {
head = kintone.app.getHeaderSpaceElement();
head.appendChild(script);
} catch (e) {
return;
}
}
// PC用の場合(詳細画面)
if (kintone.app.record.getHeaderMenuSpaceElement()) {
try {
head = kintone.app.record.getHeaderMenuSpaceElement();
head.appendChild(script);
} catch (e) {
return;
}
}
// モバイル用の場合
if (kintone.mobile.app.getHeaderSpaceElement()) {
try {
head = kintone.mobile.app.getHeaderSpaceElement();
head.appendChild(script);
} catch (e) {
return;
}
}
}
// 緯度、経度を空にする
function emptyLatLng(event) {
const rec = event.record;
// 保存の際に緯度、経度を空にする
rec.lat.value = '';
rec.lng.value = '';
return event;
}
// 詳細画面を開いた時に実行します
function detailShow(event) {
loadGMap();
waitLoaded(event, 'detail', 10000, 100);
}
// 一覧画面を開いた時に実行します
function indexShow(event) {
loadGMap();
waitLoaded(event, 'index', 10000, 100);
}
// Google Maps APIをロード
function loadGMap() {
// document.writeを定義
const nativeWrite = document.write;
document.write = function(html) {
const m = html.match(/script.+src="([^"]+)"/);
if (m) {
load(m[1]);
} else {
nativeWrite(html);
}
};
// Google MapのAPIライブラリをロード
load('https://maps.googleapis.com/maps/api/js?v=3&key=' + api_key);
}
// Google Maps APIがロードされるまで待機
function waitLoaded(event, mode, timeout, interval) {
setTimeout(() => {
timeout -= interval;
if (
typeof google !== 'undefined' &&
typeof google.maps !== 'undefined' &&
typeof google.maps.version !== 'undefined'
) {
if (mode === 'detail') {
// 詳細画面の場合
setLocationDetail(event);
} else if (mode === 'index') {
// 一覧画面の場合
setLocationIndex(event);
}
} else if (timeout > 0) {
// ロードされるまで繰り返す
waitLoaded(event, mode, timeout, interval);
}
}, interval);
}
function setLocationIndex(event) {
const lat = [];
const lng = [];
const record_no = [];
// レコード番号と緯度経度を取得
const rec = event.records;
for (let i = 0; i < rec.length; i++) {
lat.push(parseFloat(rec[i].lat.value));
lng.push(parseFloat(rec[i].lng.value));
record_no.push(parseInt(rec[i].record_no.value, 10));
}
// ポイントを先に作成
let latlng = 0;
for (let y = 0; y < lat.length; y += 1) {
if (isNaN(lat[y]) === false && isNaN(lng[y]) === false) {
latlng = new google.maps.LatLng(lat[y], lng[y]);
break;
}
}
// 緯度・経度に値が入ったレコードがなければ、ここで終了
if (latlng === 0) {
return;
}
// 地図の要素を作成
const elMap = document.createElement('div');
elMap.setAttribute('id', 'map');
elMap.setAttribute('name', 'map');
// コンテナ要素を定義
let elMapContainer;
if (event.type === 'app.record.index.show') {
// PC用
elMap.setAttribute(
'style',
'width: auto; height: 250px; margin-right: 30px; border: solid 2px #c4b097'
);
elMapContainer = kintone.app.getHeaderSpaceElement();
} else if (event.type === 'mobile.app.record.index.show') {
// スマホ用
elMap.setAttribute('style', 'width: auto; height: 150px;');
elMapContainer = kintone.mobile.app.getHeaderSpaceElement();
}
// イベントの多重化による要素生成に対応
const check = document.getElementsByName('map');
if (check.length !== 0) {
elMapContainer.removeChild(check[0]);
}
// コンテナ要素に地図要素を追加
elMapContainer.insertBefore(elMap, elMapContainer.firstChild);
// Google Mapに表示する地図の設定を行います
const opts = {
zoom: 12,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scaleControl: true,
title: 'target'
};
// 地図の要素を定義
const map = new google.maps.Map(document.getElementById('map'), opts);
// マーカーの設定
const marker = [];
const m_latlng = [];
for (let n = 0; n < lat.length; n += 1) {
if (isNaN(lat[n]) === false && isNaN(lng[n]) === false) {
m_latlng[n] = new google.maps.LatLng(lat[n], lng[n]);
marker[n] = new google.maps.Marker({
position: m_latlng[n],
map: map,
icon:
'https://chart.googleapis.com/chart?chst=d_bubble_text_small&chld=edge_bc|' +
record_no[n] +
'|FF8060|000000'
});
}
}
return event;
}
function setLocationDetail(event) {
const rec = event.record;
let elMapContainer;
// レコード登録直後等、緯度経度が空の場合は終了
if (rec.lat.value === 0 || rec.lng.value === 0) {
return;
}
// 地図を配置するための要素を取得する
if (event.type === 'app.record.detail.show') {
// PC用
elMapContainer = kintone.app.record.getSpaceElement('Map');
if (elMapContainer === undefined) {
// 「Map」のスペース要素が無い場合は終了
return;
}
// 親要素のサイズを強制変更
const elMapContainerParent = elMapContainer.parentNode;
elMapContainerParent.setAttribute('style', 'width: 300px; height: 250px');
} else if (event.type === 'mobile.app.record.detail.show') {
// スマホ用
elMapContainer = kintone.mobile.app.getHeaderSpaceElement();
}
// イベントの多重化による要素生成に対応
const check = document.getElementsByName('map');
if (check.length !== 0) {
elMapContainer.removeChild(check[0]);
}
// 地図用の要素を作成
const elMap = document.createElement('div');
elMap.setAttribute('id', 'map');
elMap.setAttribute('name', 'map');
// コンテナ要素に地図要素を追加
elMapContainer.insertBefore(elMap, elMapContainer.firstChild);
elMap.setAttribute('style', 'width: auto; height: 250px');
// Google Mapの設定
// ポイントする座標を指定
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
};
// 地図を表示する要素を呼び出し
const map = new google.maps.Map(document.getElementById('map'), opts);
// マーカーの設定
const marker = new google.maps.Marker({
position: point,
map: map,
title: ''
});
return event;
}
// 緯度経度を取得し、当該レコードを更新
function getPosition(event) {
navigator.geolocation.getCurrentPosition((position) => {
let appId, recordId;
if (event.type === 'app.record.detail.show') {
// PC用
appId = kintone.app.getId();
recordId = kintone.app.record.getId();
} else if (event.type === 'mobile.app.record.detail.show') {
// スマホ用
appId = kintone.mobile.app.getId();
recordId = kintone.mobile.app.record.getId();
}
const objParam = {
app: appId,
id: recordId,
record: {
lat: {
value: position.coords.latitude
},
lng: {
value: position.coords.longitude
}
}
};
// レコードを更新
kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', objParam, () => {
// 成功時は画面をリロード
location.reload(true);
}, (resp) => {
// エラー時はメッセージを表示して、処理を中断
alert('error->' + resp);
});
}, errorCallback);
}
// 緯度経度取得失敗時コールバック関数
function errorCallback(error) {
let errMsg = '';
switch (error.code) {
case 1:
errMsg = '位置情報の利用が許可されていません';
break;
case 2:
errMsg = 'デバイスの位置が判定できません';
break;
case 3:
errMsg = 'タイムアウトしました';
break;
}
alert(errMsg);
}
// 緯度経度を再取得するための(ボタンを配置する)関数
function updatePosition(event) {
const check = document.getElementsByName('update');
if (check.length === 0) {
const button = document.createElement('button');
button.appendChild(document.createTextNode('緯度経度更新'));
button.setAttribute('name', 'update');
const span = document.createElement('span');
span.appendChild(button);
// ボタンを配置するスペースを取得
let elButtonSpace;
if (event.type === 'app.record.detail.show') {
// PC用
elButtonSpace = kintone.app.record.getHeaderMenuSpaceElement();
} else if (event.type === 'mobile.app.record.detail.show') {
// スマホ用
elButtonSpace = kintone.mobile.app.getHeaderSpaceElement();
}
elButtonSpace.appendChild(span);
button.addEventListener('click', () => {
getPosition(event);
});
}
}
// 各種イベントハンドル
kintone.events.on(['app.record.create.submit',
'app.record.edit.submit',
'app.record.index.edit.submit', 'mobile.app.record.create.submit',
'mobile.app.record.edit.submit', 'mobile.app.record.index.edit.submit'], emptyLatLng);
kintone.events.on(['app.record.index.show', 'mobile.app.record.index.show'], indexShow);
kintone.events.on(['app.record.detail.show', 'mobile.app.record.detail.show'], detailShow);
kintone.events.on(['app.record.detail.show', 'mobile.app.record.detail.show'], updatePosition);
})();
|