カテゴリー : script
このカテゴリーの登録数:46件 表示 : 1 - 10 / 46
2010/03/29
横書きのままタテに表示するアレ
最近よく見かけるようになった、スクロールバーのとこにくっついてくるアレ
(follow me とか)
(feedback とか)
問題は、これがスクロールについてくることじゃなくて、横書きなのに、縦に表示されているってこと。
これ、どうやるんだろう...。
(中略)
やっぱここは流行りのSVGだよね。ってことで、やってみた(注:Firefox,Chrome以外動かないと思う)
ref - http://xole.net/svg.html
横書きのままタテに表示されるようになったけど、リンクが動かない...。
しょうがないので、onclickで逃げる。
ソースは↓
(function (){ var anchor = function (href, str){ var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', 300); svg.setAttribute('height', 200); var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); rect.setAttribute('x', 0); rect.setAttribute('y', 0); rect.setAttribute('width', 200); rect.setAttribute('height', 50); rect.setAttribute('fill', '#ccc'); rect.setAttribute('opacity', 0.3); rect.setAttribute('stroke', '#333'); var text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); text.setAttribute('x', 50); text.setAttribute('y', 30); text.setAttribute('writing-mode', 'tb-rl'); text.setAttribute('glyph-orientation-vertica', '90'); text.setAttribute('fill', '#333'); text.setAttribute('transform', 'rotate(90, 90, 90)'); text.textContent = str; text.onclick = function(){location.href = href}; text.appendChild(rect); svg.appendChild(text); // svg.style.display = 'block'; return svg; }; var element = document.createElement('div'); element.style.position = 'absolute'; element.style.left = 0; element.style.padding = 0; element.appendChild(anchor('http://www.google.co.jp/', 'こんにちは!')); element.appendChild(anchor('http://www.google.com/', 'hello world')); document.body.appendChild(element); })();
他にいい方法あるんかな...。(やっぱ画像?)
Javascript Library 毎のパフォーマンス比較
というこよで、貼ってみる
ちなみに DOM 操作編
やっぱ jQuery は早いねー
(2010/03/31追記)
出展元を書くのを忘れてました。
via - http://figit.net/post/644
(上記グラフは単位がmsになります)
さらに、元ネタは http://docs.jquery.com/Release:jQuery_1.3#Performanceがソースになります
2009/12/27
JavaScriptプログラマが理解しておくべき8つのこと。の個人的補足
もう今年はブログを書かないんだろうなーと思っていたけど、ちょっと気になるエントリを見てしまったので、書いておくよ!
ref - JavaScriptプログラマが理解しておくべき8つのこと - ++iskwn - キューイチ世代
いくか(8つ?)あるから、それぞれ勝手に全レスするよ!
(先に断りを入れておくと、僕は専門家でもなんでもないから、指摘があったら指摘してください)
たぶん、僕の書いた記事「javascriptを初めて学ぶ人についてのおさらい。その1」と「javascriptを初めて学ぶ人についてのおさらい。その2」を読めば全部理解するはず!(嘘偽有り)
JavaScriptは完全なオブジェクト指向ではない
これは書かれていることそのままでいいかな。ツッコミどころはそこじゃないけど。
ただ、一つ、「プロトタイプベース」「インスタンスベース」という言葉の指摘をするのであれば「オブジェクト指向プログラミング言語ではない」のが正しいのかな。どうでもいいけど
functionの定義には2つある。違いもある
これは完結してた
ただ、文と式、みたいなところにもスポットライト当ててください。。
いわゆるクロージャは単純な概念である
本文には
感覚的には単純だが、論理的には複雑で言葉で説明しづらい。体で覚えたほうが楽なタイプの概念。どんどん拾ったコードを試そう。試せばわかるよ。難しく解説してる人とか無視してOK。
これは本質を捉えている気もするけど、なんとなくアウト。
難しく解説するには、それなりの理由があるかも。特にスコープを理解しないと間違った用法が出回ると後々困るんじゃ。。?
javascriptの変数宣言には、letやvalみたいな宣言はなくて、varと宣言なしの
グローバル宣言しかない。特にこのグローバル宣言でクロージャを体得されると、後々余計なバグを作っちゃうかも
以下はグローバル宣言を使ったクロージャ的サンプル
var createCounter = function (){ counter = 0; return function (){ return counter++; }; }; var hoge = createCounter(); print(hoge()); // 0 print(hoge()); // 1 print(hoge()); // 2
これもクロージャだよね?と新人に聞かれたら、思わずスコープのお話をしてしまうに違いない!
なので、他のスコープから触れないように定義する。そうすると難しくなっていく。。。
var createCounter = function (){ var counter = 0; return function (){ return counter++; }; }; var hoge = createCounter(); print(hoge()); // 0 print(hoge()); // 1 print(hoge()); // 2
IE8はDOMアクセスがクソ速い
これは正しい。もちろん、Firefox3.5もOpera10も早い
でも、DOMをガリガリ書くよりも、CSSSelectorを使うようになっているトレンドも忘れないであげてください。。。
XmlHttpを使いたいだけならライブラリ使うな
そして再利用可能なコードなのに、似て非なるものが増えていく。。。
prototype継承とか言っちゃってる奴は目を覚ませ
元エントリによると
「prototypeを使ってプロパティの継承を行うメリットとは何か」
これに答えられないなら勉強しなおしたほうが良い。答えられた奴はprototype継承って言うのやめとこな?
そもそもprototypeは継承の仕組みではない。あと「プロトタイプベース」と「インスタンスベース」はまったく違う。
まず、ここまで書くならメリットを教えてあげてもいいじゃん。。。
「プロトタイプベース」「インスタンスベース」と上げる前に、prototypeのメリット的なのを僕から。
javascriptには、prototypeっていうプロパティがあって、そこに値を入れておくと、同じ値を共有(共有には御幣があるかも)できるよ。って仕組みがあります。まずはコード
var Hoge = function (){}; Hoge.prototype.hello = function (){ return 'hello world'; }; var a = new Hoge; print(a.hello()); // hello world
んで、このprototypeのおかげで、元となるprototypeに新しいプロパティを増やすと、そのprototypeのインスタンスにもそれがついてくるよ!ってのがメリットでしょうか(あまり使わないかも。。。)
var Hoge = function (){}; Hoge.prototype.hello = function (){ return 'hello world'; }; var a = new Hoge; print(a.hello()); // hello world Hoge.prototype.hello2 = function (){ return 'hello hello hello'; }; print(a.hello2()); // hello hello hello
インスタンスベース
説明が難しいところだけど、これはインスタンスベースでもできるじゃんか。ということなので、できる。上のコードをインスタンスベースにしてみると
var Hoge = { hello: function (){ return 'hello world'; } }; var a = Hoge; print(a.hello()); // hello world Hoge.hello2 = function (){ return 'hello hello hello'; }; print(a.hello2()); // hello hello hello
でもこれだと、インスタンス中の値がずっと同じ参照(※例1)になるから、javascriptでは、新しい参照を作るときに clone ではなく new という仕組みでクラスベースな考えになっている(※例2)。と
※例1
var Hoge = { counter: 0, increment: function (){ return this.counter++; } }; var a = Hoge; print(a.increment()); // 0 print(a.increment()); // 1 print(a.increment()); // 2 var b = Hoge; print(b.increment()); // 3
※例2
var Hoge = function (){ this.counter = 0; }; Hoge.prototype.increment = function (){ return this.counter++; }; var a = new Hoge; print(a.increment()); // 0 print(a.increment()); // 1 print(a.increment()); // 2 var b = new Hoge; print(b.increment()); // 0 print(b.increment()); // 1
うーん。あまりいい例が思い浮かばない。。。
とりあえず、javascriptにはconstructorもあるから、インスタンスベースではなく、クラスベースと捉えた方がわかりやすそう。
function.applyには正しい使い方がある
正しいかどうかは、別として、javascriptのthisという動的レシーバはとても便利だったりする。
var hello = function (arg1, arg2){ return this.calc(arg1, arg2); }; var Add = { calc: function (arg1, arg2){ return arg1 + arg2; } }; var Mul = { calc: function (arg1, arg2){ return arg1 * arg2; } }; print(hello.apply(Add, [1, 2])); // 3 print(hello.apply(Mul, [1, 2])); // 2
Javaで匿名クラスをゴリゴリとか、containerに入れてほげほげ。とか面倒なのが色々あるけど、javascriptなら標準装備!
なんて、うたい文句はあまりないけど、delegateとかproxyとかその辺がめっちゃ楽になるのはホント
(ってか「正しい使い方」を教えてください。。。)
Canvasは必ず覚えるべき
SVGもあると便利かと。
おわり
jsの話題で今年書くことになるとは思わなかった。。
とにかく、元エントリに何か物申すつもりはなく、補足も書いてあると良い事言ってるのになーと思ったんで個人的補足でした。
「インスタンスベース」でプロトタイプを学ぶなら、IoLanguageを触るのが一番簡単だと思う。きっとjsで、モヤモヤしていることはすべてスッキリ!になる。はず。
ちゃんとプロトタイプしたいならSelfもSlateも勉強になるはず。
「クラスベース」なプロトタイプはjavascriptじゃないかな。といっても、cloneとproto(__proto__はあるけど)がないと落ち着かない人はIoの世界へようこそ
2008/09/04
Symfony で ActionScript(AMF) と通信する
PHP と ActionScript が通信するためのライブラリとして AMFPHP とかが有名ですが、名前空間とかライセンスとか色々な部分が気になるので、SabreAMF を Symfony に乗っけて動かしてみるテスト
ちなみに、既に sfAMFPlugin っていうプラギンも同様のアプローチなのですが、こいつだと README に書いてあるコードが何故か動かないです。
↓こんなの
class amfAMFAction extends sfAction { public function execute($request) { $this->setLayout(false); $gateway = new sfAmfGateway; $response = sfContext::getInstance()->getResponse(); $response->setContent($gateway->service()); return sfView::NONE; } }
上記コードだと、SabreAMF_Server の __construct 中にある
public function __construct() { $data = file_get_contents('php://input'); if (!$data) throw new Exception('No valid AMF request received'); : : :
のコードにて、if(!$data) の評価に失敗して例外となるようです。
詳しい原因は掴んでいないですが、どうも ob_start() が関係している様子(素で通信したときと、上記コードで動かしたときとだと、content-length が結構違うってのも気になりますが...)
function hoge(){ $data = file_get_contents('php://input'); if(!$data) { echo 'hello world'; } else { echo 'no valid'; } } // ob_start(); ob_start(''); hoge(); $result = ob_get_contents(); ob_clean(); assert($result == 'hello world');
タイミングなのかなんなのかわからないですが、ob_start() と ob_start('') の動きが微妙に違うらしい
(てか、似たようなのがあった - IE6でダウンロード - ekurodaの日記)
(中略)
ということで、Controller を作って、そこでやってしまうことにした。
例外処理とかも結構ハンドリングできるようになって便利。
class fmServiceController extends sfFrontWebController { public function forward($moduleName, $actionName, $parameters = array()) { : : // 何か色々書く : $actionInstance = $this->getAction($moduleName, $actionName); : : // もう少し書く : $server = new SabreAMF_CallbackServer; $server->onInvokeService = array($actionInstance, 'service'); $server->exec(); } }
んで、Action とか
class amfAction extends fmServiceAction { public function service($service, $method, $data) { : : // 色々やって : return $results; } }
こんな感じ。
routing.ymlとかはこんな感じでいけるかな
amf_request:
url: /:module/gateway.amf
param: {action: amf}
json_request:
url: /:module/:id.json
param: {action: json}
また、ActionScript 自体はこんなもので試してみました。
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="init()"> <mx:Script> <![CDATA[ import mx.controls.Alert; import mx.collections.ArrayCollection; import mx.rpc.events.ResultEvent; import flash.net.NetConnection; import flash.net.Responder; import flash.net.ObjectEncoding; import mx.utils.ObjectUtil; private function init():void { var connection:NetConnection = new NetConnection; connection.objectEncoding = ObjectEncoding.AMF3; connection.addEventListener(NetStatusEvent.NET_STATUS, function(e:NetStatusEvent):void { trace(ObjectUtil.toString(e)); }); connection.addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void { trace(ObjectUtil.toString(e)); }); connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, function(e:AsyncErrorEvent):void { trace(ObjectUtil.toString(e)); }); connection.connect('http://test.server/service_dev.php/hoge/gateway.amf'); connection.call('HelloWorld.getData', new Responder(onResult, onFault)); connection.close(); } private function onResult(result:Object):void { dataGrid.dataProvider = new ArrayCollection; for(var i:uint = 0; i < result.length; ++i){ dataGrid.dataProvider.addItem({ 'AAA': result[i].AAA, 'BBB': result[i].BBB, 'CCC': result[i].CCC }); } } private function onFault(fault:Object):void { trace(ObjectUtil.toString(fault)); } ]]> </mx:Script> <mx:Panel layout="absolute"> <mx:DataGrid id="dataGrid"> <mx:columns> <mx:DataGridColumn headerText="aaa" dataField="AAA"/> <mx:DataGridColumn headerText="bbb" dataField="BBB"/> <mx:DataGridColumn headerText="ccc" dataField="CCC"/> </mx:columns> </mx:DataGrid> </mx:Panel> </mx:Application>
とりあえず、ob_start 中(?)の php://input 値が取得できるようになるまで、これで進めることにする。
2008/07/26
Io の clone でハマる
clone したときは、init メソッドが呼ばれて、そこで必ず初期化しないとダメだということ
以下のコードだと、オブジェクトの値が clone されるんだね
Hoge := Object clone do( values := List clone with := method(name, c := self clone c values append(name) c ) ) a := Hoge with("a") b := Hoge with("b") a values println ==> list(a, b)
これってつまり js だと、以下のコードと同じってことか。
var Hoge = function (){}; Hoge.prototype = { values: [], with: function(name){ var c = new Hoge c.values.push(name) return c } }; var a = Hoge.prototype.with("a") var b = Hoge.prototype.with("b") print(a.values) ==> (a, b)
ということで、Io のコード及び、js のコードを直すなら、こんな感じになる。
# って基礎中の基礎か
Io
Hoge := Object clone do( init := method( self values := List clone ) with := method(name, c := self clone c values append(name) c ) ) a := Hoge with("a") b := Hoge with("b") a values println ==> a b values println ==> b
js
var Hoge = function (){return this.init.apply(this)}; Hoge.prototype = { init: function (){ this.values = [] }, with: function(name){ var c = new Hoge c.values.push(name) return c } }; var a = Hoge.prototype.with("a") var b = Hoge.prototype.with("b") alert(a.values) ==> a alert(b.values) ==> b
慣れは怖い
2008/07/23
Io で curry, bind を実装する
prototype.js の Function.prototype.curry と Function.prototype.bind が Io にも欲しくなったので、簡単に実装してみた。
ちなみに、Function.prototype.curry は引数のカリー化を行ってくれる関数プロトタイプで、Function.prototype.bind は、スコープのカリー化もしてくれるヤツ(って説明でいいのかな)
Block apply := method(target, args,
args = if(args isNil, list(), args)
target = if(target isNil, scope, target)
self setScope(target)
self performWithArgList("call", args)
)
Block bind := method(
args := call message argsEvaluatedIn(call sender)
target := args at(0)
args = args slice(1)
b := self
return block(
b apply(target, args union(call message argsEvaluatedIn(call sender)))
)
)
Block curry := method(
args := call message argsEvaluatedIn(call sender)
if(args size < 1) then (
return self
)
/*
target := args at(0)
args = args slice(1)
*/
b := self
return block(
b apply(scope, args union(call message argsEvaluatedIn(call sender)))
)
)
まぁ、bindもcurryも同じようなものなので、こんな感じで動かす。
hoge := Object clone do( message := "this is hoge" ) foo := Object clone do( message := "this is foo" ) promp := block(a, b, "#{self message} at #{a}, #{b}" asMutable interpolate println ) promp setScope(hoge) a := promp curry("aaa") a call("bbb") ==> this is hoge at aaa, bbb b := promp bind(foo, "ccc") b call("ddd") ==> this is foo at ccc, ddd
使い道は、これから考える
2008/04/17
jsの arguments.callee で coroutineっぽく。その2
前回書いたモノに至る前に感じていたのですが、arguments.calleeだけでcoroutineっぽい実装をするには、クロージャとか使えばできないかな。ということ
つまり、こんなの
var hoge = function (){ var count = 0; arguments.callee.next = function (){ return count++; }; return function (){ return count--; }; }; var f = hoge(); print(f()); // 0 print(f()); // -1 print(hoge.next()); // -2 print(hoge.next()); // 1 print(hoge.next()); // 0 print(hoge.next()); // 1 print(hoge.next()); // 2
arguments.calleeに実行時にセットできれば、外側から参照することができるハズなので、yieldとかを発行するタイミングのオブジェクトをクロージャで閉じ込めてしまう。と
んで、arguments.callee.nextに格納されたcoroutineはいつかのタイミングで切り替えてしまう。そのいつかはどうやるか
うーん。もう少し。
jsの arguments.callee で coroutineっぽく
js(ECMAScript)のarguments.calleeって関数が実行状態になった時に生成されるものじゃないのかな?ということは、Callオブジェクトだよね。
ref - Arguments Object (ECMA262 10.1.8)
ってことで、関数毎にちゃんとarguments.calleeが作られているか
var hoge = function (a, b){ try { if(arguments.callee.coro != null){ return arguments.callee.coro(); } return a + b; } finally { arguments.callee.coro = function (){ try { if(arguments.callee.coro != null){ return arguments.callee.coro(); } return a * b; } finally { arguments.callee.coro = function (){ return a - b; }; } }; } }; print(hoge(5, 6)); // => 11 print(hoge(5, 6)); // => 30 print(hoge(5, 6)); // => 30 ??
ということで、答えは No っぽい。arguments.calleeはちゃんと生成されて無いっぽい?
というか、このコードの場合、finally 句で arguments.callee が再定義されちゃうか。ロジックが悪い
やるなら、こうかな。
var hoge = function (a, b){ try { if(arguments.callee.coro != null){ return arguments.callee.coro(); } } finally { if(arguments.callee.coro == null){ try { return a + b; } finally { arguments.callee.coro = function (){ try { if(arguments.callee.coro != null){ return arguments.callee.coro(); } } finally { if(arguments.callee.coro == null){ try { return a * b; } finally { arguments.callee.coro = function (){ return a / b; } } } } } } } } }; print(hoge(5, 6)); // => 11 print(hoge(5, 6)); // => 30 print(hoge(5, 6)); // => 0.8333333333333334
きもいwww
でもちゃんと、arguments.callee.coroは関数毎に再定義されてるっぽい。
ま、上記は、何がやりたいかっていうと、coroutineっぽい実装をjsでarguments.calleeに詰め込んでできないかなーって思っただけ。でも、難しい。同じような処理を何度も書かないといけないのだろうか。
ってか、memoizeな実装ならどうやるんだろうか。
2008/02/15
バレンタインにチョコ貰えなかったので、ついカッとなってjojo言語作った。
コーラを飲んだらゲップが出るかのごとく自然にチョコを貰えなかったぜえぇぇぇ。これは最高に「ハイ!」ってやつだぜぇ!
ナシナシナシナシナシナシ!(一個もナシ)
ref - http://labs.s2php5.jp/misc/jojoscript/jojo.html
※ネタが古すぎるし、Fxでしか試してない。しかもBrainf*ckよりもダサイ。後悔は来年する。

前回の続きです
横書きに表示されている文字をタテに表示するというのを挑戦してます。
今回は SVG を利用しているので、ほぼ全てが座標で表現されます。
こんな感じ↓
ブラウザで座標を考える場合 (0, 0) が左上になり、それよりも外側はブラウザの表示の外になります。
そこで、「美しい日本語」という文字列を (0, 0) からレンダリングするとこんな感じになります。
単純に考えれば、この文字列を 90° 垂直に回転 させれば、タテに表示されそうですがそうもいきません。
文字列を (0, 0) にレンダリングしてしまったので、そのまま回転させてしまうと、画面の外に出てしまいます。
ちなみに、SVG の回転は transform(rotate) を使うんですが、rotateの引数に rotate(rangle, cx, cy) と X座標(cx) と Y座標(cy) の回転位置を指定できるので、この引数を使い回転位置を調整します。
これで、回転位置を調整する事で無事表示領域内に文字列をタテに表示できるようになります。
(中略)
ということで、この SVG を使った実装を Figit に実装してみた。(CSSと合わせて左側にくっついてきます)
残念ながら、SVG をサポートしていない IE と 文字の rotate が上手くいかない Opera はちゃんと表示されません...。
Firefox や Webkit系(Safari, Chrome) などはちゃんと↓のように表示されているハズ...。(たぶん iPhone/Androidも大丈夫だと思う)
今回利用したソースは http://figit.net/js/pig.svg.js にもあるけど、ここにも一応書いておこう
ということで、今後とも Figit に色々のっけていきます