2015年 10月 04日

DOM の KeyBoardEvent の e.keyCode とか e.which とかを文字列としてとりたいやつ

昔 keyString.js という KeyBoardEvent からなんとなく押されたキーの文字列表記になおすやつを書いたことがある。

しかしこれは実装が不完全で一部のキーがちゃんと判定されなかったりした。が、マルチプラットフォーム・マルチブラウザで検証するような気力はないし、そんなことしても無駄になるのは目に見えているのでやる気はおきない。

KeyBoardEvent.key

KeyBoardEvent に key というプロパティが DOM Level 3 Events ではできることになっていて、これは Enter キーの場合 "Enter" という文字列が入り、物理的なキー位置(ということになっている謎の数値)ではなく、論理的なキーを表現するということになっている。が、全てのブラウザで同じように実装されているとはいえない。

ということで KeyBoardEvent.key には polyfill をつかおう。

https://github.com/inexorabletash/polyfill/blob/master/keyboard.js

を読みこむだけでいい。完璧ではないがおそらく現時点で一番まともだと思う。このファイルにはライセンスが書いてないが polyfill 全体で Public Domain となっており適当に扱っても問題ない。

KeyBoardEvent.key を直接判定に利用するには問題がある

KeyBoardEvent.key は modifierKey (シフトキーとか) の状態は当然含んでいないので、単に

if (e.key === 'Enter') {
}

で判定してしまうと、Shift+Enter や Alt+Enter なども同じもの扱いになってしまう。かといって

if (e.shiftKey && e.key === 'Enter') {
} else
if (e.altKey && e.key === 'Enter') {
} else
if (!e.shiftKey && !e.altKey && e.key === 'Enter') {
}

とか全部書くのは見通しが悪い。

ということでしかたなしに

var key = (e.altKey?"Alt-":"")+(e.ctrlKey?"Control-":"")+(e.metaKey?"Meta-":"")+(e.shiftKey?"Shift-":"")+e.key;   

みたいなのを1行書いて modifier key のプリフィックスをつけておくとやはり楽になる

if (key === 'Shift-Enter') {
} else
if (key === 'Alt-Enter') {
} else
if (key === 'Enter') {
}
2013年 09月 24日

MicroVert アンテナの設計ツール

なんかエクセルで計算できるのがでまわっているっぽいのだけれど、HTML で計算したいので JavaScript で書きなおした。

自分で書いたら欲しい機能増やせるし便利。特に、計算したパラメータから、必要な材料の長さを出したりしたかったので canvas で全体像をレンダリングしている。

コイルも密巻きの場合を簡単に求められるようにしたりした。ただ、細長いコイルはQ値がさがってよくないらしいので低い周波数では調整する必要があるのかもしれない。でもそれでどの程度効率が変わるのかがわからない。

7MHz MicroVert アンテナを制作

φ25mm φ22mm のアルミパイプそれぞれを 1m ずつ買ってきて作った。設計上は 1m + 0.85m で 15cm ほど重ねるイメージ。

コイルを設計通りに巻くのがかなり難しく、はじまりとおわりの処理の仕方がよくわからなくて、これはうまくできたとは言い難い。

