こんばんは!Mikeiです^^
今日はkinotne Advent Calendar 2017の23日目Postです。
今年はconnpassからkintone関連イベントを取得して、mapboxで地図表示をするというカスタマイズにチャレンジしてみました!
Google mapだと、いざ運用に乗せようとした時にライセンス問題があり、なかなか思うように使えないですが、mapboxはある程度自由に使えそうなので、要チェックです。(料金体系を見ると、地図のビュー数が月々5万を超えなければ無料枠で大丈夫)
APIやサンプルや地図のスタイルも豊富で触っていてとてもワクワクします^^
📍完成イメージ
カスタマイズ内容と完成イメージはこちらです。
- connpassからkintoneというキーワードを含むイベントを取得して、kintoneにレコード追加
- kintoneに登録されている位置情報から、mapboxを使ってカスタマイズビューに地図表示
- 今月開催のイベントのみ色付け
📍連携サービス紹介
カスタマイズの説明に移る前に、今回使った連携サービスの紹介です。
connpassとは
connpassは、イベント情報を管理するサービスのことです。kintone関連のイベントもよくこちらのサイトにアップされています。
APIリファレンスはこちらです。
mapboxとは
mapboxは、Webの地図サービスです。APIやSDKなども揃っているので、カスタマイズするにも持ってこいのサービス。
サンプル集や地図のスタイルが豊富なのも嬉しいポイントです。
詳しいドキュメントはこちらになります。
📍準備するもの
-
kintone環境(開発者ライセンスの取得はこちら)
-
mapboxアカウント(お持ちでない方は、こちらからサインアップ)
-
テキストエディタ
-
アプリテンプレート・ソースコード・スタイルのJSONファイル
https://github.com/TomokoMiyake/kintone-mapbox※githubにアップしているファイル群は右上の「Clone or download」から一括ダウンロードできます。
📍カスタマイズ手順
kintoneアプリ作成
アプリテンプレートをgithubリポジトリに用意しているので、こちらの手順に沿って読み込んでください。
「イベント管理(connpass & mapbox連携).zip」というファイルです。
また、今回地図が見やすいように2パターンとも一覧画面や詳細画面ではなく、カスタマイズビューに設置しています。
カスタマイズビューには以下のHTMLを記述しています。
<div id='map' style='width:100%; height:500px'></div>
※一覧名はソースコード内で指定しているので、変更すると地図が表示されなくります。
mapboxへの地図スタイル読み込み
mapboxでは下のように様々なスタイルの地図を選択してカスタマイズすることができます。(ギャラリー見るだけでも楽しいですね♪)
他の地図サービスと違うのは、テンプレートから選べるだけでなく、自分で地図スタイルを作ることもできる点です。
今回は完成イメージにもあるようにLightとDarkというテンプレートのスタイルに修正を加えたので、それを読み込んで使います。
※mapboxでは残念ながら地図上の表記を全て日本語に設定することができません。初期設定では全て英語になっているので、各国の言語で表示されるように設定し直す必要があります。今回は私の方で直したものをアップしています。(具体的には、スタイル内のテキスト設定で「name_en」となっている箇所を全て「name」に編集します。)
- mapboxにログイン
- スタイルの作成
- 「Create a style」をクリック
JavaScriptファイルの編集
- githubからダウンロードした「map(要編集).js」ファイルをテキストエディタで開く
- ソースコード最下部の「×××」4箇所を先ほどmapboxでのスタイル作成時にメモした内容に書き換えて、ファイルを保存
// イベント処理 ※書き換え必要箇所
kintone.events.on('app.record.index.show', (event) => {
const records = event.records;
const appId = kintone.app.getId();
const domain = '×××'; // kintoneのサブドメイン名を記入
const token = '×××'; // mapboxで作成したStyleのAccess tokenを記入(lightもdarkも同じ)
const styleStandard = 'mapbox://styles/×××/×××'; // mapboxで作成したlight styleのURLを記入
const styleChoropleth = 'mapbox://styles/×××/×××'; // mapboxで作成したdark styleのURLを記入
// connpassからのイベント取得
getEvents();
// mapboxで地図表示
if (event.viewName === '地図') {
showMap(records, appId, domain, token, styleStandard);
}
// mapboxでコロプレス地図表示
if (event.viewName === '分布地図') {
showChoroplethMap(records, appId, domain, token, styleChoropleth);
}
});
kintoneへの適用 & 動作確認
- 保存したJavaScriptファイルを作成したkintoneアプリに適用(アプリへの適用方法はこちら)
- 適用ファイルの構成が以下のようになっていることを確認して、設定を保存
- アプリの一覧画面に移動して、動作確認
- 4つの一覧画面(地図表示用の2つはカスタマイズビュー)
完成しましたでしょうか?
途中寄り道したくなる機能が沢山ありましたよね(笑)
📍妄想
mapboxはこれがきっかけで初めて触りましたが、工夫したい欲が湧いてくるツールでした^^
今回ここまでできなかったのですが、できたら実用的だなーと思います。(冬休みの課題にいかがですか^^;)
- BIツール化(kintoneの導入社数の分布図、kintone Caféの開催マップ)
- 旅の記録
- バスなどの運行状況マップ
分布図系は、こんなイメージ↓
https://blog.mapbox.com/introducing-data-driven-styling-in-mapbox-gl-js-f273121143c3
📍カスタマイズのポイント解説
カスタマイズ部分が気になる方はこちらもよければご覧ください。
利用したAPI
プログラム
ポイント1:reduce関数を使う
Promiseの順番処理を行うためにreduce関数を使います。
// kintoneへ登録用のデータ配列作成
let post = [];
return body.reduce((promise, formatedData) => {
return promise.then(() => {
const getRecords = {
'app': kintone.app.getId(),
'query': 'url =' + '"' + formatedData.event_url + '"'
};
return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', getRecords).then((getResp) => {
if (getResp.records.length === 0) {
const records = {
'title': {
'value': formatedData.title
},
'start': {
'value': formatedData.started_at
},
'end': {
'value': formatedData.ended_at
},
'url': {
'value': formatedData.event_url
},
'address': {
'value': formatedData.address
},
'place': {
'value': formatedData.place
},
'lat': {
'value': formatedData.lat
},
'lon': {
'value': formatedData.lon
}
};
post.push(records);
return post;
}
});
});
}, Promise.resolve()).then(() => {
////// 省略 //////
});
ポイント2:地図データのマッピング
中心の座標の指定やkitnoneアプリ内の座標データを地図データにプロットします。
const map = new mapboxgl.Map({
container: 'map',
style: styleChoropleth,
center: [137.6850225, 38.258595],
zoom: 6
});
// 地図にピン打ちするデータ作成
const features = records.map((record) => {
const link = 'https://' + domain + '.cybozu.com/k/' + appId + '/show#record=' + record.$id.value;
const feature = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [parseFloat(record.lon.value), parseFloat(record.lat.value)]
},
properties: {
title: '<a href=' + link + '>' + record.title.value + '</a>',
description: record.address.value
}
};
return feature;
});
ポイント3:マーカー(地図上のアイコン)のプロット
「地図」では条件付きで赤色と黒色のマーカーを分けているので、それ用に2つの要素を作成します。
それぞれのマーカーには緯度経度のデータやポップアップで表示する内容を指定します。
// マーカーを地図に追加
geojson.features.forEach(function(marker) {
if (isNaN(marker.geometry.coordinates[0]) || isNaN(marker.geometry.coordinates[1])) {
return;
}
// HTML要素の作成
const elThisMonth = document.createElement('div');
const el = document.createElement('div');
if (marker.properties.icon === 'thisMonth') {
el.className = 'marker-this-month';
} else if (marker.properties.icon === 'notThisMonth') {
el.className = 'marker';
}
// マーカー要素を作成
new mapboxgl.Marker(elThisMonth)
.setLngLat(marker.geometry.coordinates)
.setPopup(new mapboxgl.Popup({ offset: 25 })
.setHTML('<h3><b>' + marker.properties.title + '</b></h3><p>' + marker.properties.description + '</p>'))
.addTo(map);
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.setPopup(new mapboxgl.Popup({ offset: 25 })
.setHTML('<h3><b>' + marker.properties.title + '</b></h3><p>' + marker.properties.description + '</p>'))
.addTo(map);
});
JavaScriptで生成したクラスにCSS側でFontAwesomeをアイコンとしてあてます。
.marker:before {
font-family: FontAwesome;
content: '\f041';
color: #585858;
font-size: 2em;
text-shadow: 0px 0px 1px #FFFFFF;
}
📍おわりに
最後まで読んでくださりありがとうございました!間違ってるところがあればご指摘いただけると嬉しいですm(__)m
では皆さん、Merry Christmas and Happy New Year!!!🎄