JavaScript で CSS を切り替える
jsでcssを切り替える方法
function changeStyleSheet(title) { var linkElements = document.getElementsByTagName('link'); for (var i=0,l=linkElements.length; i<l; i++ ) { var e = linkElements[i]; if(e.getAttribute('rel') == 'alternate stylesheet') { if(e.getAttribute('title') == title) { e.disabled = false; } else { e.disabled = true; } } } }
増田美人時計ブックマークレット
美人時計が流行っているみたいなので、増田*1の時刻表示を美人時計に差し替えるブックマークレットを作ってみた。
増田にアクセスしてから、↓をロケーションバーに貼付けて実行すると時刻表示が美人さんになるよ!
javascript:(function(){var j=0;var bt=[];var elms=document.getElementById('body').getElementsByTagName('p');for(var i in elms) {if(elms[i].className=='sectionfooter'){bt.push(elms[i]);}};function tm() {if(j<bt.length){bt[j].innerHTML=bt[j].innerHTML.replace(/(\d.):(\d.)/,'<img style=\'width:200px\' src=\'http://www.bijint.com/jp/img/photo/$1$2.jpg\' />');j++;}};var k=setInterval(tm,1500)})();
一応、setInterval で1.5秒毎に1画像づつ差し替えてます。
Scribus での pt と mm の関係
Scribus での pt と mm の関係が気になったので調べてみた。
フォントのサイズ指定には pt しか使用できない
- 最近の商業レイアウトソフトでは、フォントのサイズ指定で「級(Q)」が使用できる
- なので、デザイン作業においてフォントサイズは Q で指定する場合が多い
- しかし、Scribus では pt でしか使用できない
- でも、フォントサイズ入力欄に単位つきで入力できる (例)3.25mm
- だが、単位つきで入力した場合でも結局 pt に変換されてしまう。(しかも、小数点第一位以下は切り捨てられる)
- 2.75mm (11Q) と入力すると、7.8pt になる。
ptに変換されてしまっているためか、文字サイズ13Q一行35文字詰めのテキストフレームをつくろうとしてテキストフレームの横幅を 2.75mm * 35 = 96.25mm に指定しても、34文字しか入らない事態に陥る。
どういう計算式なんだ?
ということで、ソースを調べてみました。
scribus-1.3.3.12/scribus/units.cpp より抜粋。
/*! * @brief Returns the ratio to points for the selected unit of measure. Ratios are for: PT, MM, IN, P, CM, C */ const double unitGetRatioFromIndex(const int index) { //PT, MM, IN, P, CM, C (Cicero) //NOTE: Calling functions that divide by this value will crash on divide by 0. They shouldnt be getting // a zero value if they are accessing here with a correct index. if (index<UNITMIN || index>UNITMAX) return 0; double ratio[] = { 1.0, 25.4/72.0, 1.0/72.0, 1.0/12.0, 2.54/72.0, 25.4/72.0/4.512 }; return ratio[index]; } /*! * @brief Returns the mm value from the pt value supplied */ const double pts2mm(double pts) { return pts * unitGetRatioFromIndex(SC_MM); } /*! * @brief Returns the pts value from the mm value supplied */ const double mm2pts(double mm) { return mm / unitGetRatioFromIndex(SC_MM); }
ようするに、mm から pt に変換する際に、 mm / (25.4/72.0)
とやってるみたい。
フォントのサイズ指定は pt でやるのが吉
いろいろためしてみた結論としては、以下のようにやるといいということになった。
- フォントのサイズは pt で指定する (例) 8pt
- 任意の文字詰数におけるテキストフレームの幅を mm で指定したい場合は、まず
フォントのポイント数 * (25.4/72.0) * 文字詰数
という式を使用して mm に変換する (例) 8 * (25.4/72.0) * 35 = 98.7777778 - 変換結果の数字を小数点第3位で四捨五入する (例) 98.778
- 四捨五入した数値をテキストフレームの横幅として指定してあげると、ちゃんと文字数ぴったりでおさまる
Progression を読む その2 - Progression.as コンストラクタ
public function Progression( id:String, stage:Stage = null, rootClass:Class = null )
引数たち
たとえばこんな感じに使う。
prog = new Progression( "index", stage, IndexScene );
で、次にエラー処理3つ。
- 冒頭で定義した定数VERSIONと比較し古いプレーヤーで動いている場合はエラー
- Progression 識別子(id)がすでに登録されていればエラー
- stageが定義されていなければエラー
エラーの送出は jp.nium.core.errors.ErrorMessageConstants クラスを利用している。
idの登録確認には ProgressionCollection クラスの __getInstanceByIdメソッドを使用している。
変数初期化
パッケージ情報を表示した後に、各種変数初期化。
- id
- eventHandlerEnabled を true に
- firstSceneId を取得
- ブラウザのURL(BrowserInterface.locationHref)から senePath を取得
- ブラウザ上でない場所で再生された場合(!BrowserInterface.enabled)は初期値( "/" + id)を使用
表示系を追加
Background を 表示
- _stage.addChildAt( _background, 0 );
一番下になにか配置したい場合は Progression._background.addChild(表示したいなにか); と書けばいいっぽい。- _background は private なクラス変数の為、クラス内からのみ参照可能だから上記のような使用方法はできない。
- 前述したが、_stage や _container は外部から参照する為のセッターが用意されているが、_background はない。
- じゃあ、_background ってなんの為に用意されているんだ??
- Background は CastSprite を継承している
Container を表示
- _stage.addChild( _container );
- Backgroundより上になにかを配置したい場合は progression.container.addChild(表示したいなにか); と書く。
- Container は CastSprite を継承している
SceneManager (調べ中)
KeyboardManager (調べ中)
SyncManager (調べ中)
rootClass 関連
- まず、 rootClass が存在しなければ SceneObject に変換する
rootClass ||= SceneObject;
- rootClass を作成 (インスタンス名 root)
- root が 作成できなかった場合(SceneObject クラスを継承していない場合)はエラーを送出する
- SceneObject のクラス変数 progression_internal::__owner に this を代入する
SceneObject のクラス変数 __owner について
- __owner に Progressionのインスタンスを代入すると _owner にセットされ、SceneObject のコンストラクタで _owner が _progression に代入された後、null が代入される。*1
- SceneObject の _progression は progression で参照できる。
- 要するに、SceneObject 内の progression インスタンス変数経由で“最初に作られた Progressionインスタンス”が参照できる。
ScanManager の root に root を代入する
ProgressionCollectionに登録
- ProgressionCollection の クラス変数 _ids:Dictionary に _id をキーにして this を登録する
- ProgressionCollection の クラス変数 _instances:Dictionary に 登録されたインスタンス数(_numInstances)をキーにして this を登録する
- ProgressionCollection の クラス変数 _nums:Dictionary に this をキーとして登録したインスタンス番号(_numInstances)を登録して、_numInstances++
- ProgressionCollection クラスから CollectionEvent.COLLECTION_UPDATE イベント送出
イベント送出
- SceneEvent.SCENE_ADDED
- SceneEvent.SCENE_ADDED_TO_ROOT
以上、コンストラクタ。
コンストラクタ部分を読んで収穫したもの
一番下になにか配置したい場合は Progression._background.addChild(表示したいなにか); と書けばいいっぽい。- _background は private なクラス変数の為、外部からは参照できない。
- SceneObject 内の progression インスタンス変数経由で“最初に作られた Progressionインスタンス”が参照できる。
つづくかも。
*1:なんで null が代入されるのかは後で調べる
Progression を読む その1 - Progression.as クラス定義
Progression のソースを読んでみる。(バージョンは3.1.2)
Flash CS4 Mac の場合は以下の場所にソースがインストールされる。
~/Application Support/Adobe/Flash CS4/ja/Configuration/Extensions/Progression/Project/files/src/libs_as/jp/progression/
まずは基本っぽい Progression.as を読む。
いきなり 51行目にある謎な記述につまずく。
[Event( name="processStart", type="jp.progression.events.ProcessEvent" )]
調べてみたら AsDoc 用のメタタグみたいです。
参考:Event メタデータタグの使いどころ
ということでいろんなイベントが定義されていました。
- processComplete event
- シーン移動処理が完了した場合に送出されます。
- processError event
- シーン移動処理中に移動先のシーンが存在しなかった場合に送出されます。
- processEvent event
- シーン移動処理中に対象シーンでイベントが発生した場合に送出されます。
- processInterrupt event
- シーン移動処理が停止された場合に送出されます。
- processScene event
- シーン移動処理中に対象シーンが変更された場合に送出されます。
- processStart event
- シーン移動処理が開始された場合に送出されます。
JavaScript の EventListener における this について
Firefox 3 にて検証。
あるオブジェクトに属するメソッド(関数オブジェクト)をイベントリスナーとして登録した場合、その登録の方法によってメソッド内で使用される this の意味が違ってくるよという話。
まずはこんなオブジェクトをつくってみる
// MyEventListener オブジェクト作成 var MyEventListener = function() { return this} // MyEventListener オブジェクトにonMouseClickメソッドを追加 MyEventListener.prototype = { onMouseClick: function() { alert(this); } //←ここの this が今回の主役 } // MyEventListener から myEventListener オブジェクトを作成 var myEventListener = new MyEventListener();
そして、myEventListener.onMouseClick をイベントリスナーとして登録してみる
イベントリスナーとして素直に関数名を表記した場合
アラートには "[object HTMLParagraphElement]" と表示される。
この場合、 this = イベントリスナーが登録されたターゲット 。
var div = getElementById("div"); div.addEventListener("click", myEventListener.onMouseClick, false);
イベントリスナーとして無名関数を使用した場合
アラートには "[object Object]" と表示される。
この場合、 this = イベントリスナーオブジェクト 。
var div = getElementById("div"); div.addEventListener("click", function() { myEventListener.onMouseClick() }, false);
いったん無名関数を間にはさむので this の意味が違ってくるのは当然といえば当然なんだろうけど、注意しないといろいろと面倒なことになりそうなのでメモしておきます。
(追記) Mozilla Developer Center に関連情報が書いてあった
https://developer.mozilla.org/ja/DOM/element.addEventListener
メモリに関する問題
メモリ使用量が増大する問題を引き起こす方法に共通していることは、オブジェクトのメソッドをコールバックとして渡すことです。
setTimeout(obj.func, 1000); // |this| が間違って設定される!
document.addEventListener("load", obj.func, false); // |this| が間違って設定される!単純な回避策としては、無名関数をコールバックとして渡す方法があります。
document.addEventListener("load", function(event) { obj.func(event); }, false);
注意すべきなのは、この無名関数はそれを内包する環境にある全ての変数にアクセスすることができ、それらの変数が使用するメモリは、その無名関数が使われる可能性がある限りは (つまりイベントリスナが登録されている限りは) JavaScript エンジンによって解放されないということです。この関数に対して維持される必要があるのは実際には obj だけなのに、JavaScript エンジンは他の変数も維持する事を選択し、その結果メモリの負荷が増大します。removeEventListener を呼び出すか無名関数への参照を全て削除すれば、変数の消費するメモリが解放されるようになります。なので忘れずにそれを行ない、使用されていないメモリが JavaScript エンジンによって効率的に解放されるようにして下さい。