7MHz だとカウンターポイズが 8.3m 必要だけど、なんとなく買っておいた 10m の 5D-2V があったので頑張って計って切った。コアは 50MHz 用のコブラアンテナを試作したときのを流用した (12ターン 3D-2V がW1JR巻きで FT240 #44 に巻いてある)

ちなみに、設置ロケーションは給電点地上高 2m 程度で、建物からは 30cm 程度しか離すことができないので全く SWR が落ちないような予感がしていた。やってみなければわからない、と自分を励ましつつやったが、案の定全く下がらなかった。

複素インピーダンスを広域で一覧するとだいぶ下 (6.8MHzヘルツぐらい) に同調しているような感じだったのでエレメントを短くしてみたりしたが、なかなかうまくいかず。

カウンターポイズのはわせかたを変えたり、エレメントの長さを変えたりいろいろ試行錯誤しまくったあげく、7MHz 付近でエレメントは共振しているようだが SWR は下がらない (リアクタンスがないけどインピーダンスの実数が低すぎる)、という状態になったので、カウンターポイズを動かし、ようやく 1.5 程度まで下がった。

インピーダンスが低めに出ていたので、カウンターポイズをできるだけエレメントから離すように置いたら効果があった。

エレメントの長さによっては、特定の周波数 (だいたい6.8MHzぐらい) で SWR が 1.0 程度になったりした一方、7MHz 以上では SWR が下がりきらなかった。たぶんコイルの巻きすぎ?だと思うが、ほどくのが大変面倒なので、一度コイルには手をつけずエレメントだけで調整し、7.000〜7.200MHz、すなわち 7MHz 帯全域で SWR 2.0 以下にできた。最低 SWR 点が 1.5 程度なのがちょっと微妙だけど、とりあえず気にしない。

しかしその後一旦コイルの固定やらで取り外すことにしたので、コイルも1ターン巻き戻して再調整したところ、7.0MHz 付近で SWR 1.1〜1.2 ぐらいまで落とすことができた。もう1ターン戻してもよかったかもしれないが、メインで運用しているのはバンド下限あたりなのでこれでよさそう。

帯域が広いのは事前情報で知ってはいたけど、なんとなく信じていなかったので、設計時に 7MHz をターゲットにしたのがよくなかった。今回の場合 7.1MHz ぐらいをターゲットにして作る (計算上はコイルが1ターン減るだけ) と丁度よかったかもしれない。

制作上思ったこと

  • できれば調整部分は手の届く範囲にすべき
    • 1段目を短めにしたほうが調整しやすい (70cmぐらい?)
  • LCR メータがあったほうがいい (自分は持っていないのでコイルのインダクタンスがどんなものなのか、計算でしか求められない。アナライザーでも一応測れるけど結構ナイーブで値が信用しにくい)
  • アナライザーなしでは調整が困難
    • カウンターポイズを使うアンテナでは必須だと思った
  • マストと固定するため、塩ビパイプのコイルから下側は長めにしたほうがいい

使用感

UHV-6 という 2m 程度の短縮マルチバンドアンテナとの比較しかできないが、今のところ感じるのは以下の通り

  • 信号は UHV-6 と同じか、それより弱く聴こえる
  • SN は UHV-6 より少しよく感じる
    • 特に、7.01MHz 未満では、UHV-6 はなぜかノイズが常時ひどくで聴こえなかったのが、MV で聴こえるようになった。設置位置の関係かもしれない
  • とにかく帯域が広くて 7MHz ならどこにでも出れる。UHV-6 はチューナーなしだと 7.00 から 7.025 ぐらいまでしか出れないので、嬉しい感じ。

ベランダのスペースの関係上、UHV-6 と今回作った MicroVert アンテナは開けている方角が違うので、相手局の位置によって変わりそう。もうすこし耳が良いのを期待したけど、それに関しては少し期待はずれだった。短いアンテナなので、結局その点に関しては短縮ホイップと同じなのかもしれない。

2006年 01月 09日

Opera で addEventListener の最後はできるだけ false に

window.addEventListener("load", initialize, true); って書いていたのだけど、なんかコレだと Opera が4回とか3回とか initialize を実行する。まじワカンネーよーと Opera 糞だよーふぁっきんだよーと嘆きつつ、一切実行しないように書き換えた直後、IRC に該当コードを貼り付けたらひらめいた。そんなわけで truefalse にしたら見事1回だけ実行してくれるように。

ところで initialize って一気にタイプしないと書けない。というか紙に書こうとすると無理 (謎)。それとは別だけど listener って単語がよくゲシュタルト崩壊する。12回に1回ぐらい辞書ひくか動的補完してる。あはは

2005年 12月 10日

NULL::colors*canvas

NUll::colors*canvas, キャンバス使用版

16進数直入力とか欲しかったのでカラーセレクターの部分を分離してひとつクラスかぶせた。インターフェイスは (殆ど) 同じなので特に大変な部分はなく、セレクター部分を作りさえすれば簡単に追加できるように。

  • Triangle の場合ダブルクリックでぐるぐるしなくなるように。微妙に混乱するので。
  • 数値直入力は RGB, HSV の各項目にフォーカスしたあとホイールで増減できるように。
  • プレビューエリアに設定した色 D&D できるように。このためクリックでモード切替はできなくなった。ほかのプレビュー領域と、カラーセレクターへのドロップが可能
2005年 12月 06日

canvas を使った mabinogi 裁縫練習機

NULL::mabinogi:Tailoring むしゃくしゃしてやった。

無駄だなぁ。無駄っていいなぁ。

canvas 使用なので Firefox 1.5 を要求します。

  • タイムリミット
  • 針の大きさ可変
  • 裏を縫うとき点線になるように(というかマビノギの縫い方おかしい気がする)
  • 針の落ちる位置のランダム化

壮絶なスペルミスしてた。

setInterval を使ってもマルチスレッドになるわけじゃないからタイムリミットつけるのは無理くさい。

setInterval でのみ描画させるようにすればいけるか。つまり普通のゲームと同じような Frame ずばば式。

これだとページ開いてる間ずっと重くなるけどなぁ。

タイマー実装。

2005年 12月 05日

canvas が何かに似ている

亀が見えない。

2005年 12月 04日

Canvas を使った gimp like な Triangle Color Selector

Canvas を使った gimp like な Triangle Color Selector

ぐるぐる回ります。透過 PNG 版より正確です。正確さなんてどうでもよさそうですけど。

サイズを初期化時に自由に決められるのはいいっすね。似非 Flash

最初 GIMP の描画関数をそのままやってみたんだけど、さすがに重過ぎて使えなかった。頭悪いのでグラデーション系のメソッドでてきとー描画。で実用レベルに。それでも重くてファンの回転数あがるんだけど。

Canvas 使ってる時点でブラウザ限られるわけですけど、Firefox 1.5 でしか見てないです。

中途半端に prototype.js に依存してます。内部的には依存してないけれど、めんどい部分をてきとーに済ませてある。

円形グラデーションは 360 度を色を変えつつ同じ大きさの円で fill しまくって作ってます。案外きれいにいけた。(ただしループ数というか処理がかなり重いので最初の一度だけ描画)

なんか三角形のグラデーションが偽者っぽい

lighter で合成するようにした。

lighter ってなんか変な気もするんだけど……

ぐるぐるしないほうがいい、と思った。

lighter がおかしいんじゃなくて、darker がおかしいんだ。

ECMAScript メモ

null == undefined; //=> true
null === undefined; //=> false
"1" == 1; //=> true
true == 1; //=> true
new String("aaa") == new String("aaa"); //=> false
String("aaa") == String("aaa"); //=> true
String(new String("aaa")) == String(new String("aaa")); //=> true
typeof (new String("aaa")) //=> "object"
typeof String("aaa") //=> "string"
typeof "aaa" //=> "string"
var aaa = "aaa";
aaa.prop = "aaa";
aaa.prop //=> undefined;
var aaa = new String("aaa");
aaa.prop = "aaa";
aaa.prop //=> "aaa";

nullundefined の関係がちょっと意外だった。true == 1 はキモい。

String 周りがちょっとよくわかってなくて一応いろいろやってみた。別に否直感的ではない感じ。

2005年 12月 02日

ECMAScript での var

前に書いた気がするけど、ECMAScript の var は Io の setSlot に似ている。

var foo; と書くと、既存のスコープの変数オブジェクトのプロパティに foo が作られる。そして foo = "1"; を書くと、スコープチェインの最初に、作られた foo プロパティを発見するため、そこに代入される。

一方 foo = "1";var 無しにいきなり書いた場合、スコープチェインの末 Global オブジェクトにいきつき Global オブジェクトのプロパティに新たに勝手に foo が作られて代入される。

// Global Code の開始
// Scope Chain: [Global]
// Variable Object: Global
//----
// Variable Object (Global)
// のプロパティ foo に "foo" が代入される。
var foo = "foo";
// 上に同じ
var bar = "bar";
function foobar() {
// Function Code の開始
// 新たに Activation Object (=このコンテキストでのVariable Object) が作られる。
//   (このとき arguments プロパティが自動的にセットされる。)
// Scope Chain: [foobarActivationObj, Global]
//     foobarActivationObj は仮の名前で実際にはアクセスできない。
// Variable Object: foobarActivationObj
// Variable Object (foobarActivationObj)
// のプロパティ foo に "fbfb" が代入される。
var foo = "fbfb";
// Identifier があると Scope Chain を辿る。
// この場合最初の foobarActivationObj に foo を発見できる。
foo = "bfbf";
// この場合最初の foobarActivationObj に bar を発見できないため
// Scope Chain を辿り、Global で bar を発見する。
bar = "bzbz";
// この場合 Scope Chain をたどって、Global に行き着いても発見できないため
// 勝手に Global に baz プロパティを作る。
baz = "baz";
baz.foo = "foo";
with (baz) {
// with は Scope Chain の先頭に
// 指定オブジェクトを突っ込む
// Scope Chain : [baz, foobarActivationObj, Global]
foo = "bar";
// Variable Object は変わらない
var f = "!!!";
}
baz.foo; //=> "bar"
baz.f //=> undefined
f; //=> "!!!"
}
foobar();
foo; //=> "foo" 最初にグローバルで代入したまま
bar; //=> "bzbz" 書き換えられている
baz; //=> "baz" グローバルで一切でてきていないのに存在する

Io の場合 = (updateSlot) はスコープチェインに Identifier を発見できない場合例外が発生する。現在の変数オブジェクトのスロットに突っ込むときは := (setSlot) を使用する。Io は明確な決まりがあるんだけど、ECMAScript は曖昧。気が付くと Global オブジェクトにプロパティがだらだらできたりする。

微妙にわかりにくいのは、Global Code においての Variable Object が Global で、変数に this.foo というようにアクセスできるのに対し、Function Code の Variable Object には一切触れないこと

ときどき関数中で var a = b = c = 0; って書いているのを見かけるけど、この場合の b, c は Global オブジェクトのプロパティ (または途中であるならその変数オブジェクトのプロパティ) になる。var a, b, c; a = b = c = 0; とか書くのが正解。

Prototype Chain もそうだけど、「見えないオブジェクト」がいくつかあってなかなか怖い。

2005年 11月 30日

prototype.js .inspect $H()

$H()inspect() の組み合わせが微妙に便利だ。普通の object って toString() しても [object Object] とかになって中身がわからんから、$H(obj).inspect() とかやると中身が見れて便利。

Object.prototype.p = function () {
var t = Object.inspect(this);
if (t == "[object Object]")
t = $H(this).inspect().replace(/^#<Hash/, "#<Object");
if (navigator.userAgent.match(/Firefox/)) {
window.dump(t + "\n");
} else {
window.status = t;
}
return this;
};
({aa:"aabb"}).p().aa.p().replace(/^a/, "b").p();
//=> #<Object:{'aa': 'aa'}>
//   'aabb'
//   'babb'