ラベル javascript の投稿を表示しています。 すべての投稿を表示
ラベル javascript の投稿を表示しています。 すべての投稿を表示

2014/11/11

超軽量画像モーダル系jQueryプラグイン

いわゆるLightboxみたいな感じで、

でもいろんな機能とか、派手なアニメーションはいらない。

あとスライドショーもいらない。

ほんっと画像をオーバーレイで表示させるだけ!

っていうか、画像ファイルとか、CSSまで読込みたくない!

そんなシンプルなプラグインを探したけどなかったので作ってみました。

単なる手抜きでもありますが良く言えば軽量!

(function($) {
 $.fn.imgModal = function() {
  $(this).click(function(e) {
   if(navigator.userAgent.match(/msie [6.|7.|8.]/i)) return;
   e.preventDefault();
   var that = this;
   var $loading = $('<div>').text('Loading...').attr('style', 'font-family: Helvetica,Arial; font-size: 17px; color: #eee; text-align: center; position: relative; top: 50%;');
   var $div = $('<div>').attr('style', 'z-index: 100; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,.4); display: none;')
    .on('click', function() { $(this).fadeOut('fast', function(){ $(this).remove() } )})
    .append($loading)
    .appendTo($('body'))
    .fadeIn('fast', function() {
     $('<img>').on('load', function() {
      $(this).fadeIn('slow', function() { $loading.remove() });
     })
     .attr('style', 'max-width : ' + (window.innerWidth - 50) + 'px; max-height: ' + (window.innerHeight - 50) + 'px; width: auto; height: auto; display: none; position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; border-radius: 5px;')
     .attr('src', that.href)
     .appendTo($div)
    });
  });
 };
})(jQuery);

IE8以下は切りました。手抜きです。

画像が大きい場合ウィンドウサイズによって縮小されるので

ブラウザによって少々画像が荒くなります、、

それとイベントの設定にonを使用しているのでjQuery1.7未満ですと動きません!



そんで以下で実行。引数はありません。

単純明快、シンプルに。

$(function() {
 $('a[rel="imgModal"]').imgModal();
});

アンカーのrel属性にimgModalを入れればOK。

<a rel="imgModal" href="http://www.example.com/test.jpg">img</a>

よかったらご利用ください。



DEMO



turunto

2014/09/06

ブログとかのアーカイブの表示方法について考えてみた

長くなってきたブログのアーカイブをどう表示するか?

とりあえず「もっとみる」的なスクリプトを考えてみました。

こんな感じのhtmlで。

<aside id="archives">
 <h3 class="widget-title">Archives</h3>
 <ul>
  <li>2013/12</li>
  <li>2014/1</li>
  <li>2014/2</li>
  <li>2014/3</li>
  <li>2014/4</li>
  <li>2014/5</li>
  <li>2014/6</li>
  <li>2014/7</li>
  <li>2014/8</li>
  <li>2014/9</li>
 </ul>
</aside>

こんな感じのスクリプトを入れる(jQuery使用)

$(function() {
 var $target = $('#archives');
 var count = 1;
 var num = 5;//表示する数
 var l = $target.find('li').length;
 var style = 'display: block; margin: 0 auto; width: 25px; height: 25px; box-shadow: none; cursor: pointer';
 if(num < l) {
  $('#archives li:gt(' + (num - 1) + ')').css('display', 'none');
  $('').attr({ 'src': 'http://example.com/images/arrow.png', 'style': style })
   .appendTo($target)
   .bind('click', function() {
    $('#archives li:lt(' + (num * ++count) + ')').fadeIn(350);
    if(l <= num * count) $(this).remove();
   });
 }
});

もっと見る的なjavascriptがUX的にいけてないとの記事発見。

ページ遷移して、戻ったときに「もっと見る」で開いた部分が元に戻ってる。

確かに。読んで納得。

そんで少し訂正。タブを閉じるまで開いた分をキープ。

