2021/04/30 14:47
AMCHARTSのCDNを読み込むだけでかっこいい地図とマーカーを実装してさらにクリックでアクションさせる
AMCHARTSを使ってCANVASでかっこいい地図とマーカーを置き、さらにクリックしてアンカーリンクさせたりする実装方法です。日本版と世界版の2種類を紹介。
概要
まずやりたい事として
日本の地図と世界地図をそれぞれわけて
任意の箇所にピンアイコン的なものを置き、さらにクリックで任意の場所へ飛ばすというものです。
地図の部分はAMCHARTSというものを使いました。
AMCHARTS : https://www.amcharts.com/
特にライブラリをダウンロードする必要もなく、CDN読み込みと必要な記述さえ書けば動くので導入が楽です。
DEMOページ
まずはどういうものを作りたかったのかデモを見ていただけると分かりやすいですね。
デモページ : http://phper.pro/demo_worldmap_canvas
こちらはスタイルを当てて実装した感じです。
日本と世界それぞれタブでわけてます。
コーディング
TABの切り分け部分も含めての全体のコードです。
AMCHARTSの読み込み、タブ、マップ表示、タブ処理、マップ箇所の設定の記述という流れで書いてます。
スタイルは適宜当ててください。
ちょっと長いですが、不要そうなとこは省いてもらえたらいいかと思います。
例えばTAB切替が不要ならTAB箇所は端折ってください。
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/maps.js"></script>
<script src="https://www.amcharts.com/lib/4/geodata/worldLow.js"></script>
<script src="https://www.amcharts.com/lib/4/geodata/japanLow.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
<div class="p-worldmap-tab p-worldmap-activeTab">
JAPANESE
</div>
<div class="p-worldmap-tab">
WORLD
</div>
<div id="ta1">
<div class="p-worldmap-tab-box-in active">
<div id="chartdivJP"></div>
<div id="Osaka">
Osaka
</div>
<div id="Kyoto">
Kyoto
</div>
</div>
</div>
<div id="ta2">
<div class="p-worldmap-tab-box-in">
<div id="chartdiv"></div>
<div id="Asia">
Asia
</div>
</div>
</div>
<script>
// TAB切替
$(function(){
var tabBox = $('.p-worldmap-tab-box-in');
var tab = $('.p-worldmap-tab');
$('.p-worldmap-tab-box-in:gt(0)').hide();
$(tab[0]).addClass('p-worldmap-activeTab');
$('.p-worldmap-tab').on('click',function(){
var index = $(this).index();
$(tabBox).hide();
$(tabBox[index]).show();
$(tab).removeClass('p-worldmap-activeTab');
$(tab[index]).toggleClass('p-worldmap-activeTab');
$(tabBox).removeClass('active');
$(tabBox[index]).toggleClass('active');
});
});
</script>
<script>
// 日本版の記述
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
// Create map instance
var chart = am4core.create("chartdivJP", am4maps.MapChart);
var mapData = [
// { "id": "JP-13", "name": "Tokyo", "value": 100, "color": chart.colors.getIndex(1), "url": "#Tokyo" },
{ "id": "JP-27", "name": "Osaka", "value": 100, "color": chart.colors.getIndex(2), "url": "#Osaka" },
{ "id": "JP-26", "name": "Kyoto", "value": 100, "color": chart.colors.getIndex(3), "url": "#Kyoto" },
];
// Set map definition
chart.geodata = am4geodata_japanLow;
// Set projection
chart.projection = new am4maps.projections.Miller();
chart.homeZoomLevel = 4;
// Create map polygon series
var polygonSeries = chart.series.push(new am4maps.MapPolygonSeries());
polygonSeries.exclude = ["AQ"];
polygonSeries.useGeodata = true;
polygonSeries.nonScalingStroke = true;
polygonSeries.strokeWidth = 0.5;
polygonSeries.calculateVisualCenter = true;
polygonSeries.events.on("validated", function(){
imageSeries.invalidate();
})
var imageSeries = chart.series.push(new am4maps.MapImageSeries());
imageSeries.data = mapData;
imageSeries.dataFields.value = "value";
var imageTemplate = imageSeries.mapImages.template;
imageTemplate.nonScaling = true;
imageTemplate.adapter.add("latitude", function(latitude, target) {
var polygon = polygonSeries.getPolygonById(target.dataItem.dataContext.id);
if(polygon){
return polygon.visualLatitude;
}
return latitude;
})
imageTemplate.adapter.add("longitude", function(longitude, target) {
var polygon = polygonSeries.getPolygonById(target.dataItem.dataContext.id);
if(polygon){
return polygon.visualLongitude;
}
return longitude;
})
var circle = imageTemplate.createChild(am4core.Circle);
circle.fillOpacity = 0.7;
circle.propertyFields.fill = "color";
// circle.tooltipText = "{name}: [bold]{value}[/]";
circle.tooltipText = "{name}";
circle.propertyFields.url = "url";
imageSeries.heatRules.push({
"target": circle,
"property": "radius",
"min": 4,
"max": 30,
"dataField": "value",
"propertyFields": "url",
})
var label = imageTemplate.createChild(am4core.Label);
label.text = "{name}"
label.horizontalCenter = "middle";
label.padding(0,0,0,0);
label.adapter.add("dy", function(dy, target){
var circle = target.parent.children.getIndex(0);
return circle.pixelRadius;
})
</script>
<script>
// 世界版の記述
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
// Create map instance
var chart2 = am4core.create("chartdiv", am4maps.MapChart);
chart2.homeZoomLevel = 3;
chart2.homeGeoPoint = {
latitude: 20,
longitude: 130
};
var mapData2 = [
// { "id": "US", "name": "United States", "value": 100, "color": chart2.colors.getIndex(3), "url": "#America" },
{ "id": "CN", "name": "China", "value": 100, "color": chart2.colors.getIndex(0), "url": "#Asia" },
{ "id": "KR", "name": "Korea", "value": 100, "color": chart2.colors.getIndex(1), "url": "#Asia" },
{ "id": "TW", "name": "Taiwan", "value": 100, "color": chart2.colors.getIndex(2), "url": "#Asia" },
{ "id": "SG", "name": "Singapore", "value": 100, "color": chart2.colors.getIndex(1), "url": "#Asia" },
// { "id": "BR", "name": "Brazil", "value": 100, "color": chart2.colors.getIndex(3) },
// { "id": "NZ", "name": "New Zealand", "value": 100, "color": chart2.colors.getIndex(3) },
// { "id": "CA", "name": "Canada", "value": 100, "color": chart2.colors.getIndex(4) },
// { "id": "SE", "name": "Sweden", "value": 100, "color": chart2.colors.getIndex(4) },
// { "id": "AU", "name": "Australia", "value": 100, "color": "#8aabb0" },
// { "id": "JP", "name": "Japan", "value": 34349561, "color": chart2.colors.getIndex(0) },
];
// Set map definition
chart2.geodata = am4geodata_worldLow;
// Set projection
chart2.projection = new am4maps.projections.Miller();
// Create map polygon series
var polygonSeries2 = chart2.series.push(new am4maps.MapPolygonSeries());
polygonSeries2.exclude = ["AQ"];
polygonSeries2.useGeodata = true;
polygonSeries2.nonScalingStroke = true;
polygonSeries2.strokeWidth = 0.5;
polygonSeries2.calculateVisualCenter = true;
polygonSeries2.events.on("validated", function(){
imageSeries2.invalidate();
})
var imageSeries2 = chart2.series.push(new am4maps.MapImageSeries());
imageSeries2.data = mapData2;
imageSeries2.dataFields.value = "value";
var imageTemplate = imageSeries2.mapImages.template;
imageTemplate.nonScaling = true
imageTemplate.adapter.add("latitude", function(latitude, target) {
var polygon = polygonSeries2.getPolygonById(target.dataItem.dataContext.id);
if(polygon){
return polygon.visualLatitude;
}
return latitude;
})
imageTemplate.adapter.add("longitude", function(longitude, target) {
var polygon = polygonSeries2.getPolygonById(target.dataItem.dataContext.id);
if(polygon){
return polygon.visualLongitude;
}
return longitude;
})
var circle = imageTemplate.createChild(am4core.Circle);
circle.fillOpacity = 0.7;
circle.propertyFields.fill = "color";
// circle.tooltipText = "{name}: [bold]{value}[/]";
circle.tooltipText = "{name}";
circle.propertyFields.url = "url";
imageSeries2.heatRules.push({
"target": circle,
"property": "radius",
"min": 4,
"max": 30,
"dataField": "value",
"propertyFields": "url"
})
var label = imageTemplate.createChild(am4core.Label);
label.text = "{name}"
label.horizontalCenter = "middle";
label.padding(0,0,0,0);
label.adapter.add("dy", function(dy, target){
var circle = target.parent.children.getIndex(0);
return circle.pixelRadius;
})
</script>
Asiaは一緒くたにして雑な感じになってますが、日本版の京都・大阪のように細かく分けることももちろん可能です。
記述方法はAMCHARTS公式に載ってるはずなので、ざっくりですがこれの応用で自由にカスタムしていけるかと思います。
では現場から以上です!
6262