2015年4月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
無料ブログはココログ

« 手書き版コピペシールのソースコード | トップページ | MOON で使い回しの効く GUI の作り方? »

2013年12月15日 (日)

手書き検索シールと、とりあえずな汎用の(?) stroke 入力 GUI

先週、 「手書きコピペ」シール を作りましたが、stroke 入力を使えると楽しいです。コピー対象領域を 8 の字型みたいにくり抜けるのは、矩形領域指定ではできない芸当です。

また、シールを起動してから GUI で動作を選択できるのも、ぐっと幅がひろがります。これまで、シールをタップすると問答無用でコードが走り出し、結果を出力して終了というシールしか書けなかったので、処理ごとに別々のシールを書くしかなかったのですが、シールを立ち上げてから動作を選択できれば、似たような動作のシールを一つにまとめることができます。stroke 関係も、これまではシールを立ち上げてから、ユーザーからの入力を受け取るチャンスがなかったため、「最後に書いた storke の範囲を消す」とか「最後に書いた stroke に沿って絵を動かす」とかするしかありませんでしたが、シール起動後に stroke を受け取ることができれば、ずっと自然なシールアプリを作成できるわけです。

しかし、enchant.js がある分かなりマシなはずなのですが、やはり GUI を書くのは面倒です。先週のコピペシールでも、結局一番行数をかけているのは GUI 部分です。ここに可能性があると思うのですが、敷居が高いと手を出す意欲が薄れます。

こう考えて、先週作った GUI ライブラリ部分を、少しでも汎用性が上がるように手を加えてみました。stroke 周り、および単純な動作選択 GUI には使えると思います。

このライブラリをそのまま使って下さるもよし、とりあえずのアイディア確認にプロトタイプとして使い、本番ではオリジナルの GUI を作るもよし、或いは改造して流用してもらうもよし、とりあえず使えるものがあるのは大事だと思い、ライブラリの使用法を解説したいと思います。

また、大きく設計を変えるようなものはともかく、多少なら機能追加もできると思います。何か要望があれば、ダメ元でご意見ください。

以下に使用例を挙げますので、使いたければ、シールをダウンロードして解凍し、lib/getstorke.js (と lib/accessjson.js) を、自分のシールの lib にコピーし、importJS() の引数に、"lib/getstroke.js", "lib/accessjson.js" を追加して使ってみてください。

使い方

getstroke.js を import したうえで、