var num = 5;//表示する数
var isStorage = false;
try {
 if(typeof sessionStorage['moreCnt'] === 'undefined') sessionStorage['moreCnt'] = 1;
 isStorage = true;
 moreBtn(sessionStorage['moreCnt']);
} catch(e) {
 moreBtn();
}

function moreBtn(count) {
 count = count || 1;
 var $target = $('#archives');
 var l = $target.find('li').length;
 var style = 'display: block; margin: 0 auto; width: 25px; height: 25px; box-shadow: none; cursor: pointer';
 if(num * count < l) {
  $('#archives li:gt(' + (num * count - 1) + ')').css('display', 'none');
  $('').attr({ 'src': 'http://example.com/images/arrow.png', 'style': style })
   .appendTo($target)
   .bind('click', function() {
    $('#archives li:lt(' + (num * ++count) + ')').fadeIn(350);
    if(isStorage) sessionStorage['moreCnt'] = count;
    if(l <= num * count) $(this).remove();
   });
 }
};

なんかコードがすっきりしませんが、、、

一応DEMO



今後は小ネタを遠慮なく書いていこうと思います。

2014/04/25

websocketを使ってみて感動した件


なぜにwebsocket


ふと、サーバー側からクライアントへどーにかデータ送信ってできないか??

と思うことがり、そんなような内容をググってみたところ。

ポーリングということばに出会いました。

そこが今回の始まりです。

知りませんでしたぽーりんぐという言葉。

そんでちゃちゃっと自分で調べた感じ、

javascriptにおけるポーリングとはF5又はXHR連打。

ロングポーリングとはXHRでデータ送信、

サーバ側でぐるぐる待つ。

変更があればクライアントに戻す。

かなり斜め読みのざっくり把握です。

コメットなる言葉も出てきましたがロングポーリングと

似たようなもの、ということみたい。

CometとAjaxを利用したチャットサーバの実装

こちらのサイトがわかりやすかったです。

まぁ結局のところ当たり前かも知れませんが、

クライアントからサーバへ問い合わせないと始まらんよ、と。

しかし、まぁ見てのとおりサーバーの負担が気になるところです。

よくチャット禁止とか書かれているレンタルサーバーはこういうことっだのでしょうか?

そしてwebsocketなる技術はそんなサーバーの負担を和らげてくれる技術らしい。

まぁ難しいんでしょうね~と、思いながらもちょっとググってみる。

websocketはnode.jsというもので実装されている方が多いようでした。

聞いたことはあるがイマイチなぞなnode.js。

唯一かろうじて雰囲気はわかるPHPでどーにかできないもんか。

ありました、完璧に教えてくださるサイト様が。

PHPでWebSocket

同時にお絵かき。魅力的です。

早速試してみることに。

簡単!


といってもPHPでWebSocketこちらのブログのおかげですが、、、

今回とりあえず動かす!!という目標なのでXAMPP環境でチャレンジです。

サーバサイドはphp-websocketこちらのライブラリを

ダウンロードしてまんま使わせいただきました。

ドメイン部分だけ書き換えをしたらあっさりとdemo起動。

PC、iPhoneで問題なくつながりました!

そしてこのながながとひっぱていながら全くアクセスのない

お絵かきアプリPaint!をカスタムです。

大抵この手の未知なことをはじめるとどつぼにはまるのですが、

以外にもスムーズに。

クライアント側


は、とりあえずpaintとというオブジェクトを作成して、そのオブジェクトに

カラー情報やらタッチの位置やら様々な描く情報を入れているのですが、

今回はタッチ系のイベントごとにこのpaintオブジェクトのプロパティの一部をJSONして

データを送信するという感じにしました。

そんでこのオブジェクトを通常のタッチによるcanvasへの書込み用と

websocketから来るプロパティをコピーして同じくcanvasに書き込むようの

2つのオブジェクトを作成して使用してみました。

マルチタッチとかになるとさすがに重いのかなぁとか思ったんですが意外にも

軽快に動いてこれまた感動。

そんで参加時に任意の文字で参加グループを選べるように設定。

