カテゴリー別アーカイブ: Web Applicaation

click addEventListener

前回なにげに書いたコードを見返してアレ?となった。
addEventListener には click イベントを指定できるのか。
touchend とか mouseup みたいなのでなくていいんだね。

タッチパネルとマウスの両方がこの指定でイケるみたい。
それぞれでどんな感じになるか実験ページを書いてみよう。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>タップとクリック</title>
<!-- for Smart Phone -->
<meta name="viewport" content="
    width=device-width,
    initial-scale=1.0,
    minimum-scale=1.0,
    maximum-scale=1.0,
    user-scalable=no" />
<style>
body {
    -webkit-text-size-adjust: 100%;
    font-size: 24pt;
}
div {
    background-color: #000088;
    border: 1px solid #0000ff;
    color: #ffffff;
}
</style>
<script type="text/javascript"><!--

    var counts = [0, 0, 0];
    var touch, mouse, click = null;

    var init = function() {
        // Touch
        //if (window.TouchEvent) {
            touch = document.getElementById("ID_TAP");
            touch.addEventListener("touchend", function() {
                counts[0] += 1;
                touch.innerHTML = "タップカウント: " + counts[0];
            });
        //}
        // Mouse
        mouse = document.getElementById("ID_MOUSE");
        mouse.addEventListener("mouseup", function() {
            counts[1] += 1;
            mouse.innerHTML = "マウスカウント: " + counts[1];
        });
        // Click
        click = document.getElementById("ID_CLICK");
        click.addEventListener("click", function() {
            counts[2] += 1;
            click.innerHTML = "クリックカウント: " + counts[2];
        });
    }
    //-->
</script>

</head>
<body onLoad="init()">

<div id="ID_TAP">タップカウント: 0</div>
<br />
<div id="ID_MOUSE">マウスカウント: 0</div>
<br />
<div id="ID_CLICK">クリックカウント: 0</div>
<br />
<p><a href=".">Back</a></p>
</body>
</html>

タップとクリック

tap_click

あれ?タッチパネルエミュレートで mouseup イベントが発生するのね。
iPhone Safari で試してもやはり同じ、そういうものなのか。

touchend は当然タッチパネルかエミュレートでしか反応しない。
まあこのイベントは本来マルチタッチ用途ですし使い道が違うかと。

click イベントという名前も直感的だし両対応だし今後はコイツだな。
しかし HTML5 関連サイトでもあまり見かけないような。

a download

Web を回って気になるタグを見つけた。
a 要素には download 属性を付けることができるんですね。

a 要素 – HTML | MDN

Safari は現在未対応か、残念。
Apple はセキュリティ関連で対応しないのかもだけど。

JavaScript – aタグのdownload属性 – Qiita

こんなことができるみたい。
いや、これって通常はダウンロードできないファイルに使えないか?
application/x-php とかね。
PHP が実行される前のファイルのままダウンロードできるかも。

<a href="#" download="index.php">PHP ファイルをダウンロード</a>

とやってみると Chrome は OK だけど Firefox はダメ。
PHP は当然のように実行されてしまった、残念。
うーん、素直に MDN の方法を試してみる。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>a download</title>
<!-- for Smart Phone -->
<meta name="viewport" content="
    width=device-width,
    initial-scale=1.0,
    minimum-scale=1.0,
    maximum-scale=1.0,
    user-scalable=no" />
<script type="text/javascript"><!--
    var init = function() {
        var link = document.createElement('a');
        link.innerHTML = 'download php file';

        link.addEventListener('click', function(ev) {
            link.href = 'index.php';
            link.download = "download.php";
        }, false);
        document.getElementById("ID_DL").appendChild(link);
    }
    //-->
</script>
</head>
<body onLoad="init()">
<div id="ID_DL"></div>

<br />
<p><a href=".">戻る</a></p>
</body>
</html>

a download

a_download

リンクの下線が表示されないしマウスカーソルも矢印のまま。
でもクリックすれば Chrome, Firefox 共ダウンロードできた。
クリックした後は下線が付くのは何故なんだろうな?

PHP はやはり実行された後のファイルしか取得できない。
そういう使い方ではないということでしょう。

でも通常はダウンロードにならない PHP でもダウンロードになるのは確認できた。
iOS 版 Chrome はガン無視されたじゃねーかコノヤロウ。
モバイルで便利そうな仕組みなのにモバイル未対応という…
まあ今後どうなるかはワカンナイZE!

JavaScript clientWidth

あけましておめでとうございます。

さて元旦からいきなりですが。
iOS9 Safari Bug | PaePoi
やっとコレの回避策が解りました。

【Javascript】ブラウザの表示領域サイズ取得について – すたら日記

