日々学んだことを残しておこう。きっと未来の自分が探しにくる。 (ただ忘れっぽいだけです…)

Spry × jQuery SmartImage はまったところ メモ



Today's latte, jQuery. / yukop


スマートフォンサイトに用意した画像を拡大・縮小、移動したいっと思っていろいろ調べたら、jQueryライブラリのjQuery SmartImageを発見。

デモを見て、まさに実現したかったことでした。

さらに、私がやりたかったのは、非同期で取得した複数の画像を重ね合わせて、全体を拡大・縮小みたいにすることでした。

ライブラリ作者の方も非常に親切にいろいろ教えてくださいました。


カスタマイズしたところ


①セレクタのClass指定
各imgタグのclassをsmart-imageになるようにする。
こんな感じでテストしたらOKでした。
	<div id="wrap">		
<img src="images/img1.png" alt="" class="smart-image">
<img src="images/img2.png" alt="" class="smart-image">
</div>



②タグの確認+div名指定
SpryのXMLデータセットで画像のパス情報のxmlファイルを非同期で取得していました。
spry:repeatを使っていたので、imgタグdivタグが入れ子みたいに自動作成されていました。
ライブラリにtarget.parent().height();などimgタグの親要素を指定しているのですが、その部分がちゃんとセットできていないことが判明。
divタグにphotosとid付けて、target.parent()部分を変更しました。
$("#photos").height();

	<div id="photos">
<div>
<img src="images/img1.png" alt="" class="smart-image">
</div>
<div>
<img src="images/img2.png" alt="" class="smart-image">
</div>
</div>



③ライブラリの呼び出し 領域オブザーバ通知関数の使用
   		//領域オブザーバ通知関数
function myObserverFunc(notificationType, notifier, data) {
window.console.log(notificationType);
if(notificationType == "onPostUpdate"){
//ここに処理
}
};
Spry.Data.Region.addObserver("photos", myObserverFunc);


画像が最初から用意されている場合、ページロード後にSmartImage関数を呼べば良いのですが、今回非同期で画像パスを読み込むので、読み込み後にSmartImage関数を呼び出す必要があります。
というのも、SmartImage関数で画像のheight、widthやコンテナのheight、widthを使用しているからです。
Spryのxmlデータセットには、領域オブザーバ通知関数というのが用意されています。

(参考サイト)
オブザーバー通知の使用
領域オブザーバー通知

※20121028追記
最初、上のオブザーバー通知の使用でやっていてうまくいっていなかったのですが、creatorishさんがこのケースでは、領域オブザーバー通知の方を使用することを教えてくれました。


それを使って、xml取得したイベントでSmartImage関数を呼んでもうまく変数が取れていない。。。
やはり、画像の読み込まれる前に関数呼んでいるのが良くないみたい。


④setTimeoutをかます
ちょっと時間たってから(0.5秒後)SmartImage関数を呼ぶようにしたら、一応うまくできたんだけど、これって通信の関係や端末環境によってオーバーするかもしれないし、時間の設定をどうすればよいんだろ。悩む。


⑤setTimeoutのうまい使い方
ちょうど、悩んでいるときに朗報。こんな勉強会が。
名古屋JSクリニック Vol.1
講師の張山さんがみんなのJavascriptの悩みを解決してくれるって勉強会。
早速、申し込んで昨日受講してきました。
ポイントは以下の通り。
・imageオブジェクトを作成(配列)
・画像が読み込み完了かチェックするcompleteプロパティで読み込み完了した画像枚数をチェック
・全画像枚数でなければ、ちょっと待って再度チェック開始。全画像枚数なら、SmartImage関数を呼ぶ。

というようにすれば良いとのこと。すごい、本当に解決してくれた。
クリニック万歳。

ということで、ちょっとソース書いてしておきます。

    <div id="photos" spry:region="dsPhotos">
<div spry:repeat="dsPhotos">
<img alt="" src="{dsPhotos::source}" style="position:absolute;opacity:{dsPhotos::alpha};" class="smart-image" />
</div>
</div>
<script type="text/javascript" src="js/jquery.smartimage.js"></script>
<script>
//Spryのxmlデータセット(非同期で取得)本当はここがいろいろなプルダウンによって決定。テスト用に、固定値
var dsPhotos = new Spry.Data.XMLDataSet("test.xml","test/img");

