飴屋

開発日記/2018年の日記

2018/12/6

Chrome(多分Safariも)で発生した問題がありました。display:flexで3つdiv要素を並べていたのですが、ある環境ではそれが崩れるようになってしまいました。同じブラウザを別の環境で使用しても発生しなくてしばらく悩んでいたのですが、ブラウザの拡大率がこの現象のトリガーになっていたようです。

一般的なブラウザはCtrl+[+]やCtrl+[-]を押して、レンダリングの倍率を変更することができますが、問題の起きた環境はどうも倍率が110%になっていたようです。100%のときには、特に指定しなくてもdiv要素の幅は均等に1/3になって並んでくれていたのですが、倍率を変更するとどうもこの均等割り付けが機能しなくなるようでした。バグなのか仕様なのかはわかりませんが、他のブラウザでは発生しなかったし、論理的に説明できなそうな現象なので、ブラウザのバグという扱いで終わらせたいところですが、修正せよとのことなので、div要素各々にwidth:calc(33.3% - 20px)と指定をつけ、幅を明示することで解決しました。(20pxは要素間のマージンの分です。)

2018/11/23

input[type="number"]はNumber型の数値入力欄なので、数字以外にもマイナス記号や小数点が入力できます。そして指数表記用に「e」も入力できるのですね。とある案件でjQueryのspinner UIをつけたinput[type="number"]で「e」を入力できないようにしてほしいと言われました。input[type="text"]であればさほど悩む内容ではないのですが、input[type="number"]だとグッと考えることが増えました。(ちなみに入力値は正の整数値)

まず思いついたのはpattern属性で入力可能な値を絞ってしまうことでした。

<input type="number" pattern="\d*" id="hoge">

しかし、input[type="number"]ではそもそもpattern属性は有効ではないのでした。ということで、元々この入力欄のkeyupやchangeイベント時に値をチェックしていたので、一緒に「e」の入力を検知してみることにしました。

//jQuery spinnerを使っているのでjQueryを使った実装
$('#hoge').on('keyup change',function(){
if ($(this).val().match(/\D/)) $(this).val($(this).val().replace(/\D/g,''));
});

数字以外の文字が入力されていたらカットするという内容のつもりで書いたのですが、これが意図した動作をしません。どうも理由はinput[type="number"]に入る値(value)は「数値」か「空文字列」に限られるというW3Cのルールに従っているせいなのだそうです。例えば「130」の後ろに「e」を入力して「130e」とした段階では「130e」はNumber型の数値とは言えない(指数表現として不適格)ので、$('#hoge').val()は空文字列が返ってくるのです。見た目は「130e」ですが、実態はから文字列という状況なんですね。この見た目と実態の乖離はもしかしたら将来的なブラウザの実装によっては改善するんじゃないかとも思うのですが、現状のブラウザで何とかするために直前の入力状態を確保しておくという方法を取ってみました。

var preInput = ''; //直前の入力値
$('#hoge').on('keyup change',function(){
if ($(this).val().match(/\D/) || !this.checkValidity()) {
$(this).val(preInput);
} else {
preInput = $(this).val();
}
});

確かこんな実装にしました。キー入力の度に入力値に数字以外の文字があるかどうかと、checkValidityで有効な数値かどうかを確認して、OKなら直前の入力値を更新し、NGなら直前の入力値に戻す、という内容です。

ひとまずこれでOKかと思ったのですが、checkValidityの返す結果がブラウザによってマチマチ・・・というかIE11が「e」を有効な入力値として許容するという問題がみつかりましたが、それはまた別のお話。

2018/7/29

iPhoneのMobile Safariでアニメーションが動いてない!という連絡を受けて、原因を推測して修正したときの話です。

そのWEBサイトでは、CSSの「animation」プロパティを使って画像が漂うような動きを指定していました。しかし、iPhoneで閲覧すると画像は静止したまま動いてくれませんでした。iPhoneだけで起こる問題に対処する作業は、過去に何度もありますが、CSSで規定した静的な指定が動作しないとなるとMobile Safari自体の欠陥なんじゃないかな~とかなんとか思いつつ、似たような事例を探してみることにします。特筆事項としては、閲覧中のページを一度別のタブに変更してから戻ってくると、アニメーションがちゃんと開始される、ということです。

