document.getElementById("open").onclick = function(evt) と、ws.onopen = function(evt) が、混乱して、上手く動かなかったけど、ようやく分かりました(ような気ががしています)。
つまり、"ボタン"と"websocket"という、全く別物を取り扱っている、ということに、やっと気がつきました ―― 同じ"open"という言葉を使うので、混同していました。
なので、
ws.close()処理は、当然に、document.getElementById("open").onclick = function(evt) { 処理内容} の中で実施しなけばなりません。
ws.onopen = function(evt){処理内容}は、すでにwebsocketのclose処理が行われた後の処理を記載するので、ここでws.close()を記載したら、変なことになります(二重にwebsocketのclose処理をすることになる)
それと、位置情報をコールバックで取得する関数を、
const successCallback = (position) => { 処理内容 }
と
エラーイベントを検知する関数を、
const errorCallback = (err) => { 処理内容 }
と記載した場合、
このコールバックを登録する関数は、
watchPositionID = navigator.geolocation.watchPosition(successCallback, errorCallback, options);
であり、
このコールバックを停止する関数は、navigator.geolocation.clearWatch(watchPositionID);
となります。
という訳で、server26.goの"smartphoneTemplate"で登録している、htmlファイル(javascriptを含む)の部分だけ切り出したものを記載しておきます。
var smartphoneTemplate = template.Must(template.New("").Parse(`
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<script>
let watchPositionID; // グローバル変数として出しておく
let ws; // グローバル変数として出しておく
window.onload = () => {
// これは、Web起動時に最初に読まれる部分であるが、今回、これらの関数は、全部
// document.getElementById("open").onclick = function(evt) { // openボタンを押した時
// 中に放り込んだ。 openボタンを押した後に起動するようにする為である
// navigator.geolocation.watchPositionについては次のURLにかかれています。
// https://developer.mozilla.org/ja/docs/Web/API/Geolocation/watchPosition
// これが位置情報コールバックの起動コマンド
//watchPositionID = navigator.geolocation.watchPosition(successCallback, errorCallback, options);
// ここで(もう)webソケットを開く
//ws = new WebSocket("{{.}}");
};
// ブラウザーを閉じる前に位置の監視を止めます
window.onbeforeunload = () => {
// こちらの内容も
// document.getElementById("close").onclick = function(evt) { // closeボタンを押した時
// の中に放り込んだ closeボタンを押した時に起動するようにする為である
// これが位置情報コールバック停止のコマンド
//navigator.geolocation.clearWatch(watchPositionID);
//ws.close();
}
// 引数にはミリ秒を指定。(例:5秒の場合は5000)
function sleep(a){
var dt1 = new Date().getTime();
var dt2 = new Date().getTime();
while (dt2 < dt1 + a){
dt2 = new Date().getTime();
}
return;
}
// 以下の3つはグローバル変数として取り扱う
var personal_id =0;
var lat;
var lng;
//var ws;
// 位置情報を構造体として格納する為のファンクション(jsでは、こういう風に使うらしい)
function obj(id, lat, lng){
this.id = id;
this.lat = lat;
this.lng = lng;
}
// 乱数生成装置 (minとmaxの間の乱数を作る)
function random(min, max){
return Math.random()*(max-min) + min;
}
window.addEventListener("load", function(evt) {
// メッセージ表示部
var output = document.getElementById("output");
var input = document.getElementById("input");
var print = function(message) {
var d = document.createElement("div");
d.textContent = message;
output.appendChild(d);
};
///// 起動時のボタン設定(アクティブにしたり非アクティブにしたりする)
// disabled属性を削除
document.getElementById("open").removeAttribute("disabled");
document.getElementById("open").style.color = "black";
// disabled属性を設定 (closeボタンを非活性化)
document.getElementById("close").setAttribute("disabled", true);
document.getElementById("close").style.color = "White";
document.getElementById("open").onclick = function(evt) { // openボタンを押した時
console.log("document.getElementById open");
// disabled属性を設定 (openボタンを非活性化)
document.getElementById("open").setAttribute("disabled", true);
document.getElementById("open").style.color = "White";
// disabled属性を削除(closeボタンを非活性化)
document.getElementById("close").removeAttribute("disabled");
document.getElementById("close").style.color = "black";
//if (ws) {
// return false;
//}
// ここでコールバック関数を起動
watchPositionID = navigator.geolocation.watchPosition(successCallback, errorCallback, options);
// websocket オープン
ws = new WebSocket("{{.}}");
// 最初はidを0にする
personal_id = 0;
ws.onopen = function(evt) { // 通信openイベントを検知した時(通信がopen状態になった後)
print("OPEN");
var send_obj = new obj(0, lat, lng); // 最初はpersonal_idを"0"としてエントリ
console.log("open:send_obj");
console.log(send_obj.id);
console.log(send_obj.lat);
console.log(send_obj.lng);
var json_obj = JSON.stringify(send_obj);
ws.send(json_obj);
}
ws.onclose = function(evt) { // 通信closeイベント(×ボタン)を検知した時 (通信がclose状態になった後)
print("onclose:CLOSE");
ws = null;
}
ws.onmessage = function(evt) { // 通信メッセージを受信した時(受信した後)
print("RESPONSE: " + evt.data); // jsonメッセージの内容を表示
// データをJSON形式に変更
var obj = JSON.parse(evt.data);
personal_id = obj.id; // IDの取得(何回も取る必要はないが)
console.log("personal_id");
console.log(personal_id);
if ((Math.abs(obj.lat) > 90.0) || (Math.abs(obj.lng) > 180.0)){ // 異常な座標が入った場合は、マーカーを消去する
console.log("before ws.close()");
ws.close();
console.log("after ws.close()");
}
}
ws.onerror = function(evt) { // エラーイベントを検知した時(検知した後)
print("ERROR: " + evt.data);
}
return false;
};
document.getElementById("close").onclick = function(evt) { // closeボタンを押した時
console.log(" document.getElementById close");
// disabled属性を削除
document.getElementById("open").removeAttribute("disabled");
document.getElementById("open").style.color = "black";
// disabled属性を設定 (closeボタンを非活性化)
document.getElementById("close").setAttribute("disabled", true);
document.getElementById("close").style.color = "White";
if (!ws) {
return false;
}
var send_obj = new obj(personal_id, 999.9, 999.9); // 意図的に異常な位置情報を入れて正常終了させる処理
console.log("close:send_obj");
console.log(send_obj.id);
console.log(send_obj.lat);
console.log(send_obj.lng);
var json_obj = JSON.stringify(send_obj);
ws.send(json_obj);
ws.close(); // これはws.closeの方で実施すると変なことになる closeが実施された後で、close()することになる
navigator.geolocation.clearWatch(watchPositionID); //コールバック関数の停止?
personal_id = 0; // 最後もidを0にする
return false;
};
});
// 位置情報の取得に成功した際のコールバック
const successCallback = (position) => {
console.log("successCallback:position");
lat = position.coords.latitude;
lng = position.coords.longitude;
console.log(personal_id);
console.log(lat);
console.log(lng);
//コールバックが発生するタイミングでサーバに位置情報を送付する
if (personal_id != 0){
var send_obj = new obj(personal_id, lat, lng); // 最初は"0"でエントリ
console.log("open:send_obj");
console.log(send_obj.id);
console.log(send_obj.lat);
console.log(send_obj.lng);
var json_obj = JSON.stringify(send_obj);
ws.send(json_obj);
}
// sleep(1000); // 1秒待つ
}
// 位置情報の取得に失敗した際のコールバック
const errorCallback = (err) => {
console.log(err);
};
// 位置を監視する構成オプション
// オプションの内容は次のリンクに書かれています。
// https://developer.mozilla.org/ja/docs/Web/API/PositionOptions
const options = {
enableHighAccuracy: true,
//timeout: 5000,
timeout: 500000,
maximumAge: 0
};
</script>
</head>
<body>
<table>
<tr><td valign="top" width="50%">
<p>Click "Open" to create a connection to the server,
"Send" to send a message to the server and "Close" to close the connection.
You can change the message and send multiple times.
<p>
<form>
<button id="open">Open</button>
<!-- <p><input id="input" type="text" value="Hello world!"> -->
<!-- <button id="send">Send</button> -->
<button id="close">Close</button>
</form>
</td><td valign="top" width="50%">
<div id="output"></div>
</td></tr></table>
</body>
</html>
`))