うごく生ゴミプログラマの備忘録

うごく生ゴミ 〜再臨〜

Geolocatoion APIで現在地を取得しGoogleマップに表示する方法

JavaScript で Geolocatoion APIを使用して現在地の緯度、経度を取得しGoogleマップに表示するまでをまとめておく。

実際に動いているのはこちら

http://ec2-54-191-139-159.us-west-2.compute.amazonaws.com:8080/forBlog/20160111/

位置情報を取得 ボタンを押し、位置情報の取得を許可すればマップが表示されるはず。

Macsafariでは以下の手順で位置情報の取得を許可しないと現在地を取得できないっぽい。 OS X と Safari の位置情報サービスについて - Apple サポート

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>Geolocation API テスト</title>
    <script src="http://maps.google.com/maps/api/js"></script>
    <script src="./js/app.js"></script>
   <link rel="stylesheet" href="./css/style.css">
  </head>
  <body>
   <p>
      <button id="get_position_button">位置情報取得</button>
    </p>
    <ul>
      <li><span id="latitude"></span></li>
      <li><span id="longitude"></span></li>
      <li><span id="altitude"></span></li>
      <li><span id="accuracy"></span></li>
      <li><span id="altitudeAccuracy"></span></li>
      <li><span id="heading"></span></li>
      <li><span id="speed"></span></li>
      <li><span id="timestamp"></span></li>
    </ul>
    <!-- Google マップ 表示領域 -->
    <div id="map">
    </div>
  </body>
</html>

5行目でGoogle Maps API を使用するためのライブラリを読み込んでいる。

次にCSS Googleマップを表示する領域の縦幅と横幅を指定しているだけ。

#map {
    height: 600px;
    width: 600px;
}

最後にJavaScript

(function () {
    'use strict';
    var successCallBackFunction, errorCallBackFunction, option;

    /**
    * 測位成功時のコールバック関数
    */
    successCallBackFunction = function (position) {
        var myPosition, map, marker;

        myPosition = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
        
        map = new google.maps.Map(document.getElementById('map'), {
            zoom: 14,
            center: myPosition,
            scrollwheel: false,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        });

        marker = new google.maps.Marker({
            position: myPosition,
            map: map
        });

        document.getElementById('latitude').textContent = ('緯度: ' + position.coords.latitude);
        document.getElementById('longitude').textContent = ('経度: ' + position.coords.longitude);
        document.getElementById('altitude').textContent = ('高度: ' + position.coords.altitude);
        document.getElementById('accuracy').textContent = ('緯度/高度の精度: ' + position.coords.accuracy);
        document.getElementById('altitudeAccuracy').textContent = ('高度の精度: ' + position.coords.altitudeAccuracy);
        document.getElementById('heading').textContent = ('方角: ' + position.coords.heading);
        document.getElementById('speed').textContent = ('速度: ' + position.coords.speed);
        document.getElementById('timestamp').textContent = ('測位が成功した時刻: ' + position.timestamp);
    };


    /**
    * 位置情報取得失敗時のコールバック関数
    */
    errorCallBackFunction = function (positionError) {

        alert(positionError.code + ': ' + positionError.message);
    };


    option = {
        enableHighAccuracy: true, // GPS を使用して正確さを増すかどうか true: GPSを使用する false: GPSを使用しない
        maximumAge: 0, // キャッシュを保持するミリ秒
        timeout: 30000 // タイムアウトミリ秒 指定した時間内にデータを取得できない場合タイムアウトエラーを発生させる
    };


    /**
    * HTML読み込み終了時の処理
    */
    window.addEventListener('load', function () {

        // Geolocation API 使用可/不可 のチェック
        if (!navigator.geolocation) {
            alert('Geolocation API 使用不可');
            return;
        }

        document.getElementById('get_position_button').addEventListener('click', function () {

            navigator.geolocation.getCurrentPosition(successCallBackFunction, errorCallBackFunction, option);
        }, false);
    }, false);
}());

