2014年11月21日金曜日

jQueryを使って"ページの先頭に戻る"ボタンを作る

最近よくあるアニメーションに、下のほうまで行くと"TOP"みたいなボタンがあって、それを押すとページの先頭まで自動でスクロールする、というものがありますよね。

あれをjQueryを使って実装する場合、animateメソッドを使います。おおざっぱな実装ではこんな感じです。
$('#back_to_top').hide();
$(window).scroll(function(){
    if($(this).scrollTop() > 1000){
        $('#back_to_top').fadeIn();
    }else{
        $('#back_to_top').fadeOut();
    }
});
$('#back_to_top a').click(function(){
    $('body').animate({
        scrollTop: 0
    }, 400);
    return false;
});

ボタンのIDはback_to_topです。まずはscrollTopで現在のy軸座標を取得します。それに合わせて適当にshowやhideでボタンを表示します。

今回の前提としては、ボタンのpositionをfixedで指定しておき、画面読み込み時にはhideメソッドで隠しておく感じですね。そして適当にピクセル分スクロールダウンしたら、fadeInでふわっと表示させます。もちろん単純にshowでも構いません。

さて、UIに関することはこれくらいにして、とにかくポイントはanimateメソッドを使うことです。これは四角形なんかを変形させるときにも使えます。

scrollTopではなく、heightやwidthに値を指定しておくだけですね。

あとは第二引数で変化時間を設定しておけば、オリジナルのアニメーションを実装できるという具合です。もう少し複雑な引数もあるのですが、基本はこれだけです。

animateメソッドは簡単なアニメーションを手早く実装できるので、ぜひ使いこなしたい機能です。

2014年11月16日日曜日

File Dialogのボタンデザインを変更する

ローカルのデータを読み込む際に使用するFile Dialogですが、そのまま利用するとデザインを変更できません。

そこで、まずはそのダイアログを隠してしまい、別のボタンをクリックしたときのイベント内部で呼び出すことにします。仮のボタンを作ってしまい、それを加工するということですね。

今回は好きな画像イメージを表示するソースです。縦長と横長の写真が見栄え良く並ぶように、画像のサイズは適当に調整していますが、実際には画像ファイルであるかといった判定が必要になると思います。


jQuery File Dialog

<!DOCTYPE html>

<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>jQuery File Dialog</title>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <style>
            #file_dialog_field{
                height: 30px;
                width: 100%;
                margin-bottom: 20px;
            }
            #file_button{
                margin-left: 2px;
                width: 140px;
                font-size: 14px;
                font-family: Verdana, sans-serif;
                border-radius: 15px;
                background-color: rgba(207,247,94,0.8);
            }
            #file_text{
                width: 160px;
                background-color: rgba(207,247,94,0.2);
            }
            #file_show_area img{
                margin-right: 10px;
                margin-bottom: 10px;
            }
        </style>
    </head>
    <body>
        <!-- Not show file dialog. This is called in jQuery button function. -->
        <input id="file_dialog" style="display: none;" type="file">

        <div id="file_dialog_field">
            <input id="file_text" type="text" readonly="readonly" placeholder="Select your image"></input>
            <button id="file_button">Open your file</button>
        </div>
        <div id="file_show_area"></div>
        <script>
            $(function () {
                $('#file_button,#file_text').click(function(){
                    $('#file_dialog').click();
                });
                $('#file_dialog').change(function(){
                    var file = $('#file_dialog')[0].files[0];

                    var title = file.name;
                    $('#file_text').val(title);

                    var reader = new FileReader();
                    reader.readAsDataURL(file);
                    //at the moment reader is ready
                    reader.onload = function(e) {

                        var img = new Image();
                        img.src = reader.result;

                        //ignore resizing small images. 
                        if (!(img.width < 150)){
                            //Get pictures appear well-balanced.
                            if (img.width > img.height){
                                img.width = 300;
                            }else{
                                img.height = 240;
                            }
                        }

                        $('#file_show_area').append(img);
                    }
                });
            });
        </script>
    </body>
</html>

2014年11月14日金曜日

ウェブデザインことはじめ

日頃デザインを行う際のポイントをまとめてみました。

どれも市販のデザインガイドを開けば載っているような当たり前のことですが、自分の言葉でも文章化しておきたいと思います。


レイアウト


①空間に基準線を意識して、ウィジェットや文字を配置します。
基準線は直線であったり、四角形であったりします。


②同族性のものはまとめます。これを一つのグループと考えます。これらのグループを、基準線に沿って土台(ページ)に配置します。
グリッド構造をイメージすると分かりやすいかもしれません。グループ内でも基準線を意識して見やすさを重視します。


③グループ間の距離をある程度、等間隔でとりながら、それらを反復することで統一感を出します。


④情報の優先度に従って、グループやウィジェットに差異をつけましょう。大きさや濃淡、文字の太さなどで表現可能です。


⑤視線の動きを表した、いわゆるZ線に沿った配置も心掛けなくてはいけませんね。


配色


①用意する色を三種類とした場合、割合は以下のようになります。

ベース: メイン: アクセント = 7: 2.5: 0.5

背景色(ベースカラー)、ボタンや文字などによるメインコンテンツへの誘導(メインカラー)、特売情報、新規情報、特典やサービスなど特に印象を与えたい部分(アクセントカラー)といった具合です。

色の選択は、ベースとメインは概ね彩度で区別したりするのが簡単です。濃い紫をメインカラーにして、透明感のある薄い青紫をベース、といった感じですね。

ちょっと変えたいな、という時は色相を入れ替えてみたりします。


②三種類は少ない! という時には、色を足します。ベースやメインのカラーを分割してみます。ただし、各コンテンツに対する使用の比率を変更してはいけません。

基本はトーン(色の強弱:彩度と明度で変化。brightness and darknessと書いた方が分かりやすかもしれません)と色相(いわゆる色)のどちらかを入れ替えることで対応します。

両方変えてしまうとたいていは違和感が出てしまいますね。。。なんだかチグハグな配色だなぁと感じる一番の原因かもしれません。


③アクセントはいわゆる補色を使ったりします。強い赤色に対するのは、目に痛いくらいの黄緑といった風に、機械的に決めることが出来ます。


まとめ


どれもデザインの基本ではありますが、独自のデザインを施すうえでも、基本からどこまでずらして良いのか、が一つの基準になると思います。

ただ、一番大切なのは、ウェブデザインはアートではなくて結局プロダクトデザインだよね、と忘れないことなのかもしれません。