うおぉ、document.documentElement.clientWidth を使うのか!
古いページだけどモバイル Safari でもこのメソッドは使えるようです。
window.innerWidth のバグじゃなかったのね。

ついでに、window.outerWidth は Safari で使えないようだ。
それはもうどうでもよくて。

早速パソコン表示は 728px バナーに戻すとしよう。
よしよし元通り、パソコン用でモバイルバナーはやはり変だったし。

チェック用途の実験ページも書き換えて。
ソースはパソコンで Ctrl+U ね(手抜き)
画面サイズ取得

safari_width

あれ?キチンと window.innerWidth で取得できている。
試しに document.documentElement.clientWidth をコメントアウト。
やはり駄目、取得後ならイケるみたいだが理由はワカンネエ!
レスポンシブ・ウェブデザインってムズい!

以下おまけ。

aqua

無料ガチャでアクアきたー!
って水属性ばかり強くなってどないせーと、風と光をくれよ…
特攻は HR 2 人、まあいいかお年玉をもらった。

Similar image @ Canvas

前回 Gjs でやった近似画像検索を Web ブラウザで。

Web で画像のピクセルデータ取得は意外に簡単だった。
…けれど困った結果になってしもーたがね。

とりあえず
16 3月 2014 | while(isプログラマ)
なるほど、Image と Canvas だけでできるのか。
つまり外部ライブラリは必要無いと。

[3][HTML][canvas]canvasで画像解析 – wataメモ
ピクセル毎のデータはこんなにアッサリ得られるようだ。

ただ Web での画像読み込みはローカルファイルが使えない。
下記コードを試すには Apache 等を使う必要あり。

更に有名な話で、ブラウザの画像読み込みは非同期である。
処理は onload ハンドラから行うのを忘れずに。

現行ブラウザはまだ let が使えないので var に書き換えて。
それと webkit では sort 関数の戻り値は整数にする必要があった。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Similar Image Sample</title>
<!-- for Smart Phone -->
<meta name="viewport" content="
    width=device-width,
    initial-scale=1.0,
    minimum-scale=1.0,
    maximum-scale=1.0,
    user-scalable=no" />
<style>
body {
    -webkit-text-size-adjust: 100%;
}
</style>
<script type="text/javascript"><!--

    const XY = 48;

    function init() {
        // 画像のロードは非同期なので onload 内で処理
        // ローカルファイルは読み込めないので Apache 等で
        var sample = new Image();
        sample.onload = function() {
            // ロードしたので Lab 値を得る
            var sample_lab = getImageLab(sample);
            // 比較対象
            var datas = ["nae01.jpg","nae02.jpg","nae03.jpg","nae04.jpg","nae05.jpg"];
            var diff = [];
            datas.forEach(function(element, index) {
                var data = new Image();
                data.onload = function() {
                    var lab = getImageLab(this);
                    // 比較
                    var distance = 0;
                    sample_lab.forEach(function(element, index) {
                        distance += getLabDistance(element, lab[index]);
                    });
                    diff.push({n:distance, name:datas[index]});
                    // 5枚ともロードが完了したら出力
                    if (diff.length == 5) {
                        output(diff);
                    }
                }
                data.src = element;
            });
        }
        sample.src = "nae.jpg";
    }

    function output(diff) {
        // sort
        diff.sort(function(a, b) {
            //return a.n > b.n; // no webkit
            return a.n - b.n;
        });
        // 確認
        var out = "";
        diff.forEach(function(element, index) {
            out += element.name + " " + element.n + "<br />";
        });
        document.getElementById("ID_TEXT").innerHTML += out;
    }

    // 画像をリサイズしピクセルごとのLab色空間上の座標を取得する
    function getImageLab(image){
        //
        var canvas = document.createElement("canvas");
        canvas.width = canvas.height = XY;
        var ctx = canvas.getContext("2d");
        ctx.drawImage(image, 0, 0, XY, XY);
        // 取り出し、コレは同期する
        var pixeldata = ctx.getImageData(0, 0, XY, XY);
        var lab = [];
        for(var i=0; i<XY; i++){
            for(var j=0; j<XY; j++){
                var r = pixeldata.data[j*4 + i*XY*4];
                var g = pixeldata.data[j*4 + i*XY*4 + 1];
                var b = pixeldata.data[j*4 + i*XY*4 + 2];
                lab.push(rgb2lab([r, g, b]));
            }
        }
        document.getElementById("ID_CANVAS").appendChild(canvas);
        return lab;
    }

    // xyz色空間上の座標をlab色空間上の座標に変換する
    function xyz2lab(xyz) {
        var threshold = 0.008856;

        var ref_x = 0.96422;
        var ref_y = 1.0000;
        var ref_z = 0.82521;

        var var_x = xyz[0] / (ref_x * 100);
        var var_y = xyz[1] / (ref_y * 100);      
        var var_z = xyz[2] / (ref_z * 100);
          
        var_x = (var_x > threshold) ? var_x = Math.pow(var_x, 1/3 ) : (7.787 * var_x) + (16 / 116);
        var_y = (var_y > threshold) ? var_y = Math.pow(var_y, 1/3 ) : (7.787 * var_y) + (16 / 116);
        var_z = (var_z > threshold) ? var_z = Math.pow(var_z, 1/3 ) : (7.787 * var_z) + (16 / 116);

        var l = ( 116 * var_y ) - 16;
        var a = 500 * ( var_x - var_y );
        var b = 200 * ( var_y - var_z );
        return [l, a, b];
    }
     
    // rgb値をxyz色空間上の座標に変換する
    function rgb2xyz(rgb) {
        var r = rgb[0] / 255;
        var g = rgb[1] / 255;
        var b = rgb[2] / 255;
     
        r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
        g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
        b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
     
        r = r * 100;
        g = g * 100;
        b = b * 100;
          
        var xyz = [];
          
        //sRGB D50
        xyz.push(r * 0.4360747 + g * 0.3850649 + b * 0.1430804);
        xyz.push(r * 0.2225045 + g * 0.7168786 + b * 0.0606169);
        xyz.push(r * 0.0139322 + g * 0.0971045 + b * 0.7141733);
        return xyz;
    }
     
    // rgb値をlab色空間上の座標に変換する
    function rgb2lab(rgb) {
        var xyz = rgb2xyz(rgb);
        var lab = xyz2lab(xyz);
        return lab;
    }
     
    // 2つの座標を比較し距離を返す
    function getLabDistance(p1, p2){
        return Math.sqrt( Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2) + Math.pow(p2[2] - p1[2], 2) );
    }
    //-->
