はじめに
コンテンツタイプにGoogleMAPの座標設定あると便利かとおもって・・・
チャレンジしてみた・・
コードはっく。
ヒントは、コンテンツデータに日付と時間が2つのエリアあるのでこちらを参考にしようかと・・・
lib\MT\ContentFieldTypeにそれぽい・・感じが・・
DateTime.pmとCommon.pmが関係ありそう・・
field_html_params、data_load_handlerとかぐらいでいけそう??
lib\MT\ContentFieldType.pmでレジストリの登録は参考にできそう
データベースは、mt_content_typeでblob形式だったので・・・参考にできなかった・・
コンテンツデータはmt_cd、こっちもblob・・・
最終のディレクトリ構造
ContentMapCoordtField
│ config.yaml
├─lib
│ │ ContentMapCoordtField.pm
│ └─ContentMapCoordtField
│ │ App.pm
│ └─ContentFieldType
│ ContentMapCoordtField.pm
│
└─tmpl
│ config.tmpl
│ selectmap.tmpl
├─content_field_type_options
│ googlemap_coordinate.tmpl
└─field_html
field_html_googlemap_coordinate.tmpl
config.yaml
ContentFieldType.pmからレジストリの値とか参考にyaml形式に置き換えて・・
id: ContentMapCoordtField
name: ContentMapCoordtField
version: 1.0
author_name:
author_link:
description: <__trans phrase="This plugin adds a GoogleMap coordinate content field type.">
l10n_lexicon:
ja:
This plugin adds a GoogleMap coordinate content field type.: "GoogleMap座標コンテンツフィールドを追加"
GoogleMap Coordinate: GoogleMap座標
Google Maps API key: Google Maps API key
Google Maps API ID: Google Maps ID
Google Maps latitude : 緯度(lat)
Google Maps longitude : 経度(lng)
Google Maps Default Latitude : 地図中心緯度(lat)
Google Maps Default Longitude : 地図中心 経度(lng)
applications:
cms:
methods:
google_map_popup: ContentMapCoordtField::App::google_map_popup
tags:
function:
GoogleMapKey: $ContentMapCoordtField::ContentMapCoordtField::_hdlr_googlemap_key
GoogleMapId: $ContentMapCoordtField::ContentMapCoordtField::_hdlr_googlemap_id
GoogleMapLatitude: $ContentMapCoordtField::ContentMapCoordtField::_hdlr_googlemap_latitude
GoogleMapLongitude: $ContentMapCoordtField::ContentMapCoordtField::_hdlr_googlemap_longitude
content_field_types:
googlemap_coordinate:
label: GoogleMap Coordinate
data_type: 'text'
order: 300,
icon_class: 'ic_singleline'
can_data_label_field: 0
data_load_handler: $ContentMapCoordtField::ContentMapCoordtField::ContentFieldType::ContentMapCoordtField::data_load_handler
field_value_handler: $ContentMapCoordtField::ContentMapCoordtField::ContentFieldType::ContentMapCoordtField::field_value_handler
field_html: 'field_html/field_html_googlemap_coordinate.tmpl'
field_html_params: $ContentMapCoordtField::ContentMapCoordtField::ContentFieldType::ContentMapCoordtField::field_html_params
list_props:
googlemap_coordinate:
base: '__virtual.string'
col: 'value_varchar'
terms: $Core::MT::ContentFieldType::Common::terms_text
options_html: 'content_field_type_options/googlemap_coordinate.tmpl'
options:
- label
- description
- required
- display
- initial_value
settings:
googlemaps_api_key:
default:
googlemaps_id:
default:
googlemaps_def_latitude:
default:
googlemaps_def_longitude:
default:
system_config_template: config.tmpl
lib\ContentMapCoordtField.pm
ここでは、プラグインの設定の値をMTタグとしてどこでも使えるように・・タグをつくる
package ContentMapCoordtField;
use strict;
use utf8;
use warnings;
my $PluginKey = 'ContentMapCoordtField';
sub instance {
my ($app) = @_;
$app ||= 'MT';
$app->component($PluginKey);
}
#<$MTGoogleMapKey$>
sub _hdlr_googlemap_key {
my $plugin = instance();
return $plugin->get_config_value('googlemaps_api_key');
}
#<$MTGoogleMapID$>
sub _hdlr_googlemap_id {
my $plugin = instance();
return $plugin->get_config_value('googlemaps_id');
}
#<$MTGoogleMapLatitude$>
sub _hdlr_googlemap_latitude {
my $plugin = instance();
return $plugin->get_config_value('googlemaps_def_latitude');
}
#<$MTGoogleMapLongitude$>
sub _hdlr_googlemap_longitude {
my $plugin = instance();
return $plugin->get_config_value('googlemaps_def_longitude');
}
1;
lib\ContentMapCoordtField\App.pm
ここでは、GoogleMap座標選択ようのPOPUPだすテンプレート・・
一応MT経由で表示するように・・
package ContentMapCoordtField::App;
use strict;
use File::Basename;
my $PluginKey = 'ContentMapCoordtField';
sub instance {
my ($app) = @_;
$app ||= 'MT';
$app->component($PluginKey);
}
sub google_map_popup {
my $app = shift;
my $param = {};
my $q = $app->param;
my $lat = $q->param('lat');
my $lng = $q->param('lng');
my $lat_id = $q->param('lat_id');
my $lng_id = $q->param('lng_id');
my $plugin = instance();
my $googlemaps_api_key = $plugin->get_config_value('googlemaps_api_key');
my $googlemaps_def_latitude = $plugin->get_config_value('googlemaps_def_latitude');
my $googlemaps_def_longitude = $plugin->get_config_value('googlemaps_def_longitude');
my $website_terms = undef;
if (my $blog_id = $app->param('blog_id')) {
$website_terms = { 'id' => $blog_id };
}
$param->{lat} = $lat;
$param->{lng} = $lng;
$param->{lat_id} = $lat_id;
$param->{lng_id} = $lng_id;
$param->{googlemaps_api_key} = $googlemaps_api_key;
$param->{googlemaps_def_latitude} = $googlemaps_def_latitude;
$param->{googlemaps_def_longitude} = $googlemaps_def_longitude;
my $plugin = MT->component('ContentMapCoordtField');
$plugin->load_tmpl('selectmap.tmpl', $param);
}
1;
lib\ContentMapCoordtField\ContentFieldType\ContentMapCoordtField.pm
ここではコンテンツタイプの定義、必須とか・・設定
あとContentFieldValueでの加工、保存のデータ構築?
package ContentMapCoordtField::ContentFieldType::ContentMapCoordtField;
use strict;
use warnings;
sub field_html_params {
my ( $app, $field_data ) = @_;
my ( $lat, $lng );
my $value = $field_data->{value} || '';
# for initial_value.
$value = '' unless defined $value;
$lat = '';
$lng = '';
if ( defined $value && $value ne '' ) {
( $lat, $lng ) = split ', ', $value;
}
my $required = $field_data->{options}{required} ? 'required' : '';
{ googlemap_coordinate_data => $value,
lat => $lat,
lng => $lng,
required => $required,
};
}
sub data_load_handler {
my ( $app, $field_data ) = @_;
my $id = $field_data->{id};
my ( $lat, $lng );
$lat = $app->param( 'lat-' . $id );
$lng = $app->param( 'lng-' . $id );
my $coordinate = $lat .", ". $lng;
return $coordinate;
}
sub field_value_handler {
my ( $ctx, $args, $cond, $field_data, $value ) = @_;
my $coordinate = lc $args->{coordinate} || 'lng';
my ( $lat, $lng );
return if ( $coordinate ne 'lat' and $coordinate ne 'lng' );
( $lat, $lng ) = split ', ', $value;
if($coordinate eq 'lat') {
return $lat;
}elsif ($coordinate eq 'lng') {
return $lng;
} else {
return $value;
}
}
1;
tmpl\config.tmpl
プラグインの設定でつかうHTMLコード
<mtapp:setting
id="contentmapcoordtfield-template_type"
label="<__trans phrase="GoogleMap Coordinate">">
<label for="contentmapcoordtfield-googlemaps_api_key"><__trans phrase="Google Maps API key"></label>
<input type="text" name="googlemaps_api_key" id="contentmapcoordtfield-googlemaps_api_key" class="form-control w-100" value="<mt:var name="googlemaps_api_key" escape="html">">
<label for="contentmapcoordtfield-def_latitude"><__trans phrase="Google Maps ID"></label>
<input type="text" name="googlemaps_id" id="contentmapcoordtfield-googlemaps_id" class="form-control w-100" value="<mt:var name="googlemaps_id" escape="html">">
<label for="contentmapcoordtfield-def_latitude"><__trans phrase="Google Maps Default Latitude"></label>
<input type="text" name="googlemaps_def_latitude" id="contentmapcoordtfield-googlemaps_def_latitude" class="form-control w-100" value="<mt:var name="googlemaps_def_latitude" escape="html">">
<label for="contentmapcoordtfield-def_longitude"><__trans phrase="Google Maps Default Longitude"></label>
<input type="text" name="googlemaps_def_longitude" id="contentmapcoordtfield-googlemaps_def_longitude" class="form-control w-100" value="<mt:var name="googlemaps_def_longitude" escape="html">">
</mtapp:setting>
tmpl\selectmap.tmpl
GoogleMAPを使って、座標を取得できるようにしたHTML
これはどこからか、拝借したもの・・拝借先・・覚えてません。。すみません・・
マーカーの画像を使わないタイプがよかったので・・mt-staticとか個別になると面倒になるので・・
<!DOCTYPE html>
<html lang="ja" itemscope itemtype="http://schema.org/WebPage">
<head>
<meta charset="UTF-8">
<title>経度・緯度</title>
<script type="text/javascript" src="//maps.google.com/maps/api/js?sensor=true&key=<mt:var name="googlemaps_api_key">"></script>
<script type="text/javascript">
function value_set(lat,lng){
if(!lat && !lng) {
return [<mt:var name="googlemaps_def_latitude">,<mt:var name="googlemaps_def_longitude">];
}
return [lat,lng]
}
var Lat_id = "<mt:var name="lat_id">";
var Lng_id = "<mt:var name="lng_id">";
var Lat = "<mt:var name="lat">";
var Lng = "<mt:var name="lng">";
var latlon;
latlon = value_set(Lat,Lng);
// 初期設定項目
var initLat = latlon[0];
var initLng = latlon[1]; // 初期表示する経度
var crossSize = 19; // クロスの長さ
var zoomLevelMin = 0; // ズームレベルの最大値
var zoomLevelMax = 21; // ズームレベルの最小値
var zoomLevelInit = 18; // ズームレベルの初期表示値
var mapOptions = { // mapオプション
zoom: zoomLevelInit,
center: new google.maps.LatLng(initLat,initLng),
navigationControl: true,
scaleControl: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map; // gmapオブジェクト
var controlCross; // センターに表示するクロス
var lat = 0; // 緯度保持
var lng = 0; // 経度保持
var geocoder; // ジオコーダー
function createGmap()
{
geocoder = new google.maps.Geocoder();
map = new google.maps.Map(document.getElementById("gmap"),mapOptions);
// 中心マーカーの表示
createCenterMaker();
// イベントリスナーの登録
google.maps.event.addListener(map,'center_changed',OnMapDraged); // ドラッグ終了
OnMapDrag();
}
function CrossControl(controlDiv, map)
{
var mapDiv = map.getDiv();
var x = (mapDiv.offsetWidth - crossSize + 1) / 2;
var y = (mapDiv.offsetHeight - crossSize + 1) / 2;
var controlCrossV = document.createElement('DIV');
controlCrossV.style.position = 'absolute'
controlCrossV.style.borderStyle = 'none none none solid';
controlCrossV.style.borderWidth = '1px';
controlCrossV.style.borderColor = 'red';
controlCrossV.style.height = crossSize + 'px';
controlCrossV.style.left = 0+ "px";
controlCrossV.style.top = y+ "px";
controlDiv.appendChild(controlCrossV);
var controlCrossH = document.createElement('DIV');
controlCrossH.style.position = 'absolute'
controlCrossH.style.borderStyle = 'solid none none none';
controlCrossH.style.borderWidth = '1px';
controlCrossH.style.borderColor = 'red';
controlCrossH.style.width = crossSize + 'px';
controlCrossH.style.left = (crossSize / 2) * -1+ "px";
controlCrossH.style.top = mapDiv.offsetHeight / 2+ "px";
controlDiv.appendChild(controlCrossH);
}
function createCenterMaker() {
var CrossControlDiv = document.createElement('DIV');
var crossControl = new CrossControl(CrossControlDiv,map);
CrossControlDiv.index = 1;
map.controls[google.maps.ControlPosition.TOP].push(CrossControlDiv);
}
function moveMap()
{
lng = parseFloat(document.points.lng.value);
lat = parseFloat(document.points.lat.value);
map.panTo(new google.maps.LatLng(lat,lng));
}
function OnMapDrag()
{
latlng = map.getCenter();
document.points.lng.value = latlng.lng();
document.points.lat.value = latlng.lat();
}
function OnMapDraged()
{
OnMapDrag();
}
function popup_end(lng,lat)
{
opener.document.getElementById(Lat_id).value = lat;
opener.document.getElementById(Lng_id).value = lng;
window.close();
}
</script>
</head>
<body onload="createGmap()">
<div id="gmap" style="width: 500px; height: 400px"></div>
<br />
<form name="points" method="post" action="">
<input type="text" id="lat" name="lat" size="31" maxlength="20">
<input type="text" id="lng" name="lng" size="32" maxlength="20">
<br />
<input type="hidden" name="url" value="">
<input type="hidden" name="lat_tky" value="">
<input type="hidden" name="lon_tky" value="">
<input type="button" value="決定" onclick="popup_end(this.form.lng.value,this.form.lat.value)">
</font>
</form>
</body>
</html>
tmpl\content_field_type_options\googlemap_coordinate.tmpl
これは、コンテンツデータの方で、表示するHTML
<mt:app:ContentFieldOptionGroup
type="googlemap_coordinate">
<mtapp:ContentFieldOption
id="googlemap-coordinate-initial-lat"
label="<__trans phrase="Google Maps latitude">">
<input ref="initial_lat" type="text" name="initial_lat" id="googlemap-coordinate-initial_date" class="form-control date-field w-25" value={ options.initial_lat } placeholder="">
</mtapp:ContentFieldOption>
<mtapp:ContentFieldOption
id="googlemap-coordinate-initial-lng"
label="<__trans phrase=" oogle Maps longitude">">
<input ref="initial_lng" type="text" name="initial_lng" id="dgooglemap-coordinate-initial_time" class="form-control time-field w-25" value={ options.initial_lng } placeholder="">
</mtapp:ContentFieldOption>
</mt:app:ContentFieldOptionGroup>
tmpl\field_html\field_html_googlemap_coordinate.tmpl
ここでは、MAP選択POPUPに値を渡す部分を仕込んでおく、また、修正時、MAP選択した場合、その座標で地図を表示するようにごにょごにょしておく。
一応id名を渡しておくので、複数あった場合も対応できるかと・・・
<div class="row form-inline googlemap-coordinate-field-container group-container">
<div class="col d-none d-md-block mb-0">
<span>
<input type="text" name="lat-<mt:var name="content_field_id" escape="html">" id="lat-<mt:var name="content_field_id" escape="html">" class="lat-field form-control text group html5-form content-field" value="<mt:var name="lat" escape="html">" placeholder="" mt:watch-change="1" mt:raw-name="1" <mt:var name="required">>
</span>
<span class="separator"> <__trans phrase=", "></span>
<span>
<input type="text" name="lng-<mt:var name="content_field_id" escape="html">" id="lng-<mt:var name="content_field_id" escape="html">" class="lng-field form-control text group html5-form content-field" value="<mt:var name="lng" escape="html">" placeholder="" mt:watch-change="1" mt:raw-name="1" <mt:var name="required">>
</span>
<div class="mt-3">
<a id="mappopup_<mt:var name="content_field_id" escape="html">">
<svg role="img" class="mt-icon--primary mt-icon--sm first-child last-child"><title class="first-child">Add</title><use xlink:href="/test_mt/mt/mt-static/images/sprite.svg#ic_add" class="last-child"></use></svg>
座標選択
</a>
</div>
</div>
</div>
<mt:setvarblock name="jq_js_include" append="1">
$(document).on("click", "[id^=mappopup_]", function(){
var id_str = $(this).attr("id");
stArray = id_str.split("_");
var id_lat = "lat-"+stArray[1];
var id_lng = "lng-"+stArray[1];
var lat = $('#'+id_lat).val();
var lng = $('#'+id_lng).val();
var url ='<mt:var name="script_url">?__mode=google_map_popup&lat_id=' + id_lat + '&lng_id=' + id_lng + '&lat=' + lat + '&lng=' + lng;
win = window.open(url,"map_win","toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=no,width=600,height=600");
});
</mt:setvarblock>
完成のイメージ
プラグイン
プラグインの設定
コンテンツタイプのイメージ
コンテンツデータの入力方法
ContentMapCoordtFieldでできたMTタグ
プラグインの設定で設定した値を取得できます。
MTGoogleMapLatitude、MTGoogleMapLongitudeは地図の中心座標です。地図選択POPUP等でも使用しています、
<$MTGoogleMapId$>
<$MTGoogleMapKey$>
<$MTGoogleMapLatitude$>
<$MTGoogleMapLongitude$>
ContentFieldValue
おいらが解析不十分で・・・内部的な保存が"緯度, 経度"で保存しています。CSVなどでエクスポートした場合、35.16991042521872, 136.90756276140058で1つで入ります。
なので、分割するためにContentFieldValueに要素を追加しています。
coordinate要素 指定なしは、35.16991042521872, 136.90756276140058で出力されます。
lat指定で35.16991042521872
lng指定で136.90756276140058
<mt:ContentFieldValue coordinate="lat"> 緯度
<mt:ContentFieldValue coordinate="lng"> 経度
作成したプラグインの使用例
Googlemap複数マーカー
google.maps.Markerがサポートなくなるそうなので、 google.maps.marker.AdvancedMarkerViewを使っています。
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=<$MTGoogleMapKey$>&callback=initMap&libraries=marker&v=beta" defer></script>
<script>
var markers = [
<mt:Contents content_type="アクセスマップ">
['<p><mt:ContentField content_field="店舗名"><mt:ContentFieldValue></mt:ContentField></p>','<mt:ContentField content_field="GoogleMAP座標"><mt:ContentFieldValue coordinate="lat"></mt:ContentField>','<mt:ContentField content_field="GoogleMAP座標"><mt:ContentFieldValue coordinate="lng"></mt:ContentField>'],
</mt:Contents>
];
function initMap() {
var myOptions = {
zoom: 12,
center: new google.maps.LatLng(<$MTGoogleMapLatitude$>,<$MTGoogleMapLongitude$>),
mapTypeId: google.maps.MapTypeId.ROADMAP,
streetViewControl:false,
mapId: 'DEMO_MAP_ID', // 本番は<$MTGoogleMapId$>
};
var map = new google.maps.Map(document.getElementById("map"), myOptions);
var infoWindow = new google.maps.InfoWindow();
markers.forEach( function(value, i) {
var gtitle = markers[i][0];
var glat = parseFloat(markers[i][1]);
var glng = parseFloat(markers[i][2]);
var Img = document.createElement("img");
Img.src = "./marker1.png";
Img.width = 40; // 横サイズ(px)
Img.height = 40; // 縦サイズ(px)
var marker = new google.maps.marker.AdvancedMarkerView({
position : {
'lat': glat,
'lng': glng
},
map,
title: gtitle,
content: Img
});
marker.addListener("click", ({ domEvent, latLng }) => {
const { target } = domEvent;
infoWindow.close();
infoWindow.setContent(marker.title);
infoWindow.open(marker.map, marker);
});
});
}
window.initMap = initMap;
</script>
<style>
#map {
height: 600px;
}
</style>
</head>
<body>
<div id="map"></div>
</body>
</code></pre>
上記ソースの結果はこんな感じ・・
制限事項
デフォルト値設定 デバックしてません・・・
入力値のチェック入っていません・・・
必須はどちらか1個かもしれません・・・
システムの検索・置換ロジックは、省いてます・・解析不足・・・
さいごに
GoogleMapは有償になったので、それでも問題ないって場合ですね・・
あたらしいのは・・mapIdとかの指定、div id="map"にサイズ指定しておかないとでなかったりと。。。不便・・・
製品版に標準につけてほしい。w
あ、あと。。サポートしていませんから。。うごかんぞぉーとか、クレーム入れないで・・w
あと、過去やったGoogleMapのコードが動かなくて・・?そっちに時間が・・かかったよぉ・・関連からどうぞ。。
では・・
関連
GoogleMapが動かない・・?
https://www.omakase.net/blog/2024/06/googlemap-1.html