ただ新たに端末が加わった際は同じグループ内の任意の端末からcanvasデータをbase64して送信、

その他の端末はそれを読み込み、ということをしたんですが、

写真だと重くて結構な遅延が生じてしまいました。

試してませんがbase64でやりとりよりWebSocket の導入: ウェブにソケットを実装する

みたいにバイナリデータの方が早そう気が、、、わかりませんが。

そんで今回iPhone5c2台とHTCAndroidで通信してみました↓



予想以上な軽快な動きです。感動です。

ここでひとつ思ったなのですが、Androidは今までcanvasの性能が(iPhoneに比べて)イマイチなんかなぁ

と思ってたんですが、意外と位置情報から書き込むと結構スムーズな気がしました。

なんでこのはがゆさはタッチの反応の問題?

いつかサーバサイドの理解が深まったらこんな技術も入れてみたいもんです。

少しでもきになった方、よかったらこの

ウェブアプリをホーム画面への追加よろしくお願いします。

Paint!

サーバーが不安定気味でチョイチョイアクセス出来ないことがありますが、

それとwebsocketは試せませんが、、、

ちなみにあんまり関係ないのですが、new Image()した要素を入れたプロパティを

一生懸命JSON.stringifyしようとして

TypeError: Converting circular structure to JSON

と怒られまくってしまいました。循環参照???って思ったんですが、

確かにDOMをそのままJSONっておかしいよなと原因わかって納得。

まとめ


すごい技術があるもんだ。

2014/02/12

動的に追加される要素にイベントを登録する



なぜこんな記事を書いたのか。

前回のhandleEventってなんかよさそうこの記事書いてて

思い出したついでです。

<html>
<head>
<body>
<button id="add">追加</button>
<ul id="listUL">
<li>list1<button class="remove">削除</button></li>
</ul>
このリストは動的に追加され、削除ボタンでそのリストを削除したい場合。