</script>

</head>
<body onLoad="init()">
<div id="ID_TEXT" style="font-size:12pt"></div>
<div id="ID_CANVAS"></div>
</body>
</html>

blink_draw

webkit_draw

Gjs の時と全然順番が違うんですけど。
blink と webkit も数値が全然違う。
いや iPhone 版 Chrome は Safari と同じ数値になってしまう。
それより縮小率によって順番がコロコロ変わるのは頂けない。
色々とどういうことだってばよ。

Gjs は縮小率を変えても順番はほぼ変わらないようです。
圧縮手段が違うのがそんなに影響するのかな。

GdkPixbuf で上記と同じ 24x24px の画像を作って比較してみる。

#!/usr/bin/env python3

from gi.repository import Gtk, Gdk, GdkPixbuf
  
class DrawWin(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.pixs = []
        for s in ["nae.jpg", "nae01.jpg","nae02.jpg","nae03.jpg","nae04.jpg","nae05.jpg"]:
            p = GdkPixbuf.Pixbuf.new_from_file(s)
            pixbuf = GdkPixbuf.Pixbuf.scale_simple(p, 24, 24, GdkPixbuf.InterpType.BILINEAR)
            self.pixs.append(pixbuf)
        # self
        self.resize(24*6, 24)
        self.connect("delete-event", Gtk.main_quit)
        self.show_all()

    def do_draw(self, cr):
        offset = 0
        for pixbuf in self.pixs:
            Gdk.cairo_set_source_pixbuf(cr, pixbuf, offset, 0)
            offset += 24
            cr.paint()
 
DrawWin()
Gtk.main()

って、小さすぎてわかんないや。
両方のスクリーンショットを撮って eog で拡大比較。

pixbuf_and_blink

なんだこれ、blink 雑すぎ!
これじゃ縮小率でコロコロ順番が変わって当然。
webkit も多分同じなんだろうな。

ということで、この方法は使えない。
同一画像がゼロにはなるので同一画像検索には使える。
って、それでいいならもっと簡単な手段があるってば。

縮小しなければなんとかなりそうだけど色々と効率が悪いかも。
外部ライブラリに頼るか別の手段にするか、うーん。。。

Smart Phone Auto Link

iOS 9.0.1 にアップデートが早速きた。
window.innerWidth 初期値の不具合は直っていなかった。
うーん、やっぱり対策しなきゃダメか。

面倒だから当面は全部モバイル用 CSS にする。
いや、上手い回避法が思いつかないだけです。

色々調べているうちに面白いことを見つける。

自動リンクの確認

住所をタップで Map が開くのって便利そうだな。
iPhone でもやってほしいな日式住所対応で。

てか Google ってココまでやるのかと。
スマホのアプリ作りは個人じゃ話にならんレベルになっているや。