jQueryのプラグインの力を借りてギャラリーを回して、インデックスは思いっきりパララックスでインパクト重視。。。なんて最近のブラウザなら派手に動かそうと思えばいくらでもできちゃうんですけれど、結局使う人が使いやすいかというUXの視点を忘れちゃいけないんですよね。

具体的な方法論というよりは心構えみたいなものですが、ふと迷った時にはいつでもここに帰ってこれるようにしておきたいと改めて思いました。

2014年11月13日木曜日

AngularJsを使ってみる―Serviceの利用―

Serviceの基本的な使い方です。組み込みのHttp通信機能を利用してみます。

AngularJsでJSonデータを外部から参照する方法です。
ここには、built-inのServiceを利用します。

Serviceというのは、あまり悩まず便利なAPIをまとめた機能と覚えておけば十分使えると思います。

内部ではJQueryの機能を利用しているようです。コントローラの引数の中で$httpの利用を宣言すると、injectorというAngularJsの機能が自動的に判別して、コントローラに差し込んでくれます。

引数の形式は少し特殊で、arrayをコントローラの引数に設定し、その内部でまず文字列として使用するサービスを宣言します。そして、そのサービスを無名関数の引数に設定します。

また、JSonデータは自動的にJavaScriptのArray形式に変換されます。具体的には以下のように書きます。

ここではPromiseを利用しており、通信成功時にはsucces以下がコールバックされて実行されます。ちなみに失敗時の動作はerrorという関数を追加します。

app.controller('SomeController', ['$http', function($http){
    var store = this;
    store.jsonData = [];
    $http.get('/store-json-data.json').success(function(data){ 
      store.jsonData = data;
    });
}]);

AngularJsを使ってみる―Directiveの分割―

別のモジュールを作って、Directiveを分割してみます。

前提:表示する大本のページを"index.html"、読み込むAngularソースを"sampel-app.js"、新しく作成するモジュールを含んだソースを"new-sample-app.js"であるとします。

①new-sample-app.jsに、次のような新しいモジュールを記述します。

(function() {
  angular.module("new-sample-app", [])
  
  .directive("productDescription", function() {
    return {
      restrict: 'E',
      templateUrl: "something.html"
    };
  });
 })();

②sampl-app.jsに、依存関係を追加します。依存関係がない場合は空白にしていた部分ですが、今回は新しいモジュール名を追加しておきます。

angular.module('sample-app', ["new-sample-app"])
・・・

③index.htmlのヘッダー内で、new-sample-app.jsを読み込みます。htmlタグ内で読み込んでいたng-appの指定を変更する必要はありません。

今回であれば、<html ng-app="sample-app">となっているはずです。

<head>
  <script type="text/javascript" src="angular.min.js"></script>
  <script type="text/javascript" src="sample-app.js"></script>
  <script type="text/javascript" src="new-sample-app.js"></script>
</head>

AngularJsを使ってみる―独自のDirectiveを作る―

今回は独自のDirectiveを作成します。

前提:
表示する大本のページを"index.html"、読み込むAngularソースを"sampleAngular-app.js"であるとします。また、"sampleAngular-app.js"が適用されるソースは"sample.html"です。

①AngularJsの記法で書かれた、sample.htmlファイルを用意します。
このソースを、index.htmlに埋め込む形になります。

②sampleAngular-app.jsに、次のようなDirectiveを作成します。

app.directive("sampleDirective", function() {
    return {
      restrict: 'E', //E is Element, A is attribute.
      templateUrl: "sample.html"
    };
});

③作成したDirectiveを、index.htmlに埋め込みます。埋め込み方は、restrictの設定値によって微妙に変わります。

A(attribute)の場合:

<sample-directive></sample-directive>

E(element)の場合:

<div sample-directive>

また、次のように書くことで、sample.htmlをコントローラで囲っている状態が得られます。

app.directive("sampleDirective", function() {
    return {
      restrict: 'E', //E is Element, A is attribute.
      templateUrl: "sample.html",
      controller: function(){
            //parameters and functions are here.
      },
      controllerAs: sample //You can also put alias
    };
});

2014年11月12日水曜日

AngularJsを使ってみる―Form編―

値の判定機能を持った、基本的なフォーム操作のサンプルです。

何らかのプレヴュー画面があって、値を入力すると動的に反映されますが、サブミットしないとDBなどには追加されません。

イメージとしては、ng-repeatで回ってきているproductを引数にとって、そこにpushなんかでreviewを追加する感じですね。それをDB向けに加工するための関数なんかに回すとすっきりしそうです。

フォーム作成時に、novalidateでまずはデフォルトのバリデーション設定を解除しておきます。
また、$validという値を使うと簡単に現在の状態が取得できるので、ボタンの有効化などを設定できます。

<!--  Review Form -->
<!-- $valid is only true when all "required" and formats are valid. -->
<form name="reviewForm" ng-controller="ReviewCtrl" 
    ng-submit="reviewForm.$valid && addReview(product)" novalidate>

  <!--  Live Preview -->
  <blockquote >
      <strong>{{stars}} Stars</strong>
      {{body}}
      <cite class="clearfix">{{author}}</cite>
  </blockquote>

  <!--  Review Form -->
  <h4>Submit a Review</h4>
  <fieldset>
        <select ng-model="stars" ng-options="stars for stars in [5,4,3,2,1]" title="Stars" required>
            Rate the Product
        </select>
    </fieldset>
    <fieldset>
        <textarea ng-model="body" placeholder="Write a short review of the product..." title="Review"></textarea>
    </fieldset>
    <fieldset>
        <input ng-model="author" type="email" placeholder="example@example.com" title="Email" required />
    </fieldset>
    <fieldset class="form-group">
        <input type="submit" value="Submit Review"/>
    </fieldset>
</form>

ちなみに、入力中に値がエラーである場合に背景を赤にしたい、といった場合はCSSに次のように書きます。
invalidだけだと、ページを開いた時から赤くなってしまうためです。

.ng-invalid.ng-dirty{
    background-color: red;
}

また、モデル内でURLを指定している画像の読み込み時にも注意が必要です。ng-srcタグを使わないと、読み込みの順序の関係で失敗します。

<img ng-src={{product.image}}/>

AngularJsを使ってみる―基本編―

最近注目のAngularJsをちょっとずつ触っていきたいと思います。

よくJavaScriptにおけるMVCモデル、といった表現がされますが、単純に使うだけならテンプレートエンジンとして理解するのがお手軽に恩恵を受けられる使い方だと思います。