以下の部分でボタンを押した際の処理を定義している、

       document.getElementById('get_position_button').addEventListener('click', function () {

            navigator.geolocation.getCurrentPosition(successCallBackFunction, errorCallBackFunction, option);
        }, false);

navigator.geolocation.getCurrentPosition() が現在地を取得するメソッド。 ちなみに、一定間隔おきに現在地を取得するメソッドは watchPosition() メソッド

引数では、左から順番に、現在地の測定成功時のコールバック関数、エラー時のコールバック関数、オプションを渡している。

コールバック関数(ここでは successCallBackFunction )内で Google Map API を使用してマップを表示したり、各DOMに緯度 経度などを表示している。

Java EE (JAX-RS) + JavaScript (Backbone.js) でクロスオリジン通信する方法

クライアント側とサーバサイドとで異なるオリジン(プロトコル+ドメイン+ポート番号)間での通信方法メモ

今回の方針

jsonp を使用するやり方もあるが、今回は XMLHttpRequest Level2 で可能となった Cross-Origin Resource Sharing という仕組みを使用する。

具体的に何をどうするのか

WikipediaXMLHttpRequest のクロスドメインについての記述によると…

XMLHttpRequest - Wikipedia

Access-Control-Allow-Origin: * をサーバサイドから返すレスポンスのヘッダに追加してやればいけるらしい。

実際にヘッダに Access-Control-Allow-Origin: * を入れる

ヘッダに Access-Control-Allow-Origin: * を追加する処理を書いていく。 サーバーサイドには Java EEJAX-RS の使用する。

package foo.bar.jot_down.resources;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;

import foo.bar.jot_down.data.SampleData;


@Path("sample.json")
public class Sample {


    @GET
    @Produces( MediaType.APPLICATION_JSON + "; charset=UTF-8" )
    public Response getIt() {

        SampleData data = new SampleData();
        data.setValue( "ほげほげ" );

        ResponseBuilder responseBuilder = Response.status( Status.OK );
        responseBuilder.header( "Access-Control-Allow-Origin", "*" );
        responseBuilder.entity( data );
        Response response = responseBuilder.build();
        return response;
    }

}

クライアントサイドも実装する

クライアントサイドは JavaScript フレームワークに Backbone を使用する想定。 以下のような model を作成して fetch() する。

module.exports = (function() {
    'use strict';
    var $ = require('jquery');
    var _ = require('underscore');
    var Backbone = require('backbone');
    Backbone.$ = $;


    return Backbone.Model.extend({

        url: 'http://localhost:8080/jot_down2/resources/sample.json',

        parse: function (response) {
            alert( response.value );
            return response;
        }

    });
}());

実際に通信できているか確認する

Chrome デベロッパツールで確認してみた。

f:id:jBellTree:20160102000238p:plain

200 OK が帰ってきているし、ヘッダに Access-Control-Allow-Origin: * が追加されていることもある。

何が嬉しいか

たぶん、今後デスクトップアプリは Electron とかで HTML CSS JavaScript 等のWeb の技術を使って作る手法が主流になる(と個人的には楽だな)と思っていて、その場合 サーバーサイドはクロスオリジン通信を考慮したAPIを作成する機会が出てくると思う。 で、とりあえず今回は Javaでそれができたからめでたしめでたし。

Swift での Hello world でいきなりつまづいた話

参考書に書いてある通り 以下のように書いたら 『'println' has been renamed to 'print'』と出て実行できなかった。

import UIKit

let str = "Hello World!"

println(str)

どうも Swift 2 で println が print に統一されたってことなのかな? println を print に直したら実行できた。こんにちは世界。

import UIKit

let str = "Hello World!"

print(str)

ファイルの読み込みを Java SE7 から追加された try-with-resources文 を使って書き直す

Java SE7 から追加された try-with-resources文 の使い方を、SE6 以前の書き方との比較も含めてメモっとく。 普段の業務では SE6 しか使ってないから、資格の勉強で1度覚えても忘れちゃうんよな。 (サンプルのソースは Java SE6 以前の方も SE7 以降の try-with-resources文使用ヴァージョンも テキストファイル「test.txt」の内容をすべて出力するという物 )