var imgs = [];

// XML読み込み完了時に実行する関数
function setImage(){

console.log("setImage");

var i;
var rows = dsPhotos.getData();
console.log(rows.length);

for(i=0; i<rows.length; i++){
imgs[i] = new Image();
imgs[i].src = rows[i].source;
}

// 画像をHTMLに反映する処理
checkLoad();
}

// 画像読み込み完了をチェックする関数
function checkLoad(){

console.log("checkLoad");

var count = 0;
for(var i=0; i<imgs.length; i++){
count += imgs[i].complete;
}
if(count == imgs.length){
$(".smart-image").SmartImage({
fill: true,
zoomInController: ".zoomin",
zoomOutController: ".zoomout",
moveLeftController: ".moveleft",
moveRightController: ".moveright",
moveUpController: ".moveup",
moveDownController: ".movedown",
complete: function(elm,functions) {}
});
} else {
setTimeout(checkLoad, 250);
}
}

//領域オブザーバ通知関数
function myObserverFunc(notificationType, notifier, data) {
window.console.log(notificationType);
if(notificationType == "onPostUpdate"){
setImage();
}
};
Spry.Data.Region.addObserver("photos", myObserverFunc);
</script>



感想


console.logでcheckLoadの呼び出し回数を見ると、setTimeoutを250ミリ秒にした場合、2回くらい目でライブラリの呼び出しになっていました。(もちろん、データ量、通信環境にもよってきますが)

Spryのxmlデータセットあたりは↓サイト見るとどのようにセットしているか分かると思います。

(参考サイト)
Ajaxフレームワーク「Spry」で作る「リンク集2.0」

講師の張山さん曰く、XML取得の部分もjQueryにした方が良いのではとのことでした。
jsonだとjQueryで簡単に取得できそうだったけど、xmlはSpryの方が簡単かなということでこんな作りにしちゃったんだけど、jQueryでも簡単にできるそうですね。

なんか、Spryプロジェクト終了したみたいですね。。。
2012年8月、他のWebフレームワークが大きく進歩したこともあり、Adobe社は今後のプロジェクトへの投資を停止した。
http://ja.wikipedia.org/wiki/Spry

今回、xmlの取得部分だけSpry使ったのですが、時間作って、この部分もjQueryで作成してみよっと。

それにしても、なんとかうまく動いて良かった。
いろいろ参考になる情報いただいた方に感謝です。

それにしても、jQuery SmartImageライブラリはすごく良い!


**** 追記20121028 ***************

setTimeoutを使わない手法 by creatorish


領域オブザーバ通知を使用していなかったため、たまに挙動がおかしかったので、色々creatorishさんが教えてくれて、setTimeoutを使わない手法も分かりました。

領域オブザーバ通知を使用すれば上の書き方でも問題と思いますが、両方のせておきます。

最初、記事タイトル名を「jQuery SmartImage はまったところ メモ」にしていたんですが、どちらかというと、jQueryライブラリにはまったというかSpryにはまったという感じだったので、「Spry × jQuery SmartImage はまったところ メモ」に変えましたwww

<div id="photos" spry:region="dsPhotos">
<div spry:repeat="dsPhotos">
<img alt="" src="{dsPhotos::source}" width="{dsPhotos::p_width}" height="{dsPhotos::p_height}" style="position:absolute;opacity:{dsPhotos::alpha};" class="smart-image" />
</div>
</div>
<script type="text/javascript" src="js/jquery.smartimage.js"></script>
<script>
//Spryのxmlデータセット(非同期で取得)本当はここがいろいろなプルダウンによって決定。テスト用に、固定値
var dsPhotos = new Spry.Data.XMLDataSet("test.xml","test/img");

var imgs = [];

// XML読み込み完了時に実行する関数
function setImage(data){
var loaded = 0;
var rows = dsPhotos.getData();
//smart-imageクラスが付いたものにloadイベントを付与
$(".smart-image").load(function() {
//読み込み完了数を+1
++loaded;
//データの数と比較して同じならばSmartImage実行
if(loaded === rows.length) {
//読み込み完了後の処理
$(".smart-image").SmartImage({
fill: true,
zoomInController: ".zoomin",
zoomOutController: ".zoomout",
moveLeftController: ".moveleft",
moveRightController: ".moveright",
moveUpController: ".moveup",
moveDownController: ".movedown",
complete: function(elm,functions) {}
});
}
});
}