レヴュー画面での入力や、ユーザ情報の登録などをさくっと作ったり、インタラクティブな情報のやり取りを短時間で書けてしまいます。AjaxもOKなので、上手く使えば通信量の節約にもなりますね。

Google肝いりのプロジェクトなだけあって、公式サイトの充実度も抜群です。今後はまずJQueryとAngularJsを抑えているというのが、JavaScript書きの標準になっていく可能性があります。

とりあえず相互バインドの基本と、コントローラを使ったサンプルです。

基本的な書き方は、ng-***という名前で指定した要素をHTMLタグ内に書き込みます。

JavaScriptで作ったAngularモジュールを、まずはhtmlタグ内で読み込んでいますが、これが全てを通した基本の形となります。

JavaScriptで扱うデータ構造(M:モデル)を、コントローラ要素で制御(C:コントローラ)して、HTML(V:ビュー)に反映する形であってるでしょうか。なにはともあれ、分業しやすくて良いですね。

JavaScript内で注目すべきものは、$scope変数でしょうか。これ、this.xxx = ...... といった形で書いても基本的に上手く動きます。

ただそうすると、HTML内でコントローラを呼び出した後に、aliasを指定してそれを変数名のように使って。。。という作業が発生します。そのため最近は$scopeの使用が一般的なようです。


<!DOCTYPE html>
<html lang="ja" ng-app="angular-app">
<head>
    <meta charset="utf-8">
    <title>AngularJs</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
</head>
<body>
    <!-- Simple interactive directive example. You use ng-model. -->
    <input type="text" ng-model="input" placeholder="input anything">
    <p>You are writing: {{input}}</p>
    <!-- Simple controller example. $scope helps not to use 'as ***' -->
    <div ng-controller="SampleController">
        <div ng-repeat = "item in items">
            <b>{{item.name}}</b>: {{item.color}}
        </div>
    </div>
    <script>
        //create an angular module. This is called in html tag.
        angular.module('angular-app',[])
            .controller('SampleController', function($scope){
                $scope.items = [
                    {
                        name: "item1",
                        color: "red"
                    }, 
                    {
                        name: "item2",
                        color: "blue"
                    }
                ];
            });
    </script>
</body>
</html>

2014年11月11日火曜日

JQuery UIを使ってみる―Tabs編―

よくメニューバーとして使われるタブ要素ですが、それを簡単に作れるのがtabsです。

まずタブの枠全体のidを作成します。その中に、タイトル部分をulで作り、要素をdivで作ります。そしてこれらをdiv要素のidを利用してリンクさせておきます。

あとはいつも通りJQuery UIでtabsに指定してあげれば、半自動的にメニューバーが出来上がります。

メニューバーは自分で素直に作っても良いですし、Bootstrapなどを利用しても簡単に作れますので、デザインの優先順位次第で色々と選択肢がありますね。

Bootstrapを利用するとどうしてもイメージがフラットデザイン的な感じで統一されてしまいますので、さくっと作りたいけれどある程度カスタマイズはしたい、という時にJQuery UIにお呼びがかかりそうです。

オプションを指定することで、要素の高さの基準を決めたり、タブを全て閉じるといったことが可能になります。selectedオプションを使ったデフォルトのタブ指定も良く使いそうですね。


Here is Menu 1.
Here is Menu 2.
Here is Menu 3.


<body>
    <div id="tabs_ui_training">
        <ul>
            <li><a href="#tab_menu1">Menu 1</a></li>
            <li><a href="#tab_menu2">Menu 2</a></li>
            <li><a href="#tab_menu3">Menu 3</a></li>
        </ul>
        <div id="tab_menu1">Here is Menu 1.</div>
        <div id="tab_menu2">Here is Menu 2.</div>
        <div id="tab_menu3">Here is Menu 3.</div>
    </div>
    <script>
        $(function () {
            $('#tabs_ui_training').tabs({
                //clicking open tab close that tab. In short You can close all tabs.
                collapsible: true,
                //adjust all tab height to the tallest one
                heightStyle: "auto"
            });
        });   
    </script>
</body>

JQuery UIを使ってみる―Progressbar&Slider編―

待機時間などを視覚的に伝えることが出来るProgressbarと、つまみを動かすことで値を設定できるSliderを合わせて使ってみたいと思います。 

つまみとProgressbarを連動させ、つまみが最後まで到達したとき簡単なアラートを出します。

利便性を考えると当然ではありますが、Sliderで得られる値はピクセルではなくて、Sliderの長さに対する割合です。つまり0-100の値を取得できます。



<body>
    <div id="progressBar" style="width:400px; margin-bottom: 30px;"></div>
    <div id="sliderWithBar" style="Width: 250px"></div>

    <script>
        $(function () {
            $('#progressBar').progressbar({
                //default value
                value: 0,
                //at the moment reaching the maximum of a progressbar, this is called.
                complete: function(event, ui){
                    alert("Progression done!");
                }
            });
            $('#sliderWithBar').slider({
                slide: function(event, ui){
                    //set value to a progressbar. Value is the rate of a slider length
                    $('#progressBar').progressbar('option', 'value', ui.value);
                }
            });
        });   
    </script>
</body>

2014年11月10日月曜日

JQuery UIを使ってみる―Dialog編―

JQuery UIを使えば、ダイアログの作成も簡単です。ボタンを配置して自由に関数を設定できるので、応用範囲は広そうですね。 

今回は二段構成にしてみました。ちなみに、同じダイアログを複数開かないようにデフォルトで設定されているようです。


You are learning JavaScript. This message is popped up because of JQuery UI Dialog.
This is a second dialog, that is modal!


<body>
    <button id="button_dialog">Open Dialog</button>
    <div id="msg_dialog">
        You are learning JavaScript. This message is popped up because of JQuery UI Dialog.
    </div>

    <div id="msg_dialog2">
        This is a second dialog, that is modal!
    </div>

    <script>
        $(function () {
            $('#button_dialog').click(function () {
                $('#msg_dialog').dialog('open');
            });
            $('#msg_dialog').dialog({
                //without this option, dialog pop up when a page opens 
                autoOpen: false,
                buttons:{
                    "Close": function(){
                        $(this).dialog('close');   
                    },
                    "Open": function(){
                        $('#msg_dialog2').dialog('open');
                    }
                },
                title: 'Dialog1' 
            });
            $('#msg_dialog2').dialog({
               autoOpen: false,
               buttons:{
                   "Close": function(){
                        $('#msg_dialog').dialog('close');
                        $(this).dialog('close');   
                   }
               },
               modal: true,
               title: 'Dialog2' 
            });
        });   
    </script>
</body>