まず、Java SE6 以前での書き方。 ポイントは finally 句で close() すること。 また、その際に BufferedReader のインスタンスが null である場合を考慮して if で処理を分岐すること。 これしとかないと NullPointerException が発生してしまう。

    public static void main( String[] args ) {

        BufferedReader br = null;
        try {

            br = new BufferedReader( new FileReader( "./test.txt" ) );
            String text;
            while ( (text = br.readLine()) != null ) {
                
                System.out.println( text );
            }
        } catch ( IOException e ) {

            e.printStackTrace();

        } finally {

            if ( br != null ) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

で、Java SE7 から追加された try-with-resources文 を使用したヴァージョン。 見た目での一番の違いは

try の後いきなり () 小かっこが登場しているところ。 この中かっこの中には、 ・java.lang.AutoCloseable ・java.io.Closeable のどちらかのインタフェースの実装クラスのリソースの生成処理を書く。

ここ、Oracle 認定 Java Programmer SE7 GOLD で必ず試験に出ます。(個人の感想です。)

また、この小かっこの中では複数のリソースの生成処理を書くこともできる。(ここに関してはまた今度書く。) で、小かっこの中に生成したリソースは自動的に close() が呼ばれ、解放される。

次に、なんやこれ?ってところは finnaly 句でやってる

e.getSuppressed();

getSuppressed() は Java SE7 で Throwable クラスに追加されたメソッドで、抑制された例外の配列を取得するメソッドであり、ここれは、自動的に呼び出された close() メソッド実行中に発生した例外を取得している。

Java SE6 以前のソースと比較すると、それまで finnaly 句でやっていた close するための分岐やら何やらが無くなってすっきりしている気がする。 自前で書かなきゃいけない内容があると、それだけいらんミスする可能性が増えるしね。

    public static void main ( String[] args ) {
        
        try ( BufferedReader br = new BufferedReader( new FileReader("./text.txt") ); ) {

            String text;
            while ( (text = br.readLine()) != null ) {
                
                System.out.println( text );
            }
        } catch ( IOException e ) {
            
            e.printStackTrace();

            Throwable[] suppressedArr = e.getSuppressed();
            for ( Throwable throwable : suppressedArr ) {

                throwable.printStackTrace();
            } 
        }
    }

JavaScript(Backbone.js)で、jsonファイルの読み込み方メモ

アプリケーションの設定値を定義した json ファイルの設定値を Backbone.Model を継承したオブジェクトで保持するようにしたら、 jQueryajax をそのまま使うよりすっきり出来た気がする(個人の感想)のでメモっとく。

もっと良いやり方あったらおしえてください。

まず html 側。 大事なのは head タグ内の script タグ部分。 Backbone.js には jQuery と underscore が必要なので、それらのライブラリを読み込んでいます。

stylesheet 読み込み部分はどうでもいいです。

<!DOCTYPE html>
<html lang="ja">
    <head>
       <meta charset="utf-8">
       <meta http-equiv="Pragma" content="no-cache">
       <meta http-equiv="Cache-Control" content="no-cache">
       <title>title</title>
       <link rel='stylesheet' href='./css/style.css'/>

       <!-- 各ライブラリの読み込み -->
       <script src="./script/lib/jquery-2.1.4.min.js"></script>
       <script src="./script/lib/underscore-min.js"></script>
       <script src="./script/lib/backbone-min.js"></script>

       <!-- 今回書くJavaScriptファイル -->
       <script src="./script/app.js"></script>
   </head>
    <body>
        <p>sample</p>
    </body>
</html>

で、次、読み込み対象の .json ファイルについて 今回は2つ .json ファイルを読み込むことにする。

一つ目の .json ファイル アプリケーションの名前とバージョンを持っている設定ファイルの想定。

config1.json

{
    "app_name": "アプリケーション名",

    "version": "1.00"
}

二つ目 画面か警告とかエラーとかの文言を定義している設定ファイルの想定。

config2.json

{
    "MESSAGE_001": "メッセージゼロゼロイチ",

    "MESSAGE_002": "メッセージゼロゼロニ"
}

で、最後に実際に、上記の json ファイルを読み込んでいるJavaScriptファイルについて。

app.js

var app = app || {};

// config.jsonを読み込むオブジェクト
app.Config1 = Backbone.Model.extend({

    // .json ファイルのパスを設定
    url: './config1.json',
});


app.Config2 = Backbone.Model.extend({

    // .json ファイルのパスを設定
    url: './config2.json',
});


(function(){
    'use strict';
    var config1 = new app.Config1();
    var config2 = new app.Config2();

    config1.fetch().then( function() {

        app.config1 = config1;

        return config2.fetch();

    }).then( function () {
    
        app.config2 = config2; 

        console.log( app.config1.get('app_name') );
        console.log( app.config1.get('version') );
        
        console.log( app.config2.get('MESSAGE_001') );
        console.log( app.config2.get('MESSAGE_002') );
    });

}());

ちょっと長くなってしまった。 まず、前半部分

var app = app || {};

// config.jsonを読み込むオブジェクト
app.Config1 = Backbone.Model.extend({

    // .json ファイルのパスを設定
    url: './config1.json',
});


app.Config2 = Backbone.Model.extend({

    // .json ファイルのパスを設定
    url: './config2.json',
});

jsonを読み込むためのクラスを Backbone.Model を継承して定義しています。 Backbone.Model は url 属性に定義したリソースを取得、作成、更新、削除を行う機能を持っているのでそれを使って楽します。 なので、クラスの定義は url 属性を定義するだけでおしまい。

次、後半部分

(function(){
    'use strict';
    var config1 = new app.Config1();
    var config2 = new app.Config2();

    config1.fetch().then( function() {

        app.config1 = config1;

        return config2.fetch();

    }).then( function () {
    
        app.config2 = config2; 

        console.log( app.config1.get('app_name') );
        console.log( app.config1.get('version') );

        console.log( app.config2.get('MESSAGE_001') );
        console.log( app.config2.get('MESSAGE_002') );
    });

}());

まず、前半部分で定義したクラスを new して変数に代入します。

それで、ここからが個人的にややこしいと感じた部分。

config1.fetch() は実際には 前半部分のクラスの定義設定した url に対して HTTPリクエストのGETメソッドで非同期で取得しにいっている。 で、非同期ってことは

config1.fetch();
console.log( config1.get('app_name') );
console.log( config1.get('version') );
        

こんな風に書くと、config1.fetch(); でjsonファイルを読み込みに行ってるんだけど、読み込み終わらないうちに、2行目の処理に進んじゃんって、 コンソールには undefined undefined って出力される可能性が高い。

で、それを防ぐためにどうしたかって言うと、 .fetch() で jQuery のDifferedオブジェクトが返ってくるので、Differedオブジェクトの then()メソッドを使用して、fetch(実際には HTTP の GETメソッド )が終了するのを待って、次の処理に移るようにしています。

今回の場合 config1.json の読み込みが正常に終わったらば、次は config2.json の読み込みをして、 それもちゃんと終わったらば、確認のために、それぞれの読み込んだ値をコンソールに表示するようにしています。

console.log( app.config1.get('app_name') );
console.log( app.config1.get('version') );

console.log( app.config2.get('MESSAGE_001') );
console.log( app.config2.get('MESSAGE_002') );

GitHubに学生時代に作った論理回路エディタを上げた

GitHubリポジトリが1個だけっていうのも寂しいし、 学生時代に作った論理回路エディタを上げた。

https://github.com/jsuzuki20120311/logic_circuit_editor

f:id:jBellTree:20151220210353p:plain

こんな感じで論理回路を描けるらしい。

せっかくなのでAWSにもデプロイした。

http://ec2-54-191-139-159.us-west-2.compute.amazonaws.com:8080/logic_circuit_editor_3/