@keyframes animImg {
50% {
transform: translate(-10%, 10%);
}
100% {
transform: translate(0);
}
}

原因はtransformプロパティにtranslate(平行移動)の指定を入れる際に「%」単位で移動量を指定することにあるようでした。推測になりますが、ブラウザの内部的に画面のサイズを計算し終わる前にアニメーションの移動量を「%」から別の描画単位に変換されてしまい、縦横の移動量が「0」になったために静止してるように見えたんじゃないかと思います。画面サイズの計算が終わった段階で、移動量も更新されてほしいところですが、未実装なんでしょうかね。

対策として、画面のサイズが計算し終わったタイミングでアニメーションが行われるように刺激を加えてみました。

//jQueryを使った例
$(document).ready(function(){
$('#mondaino img').css({'animation-play-state':'running'});
});

これで動いたのでよしとしました。

2018/6/20

ふいにレンタルサーバー上でmecabが動かしたいという衝動に駆られていろいろやってみたメモ。なお、レンタルサーバーはXserverです。

http://palmgate.co.jp/masato_kato/article.html&id=127

こちらを参考にmecabと辞書をインストールしました。レンタルサーバーなので、 /home/ACCOUNT-NAME/ 配下にインストールせざるを得ないという部分が特殊です。参考サイトに倣って /home/ACCOUNT-NAME/bin/mecab に配置しました。

続いて、perlが好きなのでperlのバインディング(ラッパーみたいなやつ)をインストールしてみます。perlのモジュールもレンタルサーバーなので勝手はできず /home/ACCOUNT-NAME/lib に配置しようと思います。

$ tar xvfz mecab-perl-0.996.tar.gz
$ cd mecab-perl-0.996
$ perl Makefile.PL
$ make
$ make install

通常なら↑こんな感じmecab-perl-0.996.tar.gzを展開して、Makefileを作って、makeすればいいそうですが、まずMakefileの作成に躓きます。Makefile.PLの中で呼び出す mecab-config にパスが通っていない模様。

use ExtUtils::MakeMaker;
WriteMakefile(
'NAME' => 'MeCab',
'CC' => `/home/ACCOUNT-NAME/bin/mecab-0.996/mecab-config --cxx`,
'LD' => `/home/ACCOUNT-NAME/bin/mecab-0.996/mecab-config --cxx`,
'INC' => `/home/ACCOUNT-NAME/bin/mecab-0.996/mecab-config --cflags`,
'LIBS' => `/home/ACCOUNT-NAME/bin/mecab-0.996/mecab-config --libs`,
'VERSION' => `/home/ACCOUNT-NAME/bin/mecab-0.996/mecab-config --version`,
'OBJECT' => 'MeCab_wrap.o'
);

↑こんな感じでmecab本体をインストールしたときの作業パスを加えてやるとMakefileができました。そのままインストールしようとすると、標準のモジュール置き場にインストールしようとして権限がなくて失敗するので、Makefileを直接、書き換えてみました。

INSTALLPRIVLIB = /home/ACCOUNT-NAME/lib
INSTALLSITELIB = /home/ACCOUNT-NAME/lib
INSTALLVENDORLIB = /home/ACCOUNT-NAME/lib
INSTALLARCHLIB = /home/ACCOUNT-NAME/lib
INSTALLSITEARCH = /home/ACCOUNT-NAME/lib
INSTALLVENDORARCH = /home/ACCOUNT-NAME/lib

正直、中身が把握できてないのでインストール先に関係ありそうな変数をいくつかいじってみたという感じです。これで設置はOKです。設置したパスを use lib で指定すれば、perlに必要なモジュールが読み込まれます。

$ perl test.pl

さっそくパッケージの中にあった test.plを実行してみます。が、動かない。mecab本体のライブラリ(shared object)が読み込めないとのこと。/home/ACCOUNT-NAME/bin/mecab/lib の中に必要なファイル libmecab.so.2 はあるのですが、shared objectの本来の置き場所にないので読み込めないようです。makeの際に同じ場所にある libmecab.a を静的にリンクしてみようとも思いましたが、リンカの知識が乏しいので断念しました。(-fPIC?なにそれ?)

LD_LIBRARY_PATH=$HOME/bin/mecab/lib
export LD_LIBRARY_PATH