JQuery UIを使ってみる―Datepicker編―

簡単にカレンダー機能を作れるのが、このDatepickerです。航空券の予約サイトなどで良くみるやつですね。

フォーマットの基本がdd-mm-yyという欧米式なので、日本向けのサイトの場合、オプションは必須と言えそうです。




<script>
    $(function () {
        $('#datepicker').datepicker({
            dateFormat: 'yy/mm/dd',
            //show how many months
            numberOfMonths: 2,
            //range of a date you can choose
            minDate: -5,
            maxDate: '+1M'
        });
    });
</script>

2014年11月7日金曜日

Mac環境でQtを使ったPythonスクリプトをapp形式にまとめる

この記事の対象は、色々なツールを試した(あるいは検討した)けれど、Pythonで書いたソースのapp化に使うツールがしっくりきていない方向けです。

まずは結論から。

負担を軽減したいなら、とにかくPythonの2系でPyQt4を使い、PyInstaller2.1でstand-aloneなアプリを作りましょう。

ツールの導入もフォルダを解凍するだけと、とても簡単です。

たとえQt5を使って書いたソースが手元にあるとしても、Qt4向けに修正する価値はあります。特に基本的な機能のみを使ったアプリなら、Qt5じゃなくても動くはずです。

私はYosemite環境でVirtual Box + Mavericksを起動させ、以下のツールを試しました。基本的にMacPortsを使って、なるべく綺麗な環境で行っています。

環境
・Python3.4.1
・PyQt5.3
・sip4.16.4

ツール
・py2app
・cx_Freeze

とりあえず二大メジャーツールというべき、py2appとcx_Freezeを試しましたが、結局Qt4対応のソースに書き直して、PyInstallerで作りました。

このツールの良いところはデフォルトで複数の有名なライブラリに最適化されていることです。それにQtも含まれるため、非常に簡単にapp化できるのだと思います。

対応しているライブラリはこちら

上記二つのツールを使う際の問題点は、いわゆるsemi-stand-aloneなアプリになりやすいことです。つまり実行可能形式なんだけれど、環境に依存するという形式です。他の環境で試すまで分からなかったりと困った子です。外部ライブラリの取り込みが難しいんですよね。。。そして上手くいかない際の原因が分かりづらいです。。。

一方のPyInstallerですが、こちらはすでにアプリなため、ただ公式サイトからダウンロードしてきて解凍するだけです。

PyInstaller

以前の2.0ではビルドなどに様々なコマンドが必要だったようですが、現在は本当に数ステップです。

①本家サイトから取ってきたファイルを解凍。

②解凍して出来たPyinstallerというフォルダに、app化したいPythonスクリプトを置く。

③その階層で次のコマンドを叩く。

python pyinstaller.py --windowed your_source.py -i your_icon.icns

下線部分は適宜、ご自身の素材に読み替えてください。アイコンは使いたいものがある場合だけのオプションです。デフォルトのアイコンは微妙です。他のオプションは公式サイトからどうぞ。

--windowedコマンドは、UNIXの実行可能形式のみではなく、app形式を生成するためのオプション(だったはず)です。

コマンド自体はたったこれだけです。これでご自分のスクリプト名がついたフォルダが、Pyinstallerのフォルダ内に生成されます。いくつか階層を下れば、app形式のファイルがあるはずです。

私が使った環境です。MacPortsを使って導入しています。

Python27
py27-sip
PyQt4

PyInstaller(公式サイトからダウンロード)

PyQt5で書いたソースをPyQt4に書き直すのは気が引けますが、実際はQtWidgetsをQtGuiに置換(Qt5で独立した部分です)してしまえば、あとの修正部分は驚くほど少ないはずです。

私はencodeの部分で少し分かりにくい齟齬が発生しましたが、それも他のapp化ツールの情報収集に比べれば微々たるものでした。

ライブラリも出そろってきてだいぶ安定してきた3系ですが、それでもQtを使ったアプリの配布用作成には、この記事で挙げているバージョンを採用することで悩む時間がずいぶん減ると思いますよ。

Mac環境でシステムのPythonをアップグレード(インストール)する

Windowsユーザにはなんてことない、Pythonのアップデートですが、Macユーザには意外と手間だったりします。最近ならMacPortsやHomebrewあたりを使ってPATHを書き換えるのが主流のようですね。

そんな主流に反して、システムのPythonをアップデートする方法をメモしておきます。

まず、Macのシステムってどうなってるの、というとこから。Pythonに関わるPATHは以下の三つがあります。

usr/lib
プリインストール(最近だと2.5, 2.6, 2.7あたりが入ってますね)されている、Pythonのライブラリなんかがあります。

usr/bin
pythonコマンドなどのリンクがあります。ターミナルで「python」コマンドを叩くと、このリンクから各pythonの実行ファイルに飛ぶ仕組みです。


/Library/Frameworks/Python.framework/Versions/2.7(各バージョン。私はとある事情から3.3を入れました)

公式サイトのインストーラを使ってあるバージョンをインストールした時にできる階層。ここにpythonコマンドなどが追加されますが、3系なんかのバージョンでは微妙に名称が違うので注意です。

たとえば、Python3.3の場合は、pythonではなくてpython3になっています。

よって、システムのPythonを変更した場合、次の手順を取ることになります。

①インストーラで好きなバージョンをインストール

②usr/bin配下のリンクファイルをいったん削除。

③usr/bin配下に再度、新しく追加したPythonへのリンクを作成。

④新しいPython置き場にあるライブラリのフォルダを、PATHに追加。

具体的なコマンドはこんな感じです。

sudo rm /usr/bin/pydoc
sudo rm /usr/bin/python
sudo rm /usr/bin/pythonw
sudo rm /usr/bin/python-config

まずはリンクを削除しました。続いて、リンクを作成しなおします。今回はPython3.3を例に使いますが、各バージョンに合わせてリンク元の名称は変更します。

ln -s /Library/Frameworks/Python.framework/Versions/3.3/bin/pydoc3 /usr/bin/pydoc
ln -s /Library/Frameworks/Python.framework/Versions/3.3/bin/python3 /usr/bin/python
ln -s /Library/Frameworks/Python.framework/Versions/3.3/bin/pythonw3 /usr/bin/pythonw
ln -s /Library/Frameworks/Python.framework/Versions/3.3/bin/python3-config /usr/bin/python-config

以上で、リンクの再配置が完了しました。
さらに、ライブラリのPATHを追加します。vimで.bash_profileあたりに書き加えましょう。ちなみにこのコマンドのみだと、PyQtなどの各種ツールが配置されるsite-packageが含まれないため、必要な方はそちらも追加しましょう。