//領域オブザーバ通知関数
function myObserverFunc(notificationType, notifier, data) {
window.console.log(notificationType);
if(notificationType == "onPostUpdate"){
setImage();
}
};
Spry.Data.Region.addObserver("photos", myObserverFunc);

</script>
関連記事

2012-10-26 : JavaScript : コメント : 6 : トラックバック : 0
Pagetop
コメントの投稿
非公開コメント

イベントオブザーバーの記述
Twitterではお世話になっております。
SmartImageの制作者です。

気になる部分がありましたので、コメントさせていただきます。
Spryをあまり理解していないので、検討外れかもしれませんがその場合は削除しちゃってください。

「③ライブラリの呼び出し オブザーバ通知関数の使用」ですが、これはjQueryのイベントでDOMの読み込みが完了したときに発生するものなので、SpryでXML読み込んで要素を表示するのとはタイミングにズレが生じると思います。
Spryでは以下のリンクにあるようなオブザーバーを使うのではないかと。
http://livedocs.adobe.com/ja_JP/Spry/1.4/help.html?content=WS6C9E8F29-71AB-4b76-9618-C8A8A829B950.html

もし、画像サイズがすべて統一されているようでしたらimgタグにwidthとheight属性を足して明示的にサイズ指定してあげると動作すると思います。

何かの参考になれば幸いです。
2012-10-26 16:36 : creatorish.yuu URL : 編集
Re: イベントオブザーバーの記述
お世話になります。
一応、指定されたurlの3番目の「オブザーバーとしての関数」というのを使っています。jQueryと同じなんですか?
onPreLoad、onPostLoad、onDataChangedの3つのイベントが発生して、一番最後にonDataChangedが発生するので、そのときに処理するようにしました。

先ほどテストではうまくいって、気持ちが高ぶったままブログ記事書いていたんですが、今、最終系にしたら、imgのwidthが取れなくなっていることが判明して、ちょっと凹んでたところです。

画像サイズはイベントごとに異なるものを取得しますが、一度に取得する画像はどれもサイズは同じです。

ご指摘されたようにimgタグに足してトライしてみます。
2012-10-26 16:48 : のりのりたかのり URL : 編集
Re: イベントオブザーバーの記述
すみません。
説明された意味分かりました。

あのコードはデフォルトはjQueryのロード後になっているという、修正前の記述でした。
誤解されないように消しておきました。

サンプルソースの一番下にあるように、Spryのオブザーバー使っています。
2012-10-26 16:53 : のりのりたかのり URL : 編集
Re: Re: イベントオブザーバーの記述
リファレンス見た限り、onPostLoadの方が良さそうなので、変更しました。
2012-10-26 17:00 : のりのりたかのり URL : 編集
勘違いしていました
ソースの一番下、確かにそうなっていますね。
完全に見落としていました。すいません。

画像のサイズが明示的に記述されれば画像が読み込み完了かどうかの確認は必要なくなると思いますので、
width="{dsPhotos::width} height="{dsPhotos::height}とできるならいけるかもしれません・・・。
2012-10-26 19:32 : creatorish.yuu URL : 編集
Re: 勘違いしていました
あの後、迷ったあたりを追記しました。
一応動きましたが、なぜダメだったかスッキリしませんが、
いろいろ助言くださり、本当にありがとうございました。
2012-10-26 22:54 : のりのりたかのり URL : 編集
Pagetop
« next  ホーム  prev »

広告

読みたいと思っている書籍

Amazon Web Services クラウドネイティブ・アプリケーション開発技法 一番大切な知識と技術が身につく Amazon Web Services 定番業務システム12パターン 設計ガイド イラストで学ぶ 機械学習 最小二乗法による識別モデル学習を中心に (KS情報科学専門書) イラストで学ぶ ディープラーニング (KS情報科学専門書)

カウンタ

メールフォーム

名前:
メール:
件名:
本文:

GoogleTranslate

管理人のつぶやき

人気記事ランキング

カテゴリ

openclose

ブログ内検索

全記事表示リンク

全ての記事を表示する

ブログパーツ