shared objectの置き場所のパスは環境変数LD_LIBRARY_PATHで規定されるとのことなので、.bash_profileにこんな設定を足してみたところ test.pl が無事実行されて、分かち書きされた文章が表示されました。
続いて、これをCGIとして呼び出したいと思ったのですが、これが茨の道でした。環境変数LD_LIBRARY_PATHさえ設定してやれば動くことはわかっているのですが、bashの設定がapacheのプロセスに引き継がれるわけもなく、.htaccessでmod_rewriteやmod_envを使って環境変数の書き換えを行おうとしてもうまくいかず(多分権限がない)、perlのスクリプト上でBEGIN節に環境変数の設定を書き加えても、タイミングが遅いので意味はありませんでした。バインディングを捨てて、自前でmecabの出力をparseしようかどうしようか、いろいろ悩んだ結果、最終的に子プロセスに投げるという方法で解決することにしました。

$ENV{LD_LIBRARY_PATH} = '/home/ACCOUNT-NAME/bin/mecab/lib';
system 'perl child.pl';

環境変数を書き換えた上でsystemコマンドでもなんでも子プロセスを呼べば、環境変数が親から引き継がれた状態で実行されるのでした。無駄に複雑になった気もしますが、動くには動きました。もっといい方法があれば知りたいです。

2018/6/13

cssのtransitionが設定通りに動いたり、動かなかったりした話。PC用のサイトで複数の画像を並べるページがありまして、最大5列、ウィンドウ幅に応じて列数が増減するというような内容でした。画像は条件を指定すると、AJAXで条件に応じた画像群を別途取得して、それに差し替え表示するような仕組みがついていました。画像を差し替える際に、画像の位置や増減を表現するためにtop,left,opacity,transformあたりのプロパティをアニメーションさせるように設定してあります。画像が3列や4列のときは意図した動作をするのですが、画像が5列のときだけはなぜかアニメーションが行われず、即時に各プロパティ値が書き換わってしまっているように見えました。

最初はウィンドウ幅毎に処理を変えている部分を疑ってみたのですが、どうもそれは関係なさそうでした。いろいろ試したあげく、アニメーション用の値を設定する前に0.1秒とか短時間、ディレイをつけると意図したアニメーションを確認できるようになりました。これはどうやらAJAXで画像情報を取得した後にそれをDOMに反映させた直後にはtransitionが効かないんじゃないかなって思いました。DOMに追加前のDocumentFragment状態でプロパティ値を変更して、それをDOMに加えてもtransitionによるアニメーションが起こらないことはわかっていたのですが、DOMに追加直後もアニメーションが行えるようになるまでタイムラグがあるのではないかと。

そのタイムラグがあるとして、アニメーションの準備が完了するタイミングを知る方法がわからないので、ちょっぴりディレイするしかないかなって思っていたのですが、今回の件では、アニメーションを発生させる前に画像の読み込みを完了させておく必要があったので、読み込みを待つ処理を追加したら、アニメーションもちゃんと起こるようになって、これでよしとなりました。

2018/3/22

perlのお話。トランザクションのあるデータベース(MyDQLのInnoDB)のハンドラを持っているDBという名前のクラスを作りました。そしてexitが呼ばれて処理が終了し、DBクラスのインスタンスが破棄されるタイミングでデータベース操作をcommitしようとしていました。破棄されるタイミングなので、

sub DESTROY {
# DESTROYの最初の引数には破棄されるインスタンスが渡されるらしい
$_[0]->{dbhandle}->commit();
}

↑こんな感じでいけるのかなと書いたのですが、いざ動かすとデータベースには変更が反映されませんでした。どうもDESTROYが呼ばれる時点でハンドラは既に消えてしまっている模様。
DBIクラス側できっと先に消し込んでいるのでしょう。データベースに接続(connect)する際に何かよいパラメーターを渡すと消されないのかなと思いつつ、都合のよさそうなパラメーターを見つけることができなかったので、

END {
$_->{dbhandle}->commit() foreach (@instanceCollection);
}

DBクラスのインスタンスのコレクションを持っていたので、exitの直前に呼ばれるENDの中で一つずつcommitするように書いたらうまくいきました。これまで意識する必要がなかったけど、ENDが先に呼ばれるんだぁって順番を覚えました。

開発日記