PATH="/Library/Frameworks/Python.framework/Versions/3.3/bin:$PATH"
export PATH

後はPATHを反映して、ターミナルでpythonと打って無事に新しいバージョンが起動すればOKです。

2014年11月5日水曜日

Mac上のVirtual BoxでOSXを動かす際に、解像度を変更する

開発環境用にもう一つOSXを立ち上げました。

最近Yosemiteに更新してしまったので、旧環境としてMavericksを整えておきました。

けれど一つ問題が。次のコマンドを使用して、解像度を変更できるのですが、値が決まっているんですよね。。。そのため、ぴったりくるのがなくてちょっと小さい画面を使っています。

初期状態よりは全然大きいので、とりあえずここは妥協ですね。

VBoxManage setextradata "VM name" VBoxInternal2/EfiGopMode N

"VM name" は対象のマシーン。私は単純にMavericksにしています。

Nは整数値です。下にあるのが対応表です。

0: 640x480
1: 800x600
2: 1024x768
3: 1280x1024
4: 1440x900
5: 1920x1200

ちなみLinuxなどGOPじゃなくてUGAを使っているものが対象の場合、次のコマンドで好きに設定できるみたいですね。いいなあ。。。

VBoxManage setextradata "VM name" VBoxInternal2/UgaHorizontalResolution 1200
VBoxManage setextradata "VM name" VBoxInternal2/UgaVerticalResolution 800

2014年11月4日火曜日

JQuery UIを使ってみる―Button編―簡単なサンプル

Buttonをいくつか並べてみます。

メモ用サンプルです。
ちょっとだけ色の変更や、JQueryを用いた角丸の追加などを行っています。

JQuery UI Button

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>JQuery UI Button</title>
        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/themes/smoothness/jquery-ui.css" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
        <style>
            .buttons{
                margin-bottom: 10px;
            }
        </style>
    </head>
    <body>
        <div class="buttons">
            <button>click</button>
        </div>

        <div class="buttons">
            <input type="checkbox" id="check"><label for="check">click click!</label>
        </div>

        <div class="buttons">
            <input type="radio" name="radio" id="radio1"><label for="radio1">1</label>
            <input type="radio" name="radio" id="radio2"><label for="radio2">2</label>
            <input type="radio" name="radio" id="radio3"><label for="radio3">3</label>
        </div>

        <div id="set">
            <input type="radio" name="radioset" id="radio4"><label for="radio4">4</label>
            <input type="radio" name="radioset" id="radio5"><label for="radio5">5</label>
            <input type="radio" name="radioset" id="radio6"><label for="radio6">6</label>
        </div>

        <script>
            $(function () {
                $('button').button().click(function () {
                    console.log($(this).css("background-color"));
                    if ($(this).css("background-color") === "rgb(255, 0, 0)") {
                        $(this).css("background", "none").css("background-color", "rgba(0, 50, 20, 0.6)");
                    } else {
                        $(this).css("background", "none").css("background-color", "rgb(255, 0, 0)");
                    }
                });
                $('#check').button();
                $('input[name=radio]').button();
                
                //make some buttons as a set
                $('#set').buttonset();
                
                $('.buttons .ui-button').css("border-radius", "50px");
            });
        </script>
    </body>
</html>

JQuery UIを使ってみる―Accordion編―色も変えてみる

今回はAccordionを使ってみます。

JQuery UIを使うと、非常に簡単に定番のアコーディオンを実装できます。ただし、背景色の変更などは自動で割り振られるui-accordion-header(content)クラスの背景を一度リセットして、それから再設定してあげる必要があります。

細かいオプションがいくつかありますが、今回は次の条件をクリアできるように設定しました。

①閉じた状態から開始される
②全て閉じられる
③コンテンツに合わせて大きさが変化する

ついでにソート可能なものにしてみました。

item 1

Here is an explanation. You can sort this item, handling each header.

item 2

Here is an explanation. Some of these could be very long but they are automatically adjusted with the option, heightStyle.

item 3

Here is an explanation.

item 4

Here is an explanation.

item 5

Here is an explanation.

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>JQuery UI Accordion</title>
        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/themes/smoothness/jquery-ui.css" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
        <style>
            #accordion{
                width: 100%;
                height: 250px;
            }
            .accordion_item{
                width: 400px;
            }
        </style>
    </head>
    <body>
        <div id="accordion">
            <div class="accordion_item">
                <h3>item 1</h3>
                <div>
                    Here is an explanation. You can sort this item, handling each header.
                </div>
            </div>
            <div class="accordion_item">
                <h3>item 2</h3>
                <div>
                    Here is an explanation. Some of these could be very long but
                    they are automatically adjusted with the option, heightStyle.
                </div>
            </div>
            <div class="accordion_item">
                <h3>item 3</h3>
                <div>Here is an explanation.</div>
            </div>

            <div class="accordion_item">
                <h3>item 4</h3>
                <div>Here is an explanation.</div>
            </div>

            <div class="accordion_item">
                <h3>item 5</h3>
                <div>Here is an explanation.</div>
            </div>
        </div>

        <script>
            $(function () {
                $('#accordion').accordion({
                    //begin from all close.
                    active: false,
                    //for closing all items
                    collapsible: true,
                    //explicit about header of accordion item, which open the item.
                    header: ">div>h3",
                    //adjust content size to each accordion item.
                    heightStyle: "content"
                }).sortable({
                    handle: "h3"
                });
                $('.ui-accordion-header').css("background","none").css("background-color","rgba(247, 227, 227, 0.8)");
                $('.ui-accordion-content').css("background","none").css("background-color","rgba(243, 227, 227, 0.22)");
            });
        </script>
    </body>
</html>

2014年11月3日月曜日

JQuery UIを使ってみる―Selectable&Sortable編―二つを同時に使ってみる

リストを選択形式に変更できるSelectableと、並び替えを行えるSortableを使ってみました。

ドットインストール様がとてもまとまったレッスンを提供してくださっていたので、しばらくこちらでお勉強させていただくことにしました。

また、単純にメソッドチェーンするだけではSelectableとSortableは同時に利用できません。でもどうしても同時に使いたい! という時のために、Selectableのオプションを使って実現してみました。

スタイルはいつも通り適当に。

  • item 1
  • item 2
  • item 3
  • item 4
  • item 5
  • item 6


公式サイトの例では、selectable()を設定しているだけなのですが、ここではui.selectable.idを取ってちょっとお試しソースが追加されています。

このui.selectedなんですが、idとclass以外には何が取れるのか、ちょっと分かりませんでした。もう少し公式ドキュメントを探ってみたいと思います。

Selectableの便利なところは、自動的にui-selectingやui-selectedというクラスが追加される部分です。こちらに色などを指定すれば、選択されている時、あるいは選択された後を表現するための視覚効果が簡単に得られますね。

Sortableの方は、ドットインストール様が実装されていたupdateメソッドも使ってあります。これの注意点は、id名に"_1"などのアンダースコアと数字がついた名前をつけなければならないという点です。

さて、このSelectableとSortableの同時実装についてですが、まずは内部にhandleクラスを実装します。ここからのポイントは二つです。

①Selectable
handleクラスの部分では、canselオプションで機能を停止します。

②Sortable
handleクラスの部分だけ"handle"オプションをつけて有効化します。

やっていることは、draggableの範囲指定と似ていますね。

仕上げとして、リストのそれぞれにはJQueryのfindを利用し、まずは適当なクラスを追加します。その先頭にprependで新しいdivを挿入します。ここにhandleクラスを含めてあります。これで数が多くなっても後から楽ちんです。この辺りはJQueryの基本的な動作ですね!

ついでにちょっと分かりやすいようにhandle部分にCaratもつけてあります。これはJQueryが用意してくれているアイコンです。細かい位置などをCSSで直して出来上がり!

<!DOCTYPE html>
 
<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>JQuery UI Selectable</title>
        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/themes/smoothness/jquery-ui.css" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
        <style>
            .ui-selecting{
                background-color: rgba(93, 221, 170, 0.1);
            }
            .ui-selected{
                background-color: rgba(93, 221, 170, 0.5);
            }
            .ui-selected .handle{
                background-color: rgba(230, 255, 101, 0.5);
            }
            #select_sortable{
                list-style: none;
            }
            #select_sortable > li{
                font-size: 20px;
                position: relative;
                padding-left: 30px;
                border: solid 1px;
                margin-bottom: 4px;
                font-family: 'Lucida Grande','Hiragino Kaku Gothic ProN', Meiryo, sans-serif;
                height: 30px;
                width: 300px;
            }
            li .handle{
                position: absolute;
                top: 0; bottom: 0; left: 0; 
                background-color: rgba(230, 255, 101, 0.5);
                width: 25px;
                height: 30px;
            }
            .carat{
                margin-top: 30%;
                margin-left: 5px;
            }
        </style>
    </head>
    <body>
        <ul id="select_sortable">
            <li id="item_1">item 1</li>
            <li id="item_2">item 2</li>
            <li id="item_3">item 3</li>
            <li id="item_4">item 4</li>
            <li id="item_5">item 5</li>
            <li id="item_6">item 6</li>
        </ul>
        <script>
            var selected = new Array();
            $(function () {
                $('#select_sortable').sortable({
                    //only with handle part, this is sortable
                    handle: '.handle',
                    //show cursor while it moves
                    cursor: 'move',
                    opacity: 0.5,
                    update: function (event, ui) {
                        console.log($(this).sortable("serialize"));
                    }
                }).selectable({
                    cansel: '.handle',
                    filter: 'li',
                    selected: function (event, ui) {
                        //if selected item is not in an array.
                        if (selected.indexOf(ui.selected.id) === -1) {
                            //push an selected item in an array.
                            selected.push(ui.selected.id);
                            console.log(selected);
                        }
                    },
                    unselected: function (event, ui) {
                        var id = ui.unselected.id;
                        //remove an selected item from an array with splice.
                        selected.splice(selected.indexOf(id), 1);
                    }
                //first add ui-corner-all class which makes squares rounder.
                //add div handle class with pre ui icon, that is a carat indicating movable up and down.
                }).find('li').addClass("ui-corner-all").prepend("<div class='handle'><span class='carat ui-icon ui-icon-carat-2-n-s'></span></div>");
            });
        </script>
    </body>
</html>

Canvasによる簡易アニメーションの実装。とりあえず定番のピンポンでも。

Canvasによる単純な図形の描画

前回の記事に引き続き、今回はCanvasを用いて簡単なアニメーションを表示してみます。
定番(?)のピンポン的なあれを、JavaScript的なオブジェクト指向(で良いのでしょうか。。。)で書いてみました。

ちなみにこれまでPythonやJavaを書く機会があったのですが、PythonやJavaScriptの紳士協定的なプライベート変数の扱い方でもそれほど問題を感じていません。私は先頭にアンダースコアをつけたい派です(今回は個人的なお絵かきなので省略)。Pythonから流れてきているので。

特にマシンの性能がばらばらというウェブ上で数字を求める時なんかは、クロージャを使ってメモリ圧迫する可能性を考慮しながら実装するのは骨が折れますし。

ただ、実装者のレベルがまちまちかつ、大規模開発環境だと、Javaのきっちり感はやはり有難かったですね。

さてさて、前回はonloadを用いて、ページ読み込み時に描画していましたが、今回はJQueryを利用してボタンをつけました。

Canvas

アニメーションのポイントは、描画処理を以下のようにsetIntervalで書いてあげることです。

timer = setInterval(draw, 10);

今回の処理をまとめると、おおよそ以下の動きとなります。

①クリックイベントが発生。

②ボールのオブジェクトを作成し、そこにサイズや速度などの情報を格納。それをランダム個作成
し、配列に格納。

③配列をループ処理し、それぞれの位置を変更。

やっていることはこれだけです。その際、clearRectを使って毎回画面をリセットする必要があります。

壁でバウンドする処理は、壁に到達した際に方向を変えることで表現しています。ボールの位置がキャンバスの幅をはみ出る値に達した場合、speed(速度と方向を意味する変数です)に-1をかけることで、逆向きにします。

if(this.locX < 0 || this.locX > canvasW){
this.speedX *= -1;
}

以下が今回のソースです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Canvas</title>
    <style>
        canvas{
          border: solid 2px;
          background-color:rgba(0,0,0);
          margin-bottom: 5px;
        }
        button{
          margin-left: 5px;
          border-radius: 20px;
          background-color: rgba(127,181,224,0.5);
          width: 80px;
          height:30px;
          padding: 4px;
          font-size: 16px;
          text-shadow: 0, 1px, 0 rgba(0,0,0,0.5);
        }
    </style>