add.addEventListener('click', function() {
  var listLength = document.getElementsByClassName('remove').length;
  var list = '
  • list' + (listLength + 1) + '
  • '; listUL.innerHTML += list; }); listUL.addEventListener('click', function(e) { //親がイベントを監視し、伝播するイベントをキャッチし発生元の親listを削除する //親が上の要素にいけば行くほど(広く監視するほど)無駄なイベント捕捉が増える??と思われる if(e.target.className === 'remove') { this.removeChild(e.target.parentNode); //ここのthisはリスナが登録されたlistULを指す //thisは e.currentTarget、e.targetはクリックされた要素 } });
    ちなみに動的な要素もそうだけど、大量のリストにイベント設定するときとかもforで回すして

    全ての要素に登録するより、親に1つ登録してe.targetを監視した方がよいのかしら??

    以前、ふとどーやってあとから追加された要素にイベント登録するんだろーって思って、

    ググったところjQueryのliveとかonとか出てくるんですよね。

    まぁみなさんその情報を求めているんでしょう。

    がしかしここ最近なぜかjQueryをあまり使わなくって。

    そんで調べてなるほど!

    うーん、

    参考

    jQueryのliveやdelegateは実際何をやってるのか

    handleEventってなんか良さそう



    知りませんでしたhandleEventという存在。

    すごい的を得ていないポストなのでhandleEventで検索してきてしまった方すいません。

    そんで久しぶりに恥かしながらコードを載せてみよう!

    と思ったのでSyntax Highlighter導入してみました!

    handleEventでググるとまず

    handleEventをメソッドとして持ったオブジェクトも渡すことが出来る。

    そんな説明に出会います。

    いまいちピンとこないのでいろいろサンプルを拾って試してみる。

    まずはどこかで見たhandleEventサンプルです。

    
    

    これがthisで呼べるのはおそらくhandleEventを持った(設定した)

    windowオブジェクトを渡してるってことですよね?

    そんで次

    var handler = {
     handleEvent: function(e) {
      //イベントの共通処理
      e.preventDefault();
      switch(e.type) {
       case 'mousedown':
        this.x = e.clientX;
        this.y = e.clientY;
       break;
       case 'mouseup':
        console.log(this.x, this.y);
       break;
      }
      console.log(this);//thisはhandlerオブジェクト
     },
     x: null,
     y: null
    };
    window.addEventListener('mousedown', handler);
    window.addEventListener('mouseup', handler);
    

    これはhandleEvent関数を持ったオブジェクトを作ってそのオブジェクトを渡すと。

    用は第二引数は関数ではなくオブジェクトを渡す。

    こんなサンプルをまぁいじりながら考える。

    なんか昔コンストラクタ内でのaddEventListenerって調子よくないなぁ。

    普通はコンストラクタ内には書かんのかなぁみたいなことを思った気が、、、。

    そんでなんかこれ使えば汎用的な部品が書けるのでは?

    そんで次、とりあえずなんかマウスやタッチの位置を取得して

    ごにょごにょするようなサンプルです。

    少し長いんで気をつけて下さい!!

    var Point = function(elem) {
     this.elem = elem;
     this.isTouch = 'ontouchstart' in window;
     this.start = this.isTouch ? 'touchstart' : 'mousedown';
     this.move = this.isTouch ? 'touchmove' : 'mousemove';
     this.end = this.isTouch ? 'touchend' : 'mouseup';
     this.flag = false;
     this.x = null;
     this.y = null;
     this.elem.addEventListener(this.start, this);
     this.elem.addEventListener(this.move, this);
     this.elem.addEventListener(this.end, this);
    };
    Point.prototype.handleEvent = function(e) {
     //イベントの共通処理
     e.preventDefault();
     this.x = this.isTouch ? e.touches[0].clientX : e.clientX;
     this.y = this.isTouch ? e.touches[0].clientY : e.clientY;
     switch(e.type) {
      case this.start:
       this.flag = true;
       //console.log(this.start);
      break;
      case this.move:
       //console.log(this.move);
      break;
      case this.end:
       this.flag = false;
       //console.log(this.end);
      break;
     }
     //console.log(e, this);
    };
    Point.prototype.addEvent = function(type, listener, useCapture) {
     this.elem.addEventListener(type, listener, !!useCapture);
    };
    Point.prototype.removeEvent = function(type, listener, useCapture) {
     this.elem.removeEventListener(type, listener, !!useCapture);
    };
    
    var img = new Image();
    img.src = 'https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmmbRH59pMVYYu_tAfyZnhzs8MB3cFUVnE1dUbcC8xhPDVanWeRoJvtZLjOLeqTv8KOuOhMsbJH_jvagdNV3y5keMDd5Z908xKsk5Fuhe0MluWgKAVy4v9zhq2AFPwjsUwFraeK9xuCuQ/s144/cursol_img.png';
    img.setAttribute('style', 'position:absolute;display:none;');
    img.onload = function() {
     img.centerX = img.width / 2;
     img.centerY = img.height / 2;
    };
    var canvasElem = document.body;
    var point = new Point(canvasElem);
    canvasElem.appendChild(img);
    point.addEvent(point.start, function() {
     img.style.left = (point.x - img.centerX) + 'px';
     img.style.top = (point.y - img.centerY) + 'px';
     img.style.display = 'block';
    });
    point.addEvent(point.move, function(e) {
     if(!point.flag) return;
     img.style.left = (point.x - img.centerX) + 'px';
     img.style.top = (point.y - img.centerY) + 'px';
     if(point.y > 500) point.removeEvent(e.type, point);//handleEventを削除
     if(point.x > 500) point.removeEvent(e.type, arguments.callee);//実行中の追加イベントを削除
    });
    point.addEvent(point.end, function() {
     img.style.display = 'none';
    });
    

    なんかこんなようなことを以前書きたいと思ったような、思わなかったような、、、。

    でもなんか違うような。はい、曖昧な意味不明な記事です。

    いつかこれを読み返して、これこうじゃなくて、こうじゃない?

    みたいな思いつきを期待したいです。

    なんかhandleEventのうまい書き方。誰か教えて。