GUI_GetStroke.base( buttons, caption, options,
    function( selected, minX, minY, maxX, maxY, strokes ){
        // 入力された strokes と、選択されたボタンに応じた処理
}

という形で使用します。options = {} にいろいろなプロパティを設定することで動作を修飾します。

buttons, caption は、以下のような形式で指定します。

var buttons = [
    ['ボタン1', true],
    ['ボタン2', false],
    ['Retry',   true],
    ['ボタン3', true]
];

var caption = "動作選択を促す; 説明文";

buttons の true/false で、ボタンの有効/無効を指定します。false が指定されていると、ボタンはグレーアウトされて、tap しても反応しません。ボタンの名前が 'Retry' になっているボタンを tap すると、callback 関数に処理を移すことなく、ペンの入力をキャンセルして stroke を消去します。

caption に指定した文字列は、動作選択ボタン UI の横幅に合わせて自動的に改行されますが、明示的に改行したい場合は ';' を挟むと、その位置で強制改行されます。

callback 関数の形式は以下のようになります。

function( selected, minX, minY, maxX, maxY, strokes ){}

callback 関数に渡される引数は、

selected :

  • tap されたボタンの番号、buttons に設定した配列の添え字が返ります。上記の例であれば、'ボタン1' が tap されれば 0 が、'ボタン3' が tap されれば 3 が返ります。'Retry' ボタンが tap されても callback されないので、2 を受け取ることはありません。また、ペンによる stroke 入力が全くない状態でボタンが tap された場合は、入力無効を示すために、 -1 が返ります。この場合は strokes に渡されるデータを処理せずに、キャンセル処理など適切な処理をすべきです。

strokes :

  • singleStroke モードでは stroke 1 本分のデータ {width:xx, type:"pen", color:xx, data:[...]} が返ります。multipleStrokes モードでは、stroke の配列[{width:, type:, color:, data:},{},{}...] が返ります。

minX, minY, maxX, maxY :

  • stroke 或いは strokes に含まれる、全ての点を含む矩形領域の左上、右下座標を返します。画面をくり抜いたり、stroke 全体を囲む境界線を描いたりするのに使えますし、コピペなどで stroke を移動する場合は、(minX,minY) を基準とした相対座標に加工する際に必要になります。

options に指定できる内容

options に何も設定せずに呼び出すと、デフォルトとして全画面の singleStroke モードで動作します。コピペなどの領域指定に便利なモードです。

指定できるプロパティは

bgMinX, bgMinY, bgMaxX, bgMaxY :

  • ペン stroke 入力可能領域の左上・右下座標を指定する。4 つ全てを指定しないと無効。デフォルトでは画面全体を入力可能領域とする。

bgColor :

  • ペン stroke 入力可能領域の背景色を指定する。canvas.fillStyle に渡せる値を指定する。デフォルトでは透明で、ページの stroke がそのまま見える。

bgRimColor :

  • ペン stroke 入力可能領域の縁取りの色を指定する。デフォルトでは黒。bgColor が指定されていないと無効。

buttonsCenterX, buttonsCenterY :

  • 動作選択ボタン UI の画面上の初期位置を、その中心座標で指定する。デフォルトは画面中心。

penColorR, penColorG, penColorB :

  • 画面にベン入力される描線の色、および、その結果作成される stroke(s) data の color プロパティを設定する情報。描線色は canvas.strokeStyle = "rgb(penColorR, penColorG, penColorB)" stroke(s) data は color: MOON.rgba2int(penColorR, penColorG, penColorB, 255) に設定される。デフォルトは 255, 0, 0.

penWidth :

  • 画面にベン入力される描線の太さ。デフォルトでは、2 だが、MOONPhase ver 2.8.0 現在、画面描画に反映されない。

multipleStrokes :

  • singleStroke モードと multipleStrokes モードを切り替える。true で multiple, false で single. デフォルトは false. singleStroke モードは範囲指定のための囲み線を想定、データを多少間引きつつ、stroke 一本分のデータを返す。multipleStrokes モードは、文字列あるいは図画の入力を想定。筆圧は反映しないが複数 storke の data を stroke の配列として返す。

attachBgToButtons :

  • デフォルトでは false. true を指定すると、ペン stroke 入力可能領域を、bgMin/Max/X/Y で指定したサイズで、動作選択ボタン UI の背側に張り付ける。動作選択ボタン UI を drag すると、ペン stroke 入力可能領域も drag できる。

頻用する設定のショートカットとして、

GUI_GetStroke.singleStroke( buttons, caption, function(){} )

    GUI_GetStroke.base( buttons, caption, {}, function(){} )

および、

GUI_GetStroke.multipleStrokes( buttons, caption, function(){} )

    var options = { multipleStrokes: true, bgColor: "white" };
    GUI_GetStroke.base( buttons, caption, options, function(){} )

も使えます。

使用例

コピペシール (hack.js の抜粋) [ダウンロード] 

前回のコピペシールを今回のライブラリを使う形に書き換えると、以下のようになります。なお、領域内外判定ルーチンは canvasutil.js を使って作成しています。

    var sticker = Sticker.create();

    sticker.onattach = function(event) {
        var myStickerID = InfoUtil.getStickerID();
        var nullStrokeJSON = MOON.getPaperJSON( myStickerID );
        nullStrokeJSON.strokes = [];
        MOON.setPaperJSON( myStickerID, nullStrokeJSON );

        var buttons = [
            [ 'Cut', true ],
            [ 'Copy', true ],
            [ 'Retry', true ],
            [ 'Cancel', true ]
        ];
        var caption = 'Draw a closed stroke,  then ;select an action.'

        GUI_GetStroke.singleStroke( buttons, caption,
          function( selected, minX, minY, maxX, maxY, stroke ){
            var action = ( selected < 0 ) ? 'Cancel' : buttons[selected][0];
            var isInsideStroke = CanvasUtil.getFuncIsInsideOfStrokeApplied( stroke );
            switch ( action ) {
            case 'Cut':
                CopyPaste.cut( minX, minY, maxX, maxY, isInsideStroke );
                clearSaveInfo();
                saveDataActivity();
                saveCutBasePosition( minX, minY );
                break;
            case 'Copy':
                CopyPaste.copy( minX, minY, maxX, maxY, isInsideStroke );
                clearSaveInfo();
                saveDataActivity();
                break;
            case 'Cancel':
                MOON.peel();
                break;
            }
            MOON.finish();
        });
    };

画面に字を書いて、文字認識させてみる「だけ」のシール (hack.js) [ダウンロード] 

「自分の手書き文字が汚くて認識されないかもしれない」のを確認するシールです。

GUI_GetStroke.multipleStrokes() を使用しているので、背景を白で塗りつぶすため、元のページの描線は見えない状態で、字を書くことができます。

/*
*  recogDrawTest
*   by @H_Kuruno - http://kuruno.cocolog-nifty.com/blog/
*                                   last modified on 2013/12/15
*/
importJS(["lib/MOON.js", "lib/enchant.js", "lib/stylus.enchant.js", "lib/accessjson.js", "lib/getstroke.js"], function() {
    enchant();

    var sticker = Sticker.create();

    sticker.onattach = function(event) {
        MOON.finish();
    };

    sticker.ontap = function(event) {
        var buttons = [
            [ '認識', true ],
            [ 'Retry', true ],
            [ 'Cancel', true ]
        ];
        var caption = 'Draw a closed stroke,  then select an action.';

        GUI_GetStroke.multipleStrokes( buttons, caption,
          function( selected, minX, minY, maxX, maxY, strokes ){
            var action = ( selected < 0 ) ? 'Cancel' : buttons[selected][0];
            switch ( action ) {
            case '認識':
                MOON.alert( '認識結果 : ' + MOON.recognizeStrokes( strokes ) );
                break;
            case 'Cancel':
                MOON.finish();
                break;
            }
        });
    };

    sticker.ondetach = function(event) {
        MOON.finish();
    };

    sticker.register();
});

手書き検索シール (hack.js) [ダウンロード]

Issue Tracker の #98 を、シールで無理やり解決するものです。シールを張り付けると、黄色の背景色で、ペン stroke 入力可能領域が設定されます。options で attachBgToButtons が true に設定されているので、ボタンごと drag することができますから、適当な位置に drag して、もとのページの情報を参照しながら入力することができます。文字を書いたら [認識テスト]ボタンで、正しく認識されるか確認します。誤認識されるようなら [Retry] ボタンでもう一度手書き入力をやり直します。認識結果が良ければ、[検索] ボタンを tap すると、シールを剥がしてから、enchant コマンドで検索したときと同じような処理を実行します。

十分使えるんですが、enchantMOON ここまで来ると動作の遅いのが重ね重ね残念ですね。

/*
*  searchDrawStr
*   by @H_Kuruno - http://kuruno.cocolog-nifty.com/blog/
*                                   last modified on 2013/12/15
*/
importJS(["lib/MOON.js", "lib/enchant.js", "lib/stylus.enchant.js", "lib/accessjson.js", "lib/getstroke.js"], function() {
    enchant();

    var THROW_PEEL_SIGNAL = 'THROW_PEEL_SIGNAL';

    function peelThenThrowToDetach( signal ){
        var sig = signal || true;
        var myStickerID = InfoUtil.getStickerID();
        StorageUtil.set( THROW_PEEL_SIGNAL + myStickerID, sig );
        MOON.peel();
    };

    function catchFromPeel( callback ){
        var myStickerID = InfoUtil.getStickerID();
        var signal = StorageUtil.get( THROW_PEEL_SIGNAL + myStickerID, false );
        if ( signal ) {
            StorageUtil.set( THROW_PEEL_SIGNAL + myStickerID, null );
            callback( signal );
        }
    };

    var sticker = Sticker.create();

    sticker.onattach = function(event) {
        var myStickerID = InfoUtil.getStickerID();
        var nullStrokeJSON = MOON.getPaperJSON( myStickerID );
        nullStrokeJSON.strokes = [];
        MOON.setPaperJSON( myStickerID, nullStrokeJSON );

        var buttons = [
            [ '認識;テスト', true ],
            [ '検索', true ],
            [ 'Retry', true ],
            [ 'Cancel', true ]
        ];
        var caption = 'Draw a closed stroke,  then ;select an action.';
        var options = {
             bgMinX: 0
            ,bgMinY: 0
            ,bgMaxX: 330
            ,bgMaxY: 300
            ,bgColor: "rgb(249,255,211)"
            ,attachBgToButtons: true
            ,buttonsCenterX: 768/2
            ,buttonsCenterY: 1024 *3/5
            ,multipleStrokes: true
        };

        GUI_GetStroke.base( buttons, caption, options,
          function( selected, minX, minY, maxX, maxY, strokes ){
            var action = ( selected < 0 ) ? 'Cancel' : buttons[selected][0];
            switch ( action ) {
            case '認識;テスト':
                MOON.alert( '認識結果 : ' + MOON.recognizeStrokes( strokes ) );
                break;
            case '検索':
                peelThenThrowToDetach( MOON.recognizeStrokes( strokes ) );
                break;
            case 'Cancel':
                MOON.peel();
                break;
            }
        });
    };

    sticker.ontap = function(event) {
        MOON.finish();
    };

    sticker.ondetach = function(event) {
        catchFromPeel( function( signal ){
            MOON.searchPage( signal );
        });
        MOON.finish();
    };

    sticker.register();
});

こういうのは、本格的にやるのなら

こういうのは、本格的にやるのなら、GitHub でも使って、大勢で開発するのがいいんでしょうが、私がまだ git の勉強中なのと、GitHub にしちゃうと、祭りに参加できる人の敷居が上がりそうなので、とりあえずシールをダウンロードして zip を解凍して使いまわしてもらう方向で。

できれば、こんな感じで、他にも使いまわせるライブラリを共同開発していけるといいんですけどね。

« 手書き版コピペシールのソースコード | トップページ | MOON で使い回しの効く GUI の作り方? »

enchantMOON」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1527616/54268608

この記事へのトラックバック一覧です: 手書き検索シールと、とりあえずな汎用の(?) stroke 入力 GUI:

« 手書き版コピペシールのソースコード | トップページ | MOON で使い回しの効く GUI の作り方? »