</head>
<body>
    <div class="container">
        <canvas id="anime" width=480 height=360></canvas>
        <div>
            <button id="play">Start</button>
            <button id="clear">Stop</button>
        </div>
    </div><!--container-->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script>
        var timer;
        var nowPlaying = false;
 
        var canvasW = 480;
        var canvasY = 360;
 
        var point = new Point(canvasW,canvasY);
 
        var ball_nums;
        var balls;
 
        $(function(){
            $('#play').click(function(){
                if (nowPlaying) return;
                init();
                nowPlaying = true;
                timer = setInterval(draw, 10);
            });
            $('#clear').click(function(){
                clearInterval(timer);
                init();
                clear();
                nowPlaying = false;
            });
        });
 
        //initialize the canvas
        function clear(){
            var canvas = document.getElementById("anime");
            //old browser does not support canvas. Avoid error.
            if (canvas.getContext){
                var context = canvas.getContext('2d');
                context.clearRect(0,0,canvasW,canvasY);
            }
        }
 
        function draw(){
            var canvas = document.getElementById("anime");
            //old browser does not support cavas. Avoid error.
            if (canvas.getContext){
                var context = canvas.getContext('2d');
                paint(context);
            }
        }
 
        //create ball objects
        function init(){
            ball_nums = Math.floor(Math.random() * 500);
            balls = [ball_nums];
            for(i = 0; i < ball_nums; i++){
                balls[i] = new Ball();
            }
        }
 
        function paint(context){
            //overwrite canvas
            context.globalCompositeOperation = "source-over";
 
            /* This makes canvas dark */
            //context.fillStyle = "rgba(10,10,8,0.2)";
            //context.fillRect(0, 0, canvasW, canvasY);
 
            //refresh the canvas
            context.clearRect(0,0,canvasW,canvasY);
 
            //This allows objects to merge, for example if there are blue and yellow,
            //it turns to be green.
            context.globalCompositeOperation = "lighter";
 
            for (i = 0; i < ball_nums; i++){
                balls[i].relocate();
 
                context.beginPath();
                context.fillStyle = balls[i].color;
                context.arc(balls[i].locX, balls[i].locY, balls[i].radius, 0, Math.PI*2.0, true);
                context.fill();
            }
        }
 
        //each ball object. locations change with being added each speed.
        function Ball(){
            this.speedX = Math.random() * 5;
            this.speedY = Math.random() * 5;
            this.locX = point.randomX();
            this.locY = point.randomY();
            this.color = randomColor();
            this.radius = Math.random() * 20;
        }
 
        Ball.prototype.relocate = function(){
            //relocate
            this.locX += this.speedX;
            this.locY += this.speedY;
 
            //to other way when this reaches a wall
            if(this.locX < 0 || this.locX > canvasW){
                this.speedX *= -1;
            }
            if(this.locY < 0 || this.locY > canvasY){
                this.speedY *= -1;
            }
        };
 
        function randomColor(){
            var r = Math.floor(Math.random() * 256);
            var g = Math.floor(Math.random() * 256);
            var b = Math.floor(Math.random() * 256);
            var a = Math.random();
            return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
        }
 
        //For getting a random point on the canvas
        function Point(canvas_width, canvas_height){
            this.x = canvas_width;
            this.y = canvas_height;
        }
        Point.prototype.randomX = function(){
            return Math.random() * this.x;
        };
        Point.prototype.randomY = function(){
            return Math.random() * this.y;
        };
    </script>
  </body>
</html>

OSX10.10でPyenv使ってPytho3.4.1の環境をインストールしてPyQt5入れようとしたら色々と祭りでした

エラーの嵐をなんとかやり過ごしたメモです。本当に対症療法だけで乗り越えています。
というのも、今回の目的はWindows環境で作ったGUIアプリをMac用の実行可能形式にしたかっただけなので、アプリさえ動けばとりあえずOK。

というわけで、私の環境には現在いくつかの機能が入っていません。でも目的のために手段を選んではいられない! ということで、その辺りはこの際、目を瞑りました。なので、こんな感じでひとまず動いたよ! というだけの記事です。

とりあえず、次の環境では色々うまくいかないので、当てはまる場合はpyenvを使わないほうが良いのかもしれません。

OSX10.10
PyQt5.3.2
sip4.16.4
XCode 6.1

まずはこちらのサイト様を参考に、Homebrewを利用してpyenv環境を構築。

Mac OSX で開発環境を構築するための環境構築 (Homebrew, Git, SVN, Ruby, Perl, Python)


トラブル① pyenv global が効かない


こちらのサイト様を参考にいたしました。
どうやってもsystem配下のPythonを優先してしまうので、とりあえずPATHの先頭に加えることで対処。

macでpyenvの環境を整えたい

.bash_profileに以下の記述を追加しました。

export PYENV_ROOT="${HOME}/.pyenv"
if [ -d "${PYENV_ROOT}" ]; then
    export PATH=${PYENV_ROOT}/bin:$PATH
    eval "$(pyenv init -)"
fi

続きまして、こちらのサイト様を参考にsip, PyQt5, Qtを整えていきます。

SIPとQtとPyQt5の再設定

sipとQtに関してはとりあえず公式から取ってきました。バージョンは上の通りです。

ここからはPyqt5のインストールに関してです。
まずはpython configure.pyです。


トラブル② Qt.5.3.2既存エラー


次のエラーが表示されました。
Error: Failed to determine the detail of your Qt installation. Try again using
the --verbose flag to see more detail about the problem.

次のサイト様を参考にしました。

PyQt5をmacにinstall

これにバグがあるとか。


~/Qt/5.3/clang_64/lib/QtCore.framework/Headers/qflags.h

#!if defined(_LP64_) && !defined(Q_QDOC)
Q_DECL_CONSTEXPR inline QFlag(long ai) : i(int(ai)) {}

これの一文目を、次のように変更。先頭の!を削除です。

#if defined(_LP64_) && !defined(Q_QDOC)


トラブル③ pyenv環境によるエラー


次のエラーが表示されました。

UnboundLocalError: local variable 'pylib_dir' referenced before assignment

このエラーなんですが、systemのPython(2.7.6とかだと思います)を対象にmakeをすると表示されません。

dynamic_pylib = '--enable-framework' in config_args

このconfig_argsに'--enable-framework'という値が含まれないため、pylib_dirにpyenv環境のライブラリパスが含まれないことが原因のようです。というわけで、超対処療法です。
これが原因で、最後の妥協を強いられたのかもしれませんが。。。

730行目前後です。
こんな感じのソースがあります。

if dynamic_pylib:
                pyshlib = ducfg.get('LDLIBRARY', '')

このdynamic_pylibはbooleanなのですが、これを無理やり真にしてしまいます。
dynamic_pylib = True

とりあえず物は試しということで、これで作業を続けました。
これでようやくライセンスの確認までたどり着けました。


トラブル④  headerの参照ミス


これもHomebrew環境のみで起こる、単純な参照失敗みたいです。

sip/QtPrintSupport/qprinter.sip:28:10: fatal error: 'qprinter.h' file not found

qprinter.h自体はあるんですが、QtWebKitWidgetsから参照できていないようです。

次の質問が参考になりました。


これを

 'QtWebKitWidgets':      ModuleMetadata(qmake_QT=['webkitwidgets']),

こんな感じに。

 'QtWebKitWidgets':      ModuleMetadata(qmake_QT=['webkitwidgets' 'printsupport']),

というわけで、python configure.py からもう一度やり直すことになりました。

ちなみに。

Qt/5.3/clang_64/lib/QtPrintSupport.framework/Versions/5/Headers/qprinter.h

これを、cpコマンドを使って、次の階層にコピーするという強引な方法でも通りました。

Qt/5.3/clang_64/lib/QtWebKitWidgets.framework/Versions/5/Headers/qprinter.h


トラブル⑤ シンボリックエラー


最新のXCode (2014/10/31時点)はOSX10.9, 10.10向けなため、途中でシンボリックエラーが出る場合があります。私の場合は次の修正を行ったところ、エラーを抜けることができました。

~/Qt/5.3/clang_64/mkspecs/macx-clang/qmake.conf
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.6


~/Qt/5.3/clang_64 /mkspecs /qdevice.pri
!host_build:QMAKE_MAC_SDK = macosx10.8

これらの値を、とりあえず10.9にしてみました。

トラブル⑥ シンボリックエラー再び


ちなみにこんな感じのエラーです。

Undefined symbols for architecture x86_64

どうもQtというよりもXCodeとの齟齬が原因のようなのですが、エラーには変わりありません。これはdesignerのビルド時に発生していたらしく、この階層のpython.proを色々といじってみましたが、上手くいかず。

ですが、ここで当初の目的であるmac用実行可能形式ファイルを作成する、ということを最優先し、とりあえずdesignerとqmlsceneのビルドをしないことにしました。

PyQt5.proの次の部分を修正しました。

SUBDIRS = QtCore QtGui QtHelp QtMultimedia QtMultimediaWidgets QtNetwork QtOpenGL QtPrintSupport QtQml QtQuick QtSql QtSvg QtTest QtWebKit QtWebKitWidgets QtWidgets QtXmlPatterns QtDesigner QtDBus _QOpenGLFunctions_2_0 QtSensors QtSerialPort QtBluetooth QtMacExtras QtPositioning QtQuickWidgets QtWebSockets Enginio Qt pylupdate pyrcc designer qmlscene

ここから、最後のdesignerとqmlsceneを削除しました。

基本的にmacでアプリのデザインとかしないので、妥協しました。完全なmac環境が必要になった場合は、今の所pyenvを諦めてPythonの3系をsystemのバージョンとしてインストールしたほうが早そうです。。。

以上で、ひとまず別の環境で作ったPyQt5を含むソースを動かせるようにはなりました。あとはcx_Freezeあたりを利用して、appを作成すれば良いかと思います。

以上、対処療法による傷だらけの処置方法でした。

2014年11月1日土曜日

JQuery UIを使ってみる―DroppableとResizable編―

JQuery UI第二弾です。今回はDraggable要素を受け入れるDroppable要素と、イメージのサイズを変更できるResizable要素を使って、色々試してみました。

ソースはJQueryのみです。
$(function () {
$('.box').draggable({
    opacity: 0.5,
    //イメージの移動ではなく、新しいイメージを動かせます。
    //helper: 'clone',
    //droppable以外だと、ひょいっと元の位置に戻ってくれます。
    revert: "invalid",
    drag: function (event, ui) {
        //イベントの設定です。適当に左辺の位置でもとってみました。
        console.log(ui.position.left);
    }
});
$('.target').droppable({
    accept: '.box',
    tolerance: 'fit',
    hoverClass: 'hover',
    drop: function (event, ui) {
        //ドラッグされたイメージがコピーされます。
        //ui.draggable.clone().appendTo(this);
        //acceptが指定されているイメージが重なったときのみ実行されます。
        console.log('dropped!');
    }
});
$('.resize').resizable({
    //どの辺、角からサイズを変更できるようになります。
    handles: 'all',
    aspectRatio: false,
    //サイズが変更されたときに、ランダムで色を変更します。
    stop: function (event, ui) {
        var r = Math.floor(Math.random() * 256);
        var g = Math.floor(Math.random() * 256);
        var b = Math.floor(Math.random() * 256);
        var a = Math.random();
        var color = "rgba(" + r + "," + g + "," + b + "," + a + ")";
        $(".resize").css("background-color", color);
    }
}).draggable();


Draggable
Target
Resize

JQuery UIを使ってみる―Draggable編―

ただでさえグローバルで活躍できる有能なJQueryを、さらに有能にしてしまう恐ろしい公式ライブラリJQuery UIに関するメモ書きです。

ちなみにちょっと中を覗いてみると、JQueryのマウスイベントを利用して、常に座標を更新し続けるアニメーション的動作な感じでしょうか。そのうち時間を取ってソースを追いかけてみたいと思います。


<!DOCTYPE html>

<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>JQuery UI</title>
        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/themes/smoothness/jquery-ui.css" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
        <style>
            #box{
                width: 150px;
                height: 150px;
                background-color: rgba(164,218,243,1);
                font-size: 16px;
                border: solid 2px;
            }
            .handle{
                height: 50%;
                background-color: rgba(201,246,74,1);
            }
        </style>
    </head>
    <body>
        <div id="box">
            <div class="handle">Draggable</div>
            <div>Undraggable</div>
        </div>
        <script>
            $(function () {
                $('#box').draggable({
                    opacity: 0.5,
                    handle: '.handle'
                    //cancel: '.cancel'
                 });
            });
        </script>
    </body>
</html>
上のソースを貼り付けると、次のような、ドラッグ可能な四角形を表示できます。

Draggable
Undraggable

HTML内で作成したboxに、JQuery UIでDraggableをつけているだけです。簡単ですね! 色々な引数がありますが、そこは本家サイトを参照します。

JQuery UIのリファレンス

ここで使っているのは、handleというオプションです。この値が指定されている箇所のみがドラッグ可能になります。反対はcancelですね。 opacityで、ドラッグしている間だけ色が薄くなる効果をつけています。

色々なことが出来そうですね!