2011年12月3日土曜日

TwitterのTimeLineを簡易記録するWebブラウザ動作のTwitterクライアント作りました

TLRecという名前の、ChromeとSafari(iOSのではなくMac OS Xの)とFirefoxで動作する、Twitterクライアントを作りました。
(2011/12/16: Firefox対応)

TLRec - Personal TimeLine Recorder -

TLRecは自分のTimeLine(Home、Mention、List、Search)を日時指定予約して記録し、あとで再生できます。実況TL参加したかったのに「その時間会社だから無理」「深夜起きてらんない」「ニチアサ寝坊した…」なんてことがある人で、自宅はPC基本立ち上げっぱなし、みたいな人向けです。


時間とTLを指定して予約しておけばサーバー側で勝手にログ取っておいてくれると思った?残念さやかちゃんでしたー!のではなく、サーバー側はそういうことしません。TLの記録をするにはPCがネットワークに接続していること、ブラウザでTLRecにSign in後のサイトを開いていること(最小化しててもOK)が必要です。あ。PCの時刻設定にしたがって記録開始・終了を行うので、時間ずらしてる場合はそれを考慮して予約するか、PCの時刻設定直すか、してください。


要するに、ユーザー側環境で記録を行います。


ブラウザのlocalStorage機能を利用してTLを保存します。そのPCのそのブラウザ、にしかTLデータは残りません。サーバー側にはデータは残りません。共用PC等での利用はあまりオススメしません。そういう仕様なので、記録したTLの再生を行うには、記録したPC、ブラウザで、TLRecにSign inすることが必要です。

ちなみにTL再生中にツイートすると、その当時にツイートしたかのように表示します。そして、Twitterへ実際に投稿するか気分だけの偽ポストか選べます。基本は偽です。実況参加してる風ではあるけれど、リアルTLは違う流れですので。


localStorage容量はブラウザ仕様上たぶん5MBです。何ツイートぶんくらいか前に計算したけど忘れました。いっぱいになったらTL記録できませんので、適宜記録済みTL削除してください。んでもってそんな容量を鑑みて、予約・記録保持できるTLは3つまでです。


記録は見えないところで行われますので、その間普通に他のTLみたりできます。もちろんPostも。ただあまりアレコレやりすぎるとAPIアクセス制限値を越えてしまい、記録のためのTL取得もできなくなるので、ご注意ください。

記録以外の普通のTL閲覧では、90秒で表示中のTL自動更新です。ただしMentionは除く。Mentionは表示してなくても180秒に1度、新着あるか確認します。


DMはめんどいのでサポートしてません。

安定性に難、TL取りこぼし等あるかもしれませんが許してください。
万年ベータ版です、きっと。


TLRecは @piyotori の「"ニチアサ"実況にリアルタイムになかなか参加できないけれどあとで録画見るときに実況を楽しみたい」という動機で作ってます。

更新情報等は @tlrec_info でツイートすると思います。
そのうちFirefox対応くらいはしたいと考えてます。→対応しました(2011/12/16)

2011年4月18日月曜日

CSS桜ひらひらはこうして作りました

都内の桜ももう散りましたね。

先月、jsdo.itというJavascript, HTML5, CSSをブラウザ上でコード書いて共有できるサイトに、桜の花びらが舞うCSSアニメーションのコードをアップしました(Webkitブラウザ限定ですが)。

さーくらー ひらーひらー - jsdo.it

これのbookmarklet版のコードも公開してます。
桜ひらひらbookmarklet - jsdo.it

今SafariかChromeを利用している方なら、下記のリンクをクリックすればこのページ内を桜の花びらが舞います。

桜ひらひらbookmarklet

これをどうやって実現しているか今日は書きたいと思います。
まあ僕がやることはいつもたいしたことじゃありません。多少手間がかかることをちまちまやってるだけです。


■花びら
まず花びら。半分ずつ作ります。
下の画像はdivを加工していく過程で、左から右にどんどん適用style増えていきます。(見やすさのために実際の2倍の大きさにしてます)


左端は、width: 9px, height: 6px のdivを作りまして、position: absolute にしておき、そしてborder-radius: 6px 0px 0px 0px として左上だけ丸めた状態です。
次に -webkit-transform: skew(-30deg) でちょっと歪めてます。
さらに、-webkit-transform: skew(-30deg) scale(1.2, 1)で横方向1.2倍、縦方向1倍、要するに横にちょびっと引き伸ばします。
さらにさらに、-webkit-transform: skew(-30deg) scale(1.2, 1) rotate(12deg) で少し傾けます。
これに background: -webkit-gradient(linear, left top, right bottom, from(rgba(224, 176, 192, 1)), to(rgba(255, 240, 240, 1))) で色着けます。
見やすさのために付けてたborder外したのが一番右の画像。
これを左半分とします。

同じようにもう半分を作りますが、skewとscaleの縦方向の値の符号を反転したものを作ってあげます。
width: 9px, height: 6px, position: absolute, border-radius: 6px 0px 0px 0px のdivは同じですが、 -webkit-transform: skew(30deg) scale(1.2, -1) rotate(12deg) とします。色もグラデの向きがちょっと違い、 background: -webkit-gradient(linear, left bottom, right top, from(rgba(224, 176, 192, 1)), to(rgba(255, 240, 240, 1))) です。まあこの辺は、向きとか形とか実際に確認しながらやってます。



これら半分ずつを合わせて1枚の花びらにしたいので、同じdivの中に2つを入れます。
position: absoluteが効いてて見事に重なってくれてますので、少し位置を合わせるために、下半分の div を top: 4px 指定します。
これに色着けた状態でborder外したのが左から3番目のものです。
見やすさのために倍の大きさにしてますが、本来の大きさは一番右のものです。



さて、ここまでを整理して、style設定をいくつかのclassに分けて、divで花びら作るhtmlはこうなります。

コード:
<style type="text/css">
/* 花びら(parent) */
.petal {
width: 15px;
height: 10px;
}

/* 花びらの半分基礎 */
.petalBase {
border-radius: 6px 0px 0px 0px;
position: absolute;
top: 0px;
left: 3px;
width: 9px;
height: 6px;
}

/* 花びらの左半分になるところ */
.petalLeft {
background: -webkit-gradient(
linear, left top, right bottom,
from(rgba(224, 176, 192, 1)),
to(rgba(255, 240, 240, 1))
);
-webkit-transform: skew(-30deg) scale(1.2, 1) rotate(12deg);
}

/* 花びらの右半分になるところ */
.petalRight {
top: 4px;
background: -webkit-gradient(
linear, left bottom, right top,
from(rgba(224, 176, 192, 1)),
to(rgba(255, 240, 240, 1))
);
-webkit-transform: skew(30deg) scale(1.2, -1) rotate(12deg);
}
</style>


<div class="petal">
<div class="petalBase petalLeft"></div>
<div class="petalBase petalRight"></div>
</div>



■花びら回転
花びらを回転させましょう。
さきほど花びらを作ったとき、半花びら2つを内包する親divを作りましたので、そいつをCSSアニメーションで動かせばいいのです。
アニメーションの設定はこんな感じで、まずは3D-X回転のみです。

コード:
<style type="text/css">
/* 花びら回転 */
.petalRotate {
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
-webkit-animation-duration: 1s;
-webkit-animation-name: rotateX;
}

@-webkit-keyframes rotateX {
0% {-webkit-transform: rotate(0deg) rotateX(0deg);}
100% {-webkit-transform: rotate(0deg) rotateX(360deg);}
}
</style>


<div class="petal petalRotate">
<div class="petalBase petalLeft"></div>
<div class="petalBase petalRight"></div>
</div>


petalRotateクラスではアニメーションは終わりなしの無限Loop、動作の加速度はリニア、アニメーション1回にかかる時間は1秒、アニメーションの細かい設定名はrotateX、という指定です。
keyフレームは、アニメーションがn%進んだ位置でのアニメーションしたい属性とその値を書きます。間の値は補完されます。今回はwebkit-transformで2次元の回転(rotate)と3次元縦方向回転(rotateX)を指定して、rotateは値変えてないので実質アニメーションしませんが、3D縦方向は1sでくるくるします。

このアニメーション設定クラスpetalRotateを親divのclassに追加すればくるくるしだします。rotateは後で使います。
(すいません、実サンプル載せてなくて。)


■花びらの移動
回転できたら回転する花びらを移動させたいところです。ひらひら舞い落ちるんで。
しかし回転のアニメーションは1sです。一緒のclassに移動するアニメーション設定まで突っ込んだら、1sで移動開始点から終了点まで動くことになり、風情がない落ち方になります。

「ねぇ、知ってる?秒速5センチなんだって。桜の花の落ちるスピード。」

ということで、回転とは独立したアニメーションを設定したいわけですが、そのために「回転する花びら」をdivで囲んで、そいつにアニメーションを適用します。
花びらの構造がこんなふうになるわけです。
<div class="parentPetal petalTrans"> <!-- 移動アニメーション用-->
<div class="petal petalRotate"> <!-- 回転アニメーション用 -->
<div class="petalBase petalLeft"></div> <!-- 花びら半分A -->
<div class="petalBase petalRight"></div> <!-- 花びら半分B -->
</div>
</div>


CSS含むコードはこんな感じ:
<style type="text/css">
/* 花びら(parent) */
.petal {
width: 15px;
height: 10px;
}

/* 花びらの半分基礎 */
.petalBase {
border-radius: 6px 0px 0px 0px;
position: absolute;
top: 0px;
left: 3px;
width: 9px;
height: 6px;
}

/* 花びらの左半分になるところ */
.petalLeft {
background: -webkit-gradient(
linear, left top, right bottom,
from(rgba(224, 176, 192, 1)),
to(rgba(255, 240, 240, 1))
);
-webkit-transform: skew(-30deg) scale(1.2, 1) rotate(12deg);
}

/* 花びらの右半分になるところ */
.petalRight {
top: 4px;
background: -webkit-gradient(
linear, left bottom, right top,
from(rgba(224, 176, 192, 1)),
to(rgba(255, 240, 240, 1))
);
-webkit-transform: skew(30deg) scale(1.2, -1) rotate(12deg);
}

/* 花びら回転 */
.petalRotate {
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
-webkit-animation-duration: 1s;
-webkit-animation-name: rotateX;
}

@-webkit-keyframes rotateX {
0% {-webkit-transform: rotate(-58deg) rotateX(0deg);}
100% {-webkit-transform: rotate(-58deg) rotateX(360deg);}
}

/* 花びら移動 */
.animationArea {
position: relative;
overflow: hidden;
width: 640px;
height: 640px;
border: 1px solid red;
}

/* 移動アニメ適用div */
.parentPetal {
position: absolute;
}

/* 花びら落下 */
.petalTrans {
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
-webkit-animation-duration: 10s;
-webkit-animation-name: transPetal;
}

@-webkit-keyframes transPetal {
0% {top: -5%; left: 90%;}
5% {top: -5%; left: 90%;}
95% {top: 105%; left: 10%;}
100% {top: 105%; left: 10%;}
}
</style>


<div class="animationArea">
<div class="parentPetal petalTrans">
<div class="petal petalRotate">
<div class="petalBase petalLeft"></div>
<div class="petalBase petalRight"></div>
</div>
</div>
</div>


ひらひらアニメーションする「エリア」を設けるために、さらに親divをひとつ作ってます。この領域内を花びらが舞い、領域の外では見えなくなるようにするために、overflow:
hiddenです。実際のjsdo.itのコードではこの領域をJavaScriptで画面いっぱいになるようにブラウザ幅等取得して調整してます。

移動アニメーション適用のためのdivにもposition:
absolute指定付けときます。そしてアニメーションさせるstyleとして、positionのtop, leftを用います。

アニメーション時間は10秒間にしました。視界の外から入って外に出て行く、ために、top: -5% 位置から入って、top:
105%位置に抜けてるようにしてます。leftは90%からスタートして10%位置へ。右上から入って左下に抜ける道筋になります。

アニメーション進行時間の0-5%、95-100%が同じ位置です。これは、実際のアニメーションは5-95%の間で、前後は画面外で静止しているようにしてます。次から次へと同じルート上を落ちてくるとせわしないかな、ということで、ちょっとしたWaitが入ってるようなもんです。

ついでに、ちゃっかり回転の方のアニメーション設定の、rotate(rotateXではない)を -58 deg
に設定しています。これは花びらの落ちるコースの角度に合わせたもので、topとleftの移動距離を使ってatan(アークタンジェント)で計算して出せます。


■ひらひら
ここまでは花びら1枚の、作成方法とアニメーションの設定について書きました。
複数の花びらがひらひら舞うようにするには、JavaScript使って花びらの量産し、その1枚ずつにそれぞれ回転・道筋のアニメーション設定、をしています。
このあたりはJavaScriptの説明になりさらに長くなるので、詳細は割愛しますが、ざっと以下のような手順です。
  1. 花びら1枚ずつにid振って、たくさん作ります(jsdo.itのコードでは48枚)
    回転用divと移動用divにそれぞれid振ります。
  2. それをアニメーション領域のdivの子として追加します
  3. アニメーション設定(回転と道筋)をJavaScriptで48個分書き出します
    まず先に道筋を、topは-5%スタートの105%エンドで固定で、leftを、スタートは20-150%くらいの範囲、エンドを0-130%くらいの範囲で、乱数用いて決定します。
    これでアニメーション領域の幅(px数)と%で、縦横の移動距離わかるので、atan使って、花びらのコースに沿った角度を求めて、回転の方のアニメーション設定に活かします。
    (今回は面倒だったので、これらを<style>に生テキストとして突っ込んでます)
    この段階ではまだアニメーションしてません。
    まだkeyframeを用意しただけで、それぞれの花びらに対して、-webkit-animation-なんとか、のstyleを適用してません。
  4. すべての花びらのアニメーション時間設定を、これも多少のバリエーション持たせたstyleを用意します。
    回転は0.8s - 1.2s、移動は9 -13sの範囲からランダムに設定されます。これで他よりややゆったり落ちる花びら、他より多めにくるくる回ってる花びら、などが生まれます。道筋も、基本的に右上方面から左下方面、ってだけで角度はバリエーションありますので、1枚ずつは同じ道筋・回転の速さでループしていても、複数枚が舞うことで、すぐには飽きないようにというのを狙ってます。
  5. 最後にすべての花びらに生成したstyleを適用します。


最初の方にも書きましたが、やってることは別に難しいことでもなんでもなくて、ちまちまと多少面倒なことを積み重ねているだけです。
もし気になることなどあれば、jsdo.itの方には質問等かくとこあるので、そちらへ。

2011年4月15日金曜日

icotileのロゴデザインをしました -icotile のどのあたりが HTML5 なのか? 番外編-

少し前に、icotile(http://icotile.ogaoga.org/)のロゴデザインやその他機能の実装等をやりました。おかげさまでicotile、「第 0 回 HTML5 プログラミング&クリエイティブ・コンテスト」にて優秀作品賞をいただきました
(って書くと作成し終わったかのようですが、icotile自体は今もまだアップデート続いてます)

icotileとは:
Twitter のフォローしている人/されている人やリストを iTunes のような操作感で管理でき、また各ユーザーに対して自分だけのメモも残せる Web アプリケーション。Developed by @ogaoga / Designed by @piyotori
ということですが、僕はCSS3まわりやビジュアル的なデザイン面以外でも普通にJavaScriptのロジック部分も書いたりしてますし、むしろogaogaさんが総合的な意味でデザインやってたりします。


さて、icotile企画者にてUI含めほとんどの部分を作ったogaogaさんが、「icotile のどのあたりが HTML5 なのか? #html5j」を書いてます。その中でCSS3まわりについては piyotori がそのうち書くでしょう、って振られてたのですが、なかなか書けずにいましたが、重い腰を上げて書くことにします。


が、CSS3じゃなくてまずはロゴデザインの話します (キリッ


まず最初に書いておきますが、僕はデザイナーを生業とするものではありません。普段はhtml5はもとよりデザインもWebも関係ないような仕事をしています。ので、そんな風にデザインやってんのかよ的なところ多々あると思いますが、ご容赦ください。

初めに。icotile一緒に作りましょうという話をogaogaさんからいただいのたのが今年1月中旬くらいで、html5コンテストは2/10締め切り。あまり期間がない(ある方か?)けれども、ロゴだけでもまずはなんとしてでも作らねば状態でした。が、Webサービスのコンセプトを聞いた後、さらにはロゴこんな感じと、既存フォントで作ったイメージも提供いただいたので、イメージを掴みやすかったです。

そのときいただいたロゴイメージ:


このイメージと、「icotile」という名前がそもそも「アイコンがタイル上に並ぶ」ことに由来していることから、I, C, O, T, I, L, Eのアルファベットを1文字ずつタイルに描かれた文字みたいに並べてロゴにしようと思いました。
で、iPadですらすらっとお絵描きしてみたのがこれ。
…と思ったらあれ?画像がない。だいぶ前に消しちゃったっぽい。
すいません。
なかったことにして話を進めますが、ラフな絵を描いた段階で頭の中では、タイルの1辺を a pxとして、文字の幅は a/4 pxで、カッチリ計算したフォントみたいなの作ろうと思ってました。


で、計算により描画する、ということで、はいここでhtml5のcanvasです。強引。


っつーわけで僕は canvas 使って ロゴに使う1文字ずつの画像を作成することにしました。

まず正方形のcanvas を用意し、1辺のpxを指定して、そこからすべて計算により図形を描画して文字を作っていきます。
簡単な I を例にすると、仮に1辺が120pxだとして、下図のような、緑の点を基点とした、横幅が 120/4 = 30、高さが120 の長方形描けばいいのです。


緑の点の座標は、まずXは、canvasのセンターが120 / 2 = 60なので、そこから文字幅 120 / 4 = 30をさらに 2 で割った値をマイナスしてあげた、X=45、Yはcanvasの一番上なので0、となります。

JavaScriptはこんな感じ。
    var cnvs = document.createElement("canvas");
cnvs.width = 120;
cnvs.height = 120;
cnvs.id = "id_cnvs_I"
$("body").append(cnvs);

var ctx = document.getElementById("id_cnvs_I").getContext('2d');
ctx.fillStyle = "black";
ctx.fillRect(45, 0, 30, 120);

これで、120x120のcanvasの真ん中に棒が一本みたいなのができます。

でもこれだとカッチリカクカクな棒なので、角丸になるように、半径 r の円弧を使って角丸boxを書く関数を用意します。これはこちらの記事を参考にさせていただきました。

[javascript]canvasで円や角丸の矩形を描画する - 週末ラボ

これでこんな「I」の文字ができます(外枠は本当はありません)。


この文字を一回り大きいサイズの角丸四角で囲みたくなります。「タイル」をイメージするんで。

しかし。僕自身このエントリで書いてるようにロゴ文字を作っていったので、さて外枠描画しようかなってときに、canvasサイズ小さいじゃん!ってなりました。まあいろいろな対応が考えられますが、とりあえずcanvasをひとまわり大きいサイズにするにはしますが、こんな手順で外枠付けました。

0.例では120x120のcanvasだったが128x128のcanvasを最初に用意することにする(外枠マージン上下左右4pxずつ)
1.外枠のマージン分canvasを移動させて文字を描画する
2.canvasを大きくする前と同じままのコードで文字を描画する
3.外枠のマージン分移動したcanvasを元に戻す
4.外枠描く

「canvasの移動」には translate を使います。translateはちょっと混乱しますが、画用紙にひたすら同じ図形を描いているロボットアームがあったとして、画用紙をずらしたらずれた位置に同じ図形描きますよねってのをイメージしていただくとよいかと思います。
実際に I を描いてさらに外枠付けるコードはこんな感じです。
    var cnvs = document.createElement("canvas");
cnvs.width = 128;
cnvs.height = 128;
cnvs.id = "id_cnvs_1"
$("#font_draw_area").append(cnvs);

var ctx = document.getElementById("id_cnvs_1").getContext('2d');
ctx.fillStyle = "black";

pi = Math.PI;
/* 角丸boxパス作成 */
var makeRoundRectPath = function(ctx, x, y, w, h, r){
ctx.beginPath();
ctx.arc(x + r, y + r, r, - pi, - 0.5 * pi, false);
ctx.arc(x + w - r, y + r, r, - 0.5 * pi, 0, false);
ctx.arc(x + w - r, y + h - r, r, 0, 0.5 * pi, false);
ctx.arc(x + r, y + h - r, r, 0.5 * pi, pi, false);
ctx.closePath();
}

/* 文字描画 */
ctx.translate(4, 4); /* canvas移動 */
makeRoundRectPath(ctx, (120 / 2) - (30 / 2), 0, 30, 120, 6);
ctx.fill();
ctx.translate(-4, -4); /* canvas移動戻す */

/* 外枠描画 */
ctx.strokeStyle = "black";
makeRoundRectPath(ctx, 0, 0, 128, 128, 6);
ctx.stroke();

/* 画像オブジェクトに */
var imgObj = new Image(128, 128);
var imgSrcData = document.getElementById("id_cnvs_1").toDataURL("image/png");
imgObj.src = imgSrcData;
$("body").append(imgObj);
$("#id_cnvs_1").remove();
最後の方が妙なことやってますが、後で説明します。
これで、以下のような I の画像ができあがります。


今回説明する都合上単純化しており外枠はstrokeで済ませました。でも実際にはroundRectをさらに改造したもの、を組み合わせて、外枠描画するようにしてます。


「I」は簡単でしたが「T」はどうでしょうか。

まず横棒(X=0, Y=0, W=120, H=30の長方形)と縦棒(X=45, Y=0, W=30,
H=120の長方形)を描画します。(わざと半透明色にしてます)


これでもいいのですが、Tの「脇」が気になります。以下の赤いところ。


今回はここも丸みを持たせるデザインにしようと思います。そこで、角丸boxの外側を描画する関数を用意します。下図のようなイメージで、指定した領域(うす緑)の4つの角を描画するものです。


実際には、どこの角を塗るか指定するMaskもつけて、こんな感じの作りました。

/* 角丸Outerパス作成 */
// mask: bit3=lefttop, bit2=righttop, bit1=rightbottom, bit0=leftbottom
function makeRoundRectOuterPath(ctx, x, y, w, h, r, mask){
ctx.beginPath();
if(mask & 0x08){
ctx.moveTo(x, y);
ctx.arc(x + r, y + r, r, - pi, - 0.5 * pi, false);
ctx.lineTo(x, y);
ctx.lineTo(x, y + r);
}

if(mask & 0x04){
ctx.moveTo(x + w - r, y);
ctx.arc(x + w - r, y + r, r, - 0.5 * pi, 0, false);
ctx.lineTo(x + w, y);
ctx.lineTo(x + w - r, y);
}

if(mask & 0x02){
ctx.moveTo(x + w, y + h - r);
ctx.arc(x + w - r, y + h - r, r, 0, 0.5 * pi, false);
ctx.lineTo(x + w, y + h);
ctx.lineTo(x + w, y + h - r);
}

if(mask & 0x01){
ctx.moveTo(x + r, y + h);
ctx.arc(x + r, y + h - r, r, 0.5 * pi, pi, false);
ctx.lineTo(x, y + h);
ctx.lineTo(x + r, y + h);
}
ctx.closePath();
}
これで両脇を丸くしてやってTができます(外枠付与前)。



こんな感じで残りの、C、O、L、Eも一文字ずつちまちまと計算しながらデザインしました。
Eは、真ん中の横棒を浮かせるか根元に付けるか試して、最終的には浮かせることにしました。




さて、こんな風にすべてcanvasで描画できるのなら、そのままサイトに組み込んでしまえ、と最初はやりました。
canvasそのまま組み込んでもいいのですが、canvas上の描画された絵をimageとして使いたいので、「I」の字描画コードの最後でしてたようなことをやります。

しかし、ロゴというなるべく早く読み込まれて然るべきもの(と思う)をこんな処理してるのもどうかと思ったので、そうやって作った画像を名前をつけて保存してサーバにアップして画像として最初から読み込むようになってます。


こうして1文字ずつの画像はできましたが、今のicotileのsign in後に右上に出てるロゴなんかは、7文字繋がった1枚の画像になってます。
それもcanvas利用して作成してます。
 1.文字の画像をcanvasで描画
 2.image objectに
 3.横長canvasに2のobjectを適切な座標に読み込む
 4.1~3を ICOTILE ぶん繰り返す
 5.横長canvasを image object にして 最後はブラウザ上から「名前を付けて保存」
で、作ってます。

実際のものとは違いますが、たとえば上で作成した「I」の字を128pxじゃなくて36px版にして、7文字連結するコードはこうなります。
    var cnvs = document.createElement("canvas");
cnvs.width = 36;
cnvs.height = 36;
$("body").append(cnvs);

var ctx = cnvs.getContext('2d');

pi = Math.PI;
/* 角丸boxパス作成 */
var makeRoundRectPath = function(ctx, x, y, w, h, r){
ctx.beginPath();
ctx.arc(x + r, y + r, r, - pi, - 0.5 * pi, false);
ctx.arc(x + w - r, y + r, r, - 0.5 * pi, 0, false);
ctx.arc(x + w - r, y + h - r, r, 0, 0.5 * pi, false);
ctx.arc(x + r, y + h - r, r, 0.5 * pi, pi, false);
ctx.closePath();
}

/* 文字描画 */
ctx.translate(2, 2); /* canvas移動 */
makeRoundRectPath(ctx, 12, 0, 8, 32, 2);
ctx.fill();
ctx.translate(-2, -2); /* canvas移動戻す */

/* 外枠描画 */
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
makeRoundRectPath(ctx, 0, 0, 36, 36, 4);
ctx.stroke();

/* 画像オブジェクトに */
var imgObj = new Image(36, 36);
var imgSrcData = cnvs.toDataURL("image/png");
imgObj.src = imgSrcData;
$("body").append(imgObj);
$(cnvs).remove();

/* 横長canvas */
var cnvs = document.createElement("canvas");
cnvs.width = (36 * 7) + 6;
cnvs.height = 36;
$("body").append(cnvs);

ctx = cnvs.getContext('2d');

/* imageをcanvas上の指定位置に読み込む x 7回 */
for(var i = 0; i < 7; i++){
var x = (36 + 1) * i;
var y = 0;
ctx.drawImage(imgObj, x, y);
}
$(imgObj).remove();

/* 画像オブジェクトに */
var imgObj = new Image((36 * 7) + 6, 36);
var imgSrcData = cnvs.toDataURL("image/png");
imgObj.src = imgSrcData;
$("body").append(imgObj);
$(cnvs).remove();
これで258x36の右クリック保存可能なlogo画像ができました。


だいたいこのようにしてicotileの(sign in後の)ロゴ画像は作られました。
実際には、タイルの1辺のサイズを指定すればあとは各文字の描画位置を比率で計算してすべて描画されるようにスクリプトは書いています。
※canvas上に描く図形の座標がキリがいい数字になる(ことが多くなる)ように設計されてないと、意に反したクオリティの画像になる場合があります。

(sign in前のページのロゴ(Tの字がくるくるするやつ)の話は、またicotileのどこがhtml5か -CSS3アニメ編-としてでも書こうと思います)



まあ何面倒なことやってんだってことでもあるのですが、開発段階ではcanvasそのまんまでサイトに組み込んでみることで、文字の色とかサイズとか微調整だとかやりながら、デザインも行えてしまうという、(若干こじつけの)メリットがあります。
また、ブラウザとテキストエディタがあればデザインが行えるというメリットもあります。イラレやフォトショなどなくてもいいのです。

というわけで、「icotile のどのあたりが HTML5 なのか?」の番外編として、ロゴデザインワークが実はcanvasにて行われていた、というお話でした。


番外編な上にさらに番外:
勢い余って、ICOTILEフォントっぽいもの、作りました。すべての文字のための関数用意するのは時間かかりました。
そして案の定、使いどころないです。

2011年3月3日木曜日

Firefoxで display: -moz-box 指定が効かないときの回避策

CSS3では、3カラムレイアウトなんかが簡単にできる、子要素が横並びに並んでくれるdisplay: boxってのがあります。

参考サイト: CSS3 でのレイアウトで使える box 系プロパティのまとめ | CSS Lecture

例えばこんなCSS指定とタグを書くと、
<style>
#container {
width: 100%;
display: -webkit-box;
display: -moz-box;
}

#left {
border:1px solid red;
width: 100px;
}

#center {
border:1px solid green;
-moz-box-flex: 1;
-webkit-box-flex: 1;
}

#right {
border:1px solid blue;
width: 150px;
}
</style>

<div id="container">
<div id="left">left</div>
<div id="center">center</div>
<div id="right">right</div>
</div>

対応ブラウザでは以下のようになるわけです(生でタグ書いてるので対応してればきれいに横並びになってるはずです)。


left

center

right



しかし、これがFirefoxでうまくいかないときがあります。
次のように、親要素にposition指定をしてみます。メニューバーをdisplay: boxで作ってposition: fixedで、なんて使い方とかあると思います。

上で出した例の#containerにposition: fixedを入れてみます。
#container {
width: 100%;
position: fixed; /* add */
display: -webkit-box;
display: -moz-box;
}


すると、先ほどは横に揃っていた子要素達が、Firefoxではこうなります(今度は生タグじゃなくて画像)。

SafariやChromeの場合、横並びのままなんですが、Firefoxだとdisplay: -moz-boxが効いてません。

理由はわかりませんが、Firefoxでは親要素(「僕の子らは同じ1つのbox(すなわち親である私)内に収まりますよ」と指定しているやつ=本エントリでは"id=container")にrelative以外のposition指定をすると、boxとして揃ってくれません。Firefox 3.6.14でも、Firefox 4 beta2でも、この現象はでます。

これを回避するには問題となってるposition指定を外すことです。でもそれだと本来のposition(fixedとかabsoluteとかで指定したかった位置)が意味なくなります。
そこで、こんな風にさらに親要素をひとつつけてやって、それにpositionの役割を果たしてもらうことで、うまくいくようになります。


<style>
#parentBox {
position: fixed;
}

#container {
width: 100%;
display: -webkit-box;
display: -moz-box;
}

#left {
border:1px solid red;
width: 100px;
}

#center {
border:1px solid green;
-moz-box-flex: 1;
-webkit-box-flex: 1;
}

#right {
border:1px solid blue;
width: 150px;
}
</style>

<div id="parentBox">
<div id="container">
<div id="left">left</div>
<div id="center">center</div>
<div id="right">right</div>
</div>
</div>


…で済めばいいんですが、サイトのデザインによっては、さらにいろいろ微調整が必要になることも考えられます。widthとか。そこはまあがんばってください(投げ)。


icotileのFirefox対応検討中、この現象に遭遇しました。何が影響してるか検証した結果positionと判明したので、ならばと回避策を考えてみた次第です。

icotileとは:
Twitter のフォローしている人/されている人やリストを iTunes のような操作感で管理でき、また各ユーザーに対して自分だけのメモも残せる Web アプリケーション。Developed by @ogaoga / Designed by @piyotori
ってことで、最近icotileのデザイン周りでCSS3あれこれ調べたり、ビジュアル的なデザイン面以外でも普通にJavaScriptのロジック部分も書いたり、やってます。(そしてCSS3楽しーってなると勢いあまってシャルロッテとか作るわけです(前回エントリ参照))

2011年3月2日水曜日

CSS3でまどか☆マギカのシャルロッテを描いた

CSS3(webkitのみ)でまどか☆マギカのシャルロッテを作る、の続きです。

今朝未明のエントリでは力尽きて耳というか羽というかまでは作れませんでしたが、あとちょっとだしということで、付けました。

この完成版で、background-colorやらborderやらの指定を取り除き、border:1px solid whiteのみ適用してみると、こうなります。


だいたい、border-radiusを2角にだけかけたdivを、rotateして位置はabsoluteでチマチマ合わせてます。
目はradialタイプのgradientで色分け。
ひんまがった口には、border-radiusめいっぱいかけたdiv=円のborderを2辺だけ表示にして半円にし、それにskewやらscaleやらrotateやら適用してます。たぶん。


汚いソース見たい奇特な方は下記ページを開きブラウザの「ソースを表示」等からどうぞ。
実際のページ
※リンク先ページ内オブジェクトクリック危険

CSS3でまみまみしたい

CSS3で描いたよ!canvasとか使ってないよ!
まどか☆マギカ見たいと思ってるけどまだ見てなくて実はよく知らないよ!


汚いソース見たい奇特な方は下記ページを開きブラウザの「ソースを表示」等からどうぞ。
実際のページ
※リンク先ページ内オブジェクトクリック危険
※webkit限定

羽みたいのはもう疲れたから付けない。
付けました(2011/03/02 22:30)

2010年10月22日金曜日

Twitterbot移設メモ2

前回はGAE(Python)からPost成功したところまででした。

これからカーチャンbotのメッセージ選択アルゴリズムを移植します。

まずJavaScript動作のときの概要をちょっと書いておきます。

カーチャンbotは、全部で70種類くらいの定型文を用意しています。
お昼や夕食等の定刻用メッセージ、文中にユーザー名、商品名、などが入るものも含まれます。それら定型文自体をDOM要素として持たせていました。また、置換アイテムも同様です。

大雑把に書くと、
・定型文、置換アイテム、followerリストをデータとして持っている
・そしてそれらを使用したかどうかフラグを管理している(ストレージ等に書き出さないRAM上のもの)
・毎時ランダムに未使用のものを選ぶ
・定刻は定刻用定型文から引っ張ってくる
・通常時も、時間縛りあり定型文、時間縛りなし定型文がある
といった感じです。

毎時00分に、定型文をランダムに選び、時刻縛りがある場合はそれにあわせて、置換する必要があればアイテムもランダムに選び、そして投稿する文章が完成します。post完了後には、次の00分00秒000までの時間を計算して、setTimeoutで次の00分にまた同じことをするよう、仕込んでおきます。それを繰り返しています。
(0時過ぎのおやすみpost、followerリスト更新、などはまだ移植してないので、触れないでおきます)


GAE移植にあたって、これらデータの使用/未使用管理をどうするか、です。JavaScriptではRAM上でフラグ管理してました(のでブラウザ再起動で初期化されます)が、今度GAE移植して、cronで毎時動作させるとなると、いくら定型文使用/未使用のフラグをRAM上で管理しても、1回動作が終われば消えますから、ストレージに書き出さないとなりません。当然ですが。(むしろ今までが特異な動作原理のbotだっただけで)

ということで、僕はDBは全くわからないので、csv形式の生データファイルを読み書きする方向で行きます。(※最後に書いてありますが、ちなみにこの方法ではうまくいきません)

たとえば、

0,10-17,%A おかあさんちょっと買い物行って来るからね\n

という感じで。先頭が使用/未使用(1/0)、次が時刻指定/時間範囲縛り設定(なし=N,19時用=19,10時~17時用=9-18といった感じ)、最後が本文です。%AはJ( 'ー`)しに後で置換します。
これがずらーっと並んだデータファイルを作っておきます。

で、実際にPythonで読み込むときはこんな感じに。


import os
import random

# ファイル読み書きクラス
class fileAccess:
def __init__(self, src):
self.src = src
self.lines = []

def readData(self):
try:
f = open(self.src, 'r')
except IndexError:
print 'Index error'
except IOError:
print '"%s" cannot be opened.' % self.src
else: # no error
tmpLines = f.read().split('\n') # \n を区切りとしてファイル内容を読み込む
f.close() # ファイルクローズ

length = len(tmpLines) # 読み込んだ行数
for cnt in range(0, length):
str = tmpLines[cnt]
if str != "": # 空行は除外
self.lines.append(str)

def modifyData(self):
if len(self.lines) == 0:
print 'input lines has no data.'
return

tmpfile = "tmp_" + self.src
try:
f = open(tmpfile, 'w')
except IndexError:
print 'Index error'
except IOError:
print '"%s" cannot be opened.' % tmpfile
else: # no error
length = len(self.lines) # 読み込んだ行数
for cnt in range(0, length):
if self.lines[cnt] != "": # 空行は除外
f.write(self.lines[cnt] + "\n") # 引数の文字列をファイルに書き込む
f.close() # ファイルを閉じる

# ファイル操作: 変更前backupコピーを作成し 変更後tmpを正式にrename
bakfile = "bak_" + self.src
if os.path.exists(bakfile):
os.remove(bakfile)
os.rename(self.src, bakfile)
os.rename(tmpfile, self.src)

# 読み込んだ行をカンマで分けるクラス
class messageStruct:
def __init__(self, str):
tmp = str.split(',')
self.used = tmp[0]
self.timespan = tmp[1]
self.msg = tmp[2]

def setUsedStatus(self):
self.used = "1" # ものぐさで、int()で数値化してないで文字で判定してる

def clearUsedStatus(self):
self.used = "0"

def getCombinedStr(self):
return self.used + ',' + self.timespan + ',' + self.msg

# main
# データ読み込み
messageSource = fileAccess("msg.csv.dat")
messageSource.readData()

found = False
while found == False:
# ランダム
rndMax = len(essageSource.lines) - 1
i = random.randint(0, rndMax)

# カンマ区切りを各パラメータに分解
str = messageStruct(messageSource.lines[i])

if str.used == "0": # 未使用なのでメッセージ確定
str.setUsedStatus() # 使用済みに更新
messageSource.lines[i] = str.etCombinedStr()
found = True

# 略しますが、
# 必要があればuser名など置換してpost処理

# データ更新
messageSource.modifyData()


本当はもっと細かく、現在時刻取得して定刻用メッセージにするかどうか判定したり、置換アイテムが必要か、どの種のアイテムか、などいろいろやりますが、基本はファイル読んでランダムに選んで未使用なら採用、ってやってます。

が、ここで困ったことが。
実はGAEではファイルを静的なデータソースとして置くことはできるっぽいのですが、それを動的に更新したりはできません(知らずにLocalでターミナルからPython実行して↑の仕組み作ってた)。ので、この方法は、ランダムポストだけするには使えますが、本来の目的のどの定型文をポストしたかの管理を行うには、これでは不十分です。GAEのデータストアの方法を知らねばならないようです。僕がさっぱり知らない領域、DBに首を突っ込まねばなりません。

続く

2010年10月9日土曜日

Handycamについての連続Tweet

Handycamについて思うことTweetしてたのを、まとめたくなったので自分のblogに掲載。

---
#1
今日は子どもの運動会があるのでHandycamのHDDを空けとかなければいけない。まだ空きあると思うけど書き出しておく。

#2
子ども生まれてHandycam買ったはいいけど、全然撮る気にならないんだよね。ビデオ撮影って行為がどうにもつまんなくて。撮ったもの見返すと気に入らないんだよ。素人映像で。当たり前だけど。だって素人なんだから。

#3
なんていうか、写真はそれなりに構図とか思い描けるけど、動画の場合、そのイメージが湧かない。どんな長さのどんな映像のものを撮るか、なんて考えながら撮らない方がきっといいんでしょう。

#4
映画監督かっつーの。って。

#5
いや映像イメージは本当はあるんだよ。こうPANしていって、とか、ドリー撮影とか本当はしてみたかったり、Bird視点からの絵が欲しかったりさ。でもそれHandycam手に持った素人からかけ離れてるんだよ。

#6
そんな僕なので、Handycamってよくもまあ25年間たいして変わらないUXで商品売れてるもんだなぁと関心する。

#7
Handycamの話まだするけど、わかってはいますよ、そんなたいそうな「作品」作ろうなんて思わないで、スナップを撮るように、その出来事を記録しておくことが目的とか、そういうのは。

#8
でもそのわりにはさ、邪魔なんだよ、あれ。小さくなったとはいえでけーし時間かかるし手とか疲れるし何より目の前のことを見ていたい僕の裸眼の前に立ちふさがるわけですよあれ。

#9
時間を占有して!

#10
気軽に撮りたいけれど、気が軽くなれないんだ、あの機材。僕にとっては。

2010年10月6日水曜日

Twitterbot移設メモ1

自作Twitterbot(カーチャンbot)を移設しようとしています。※まだ移設できてません

現在は、この過去エントリにあるとおり、botはJavaScriptで動作させています。僕のMacのブラウザ(FF)上で。おかげでMac付けっぱなしです。また誰に@付きメッセージ送ったか、どの定型文を使ったか、などの管理がメモリ上で、なんらかのストレージに書き出してないので、ブラウザ閉じたり、Mac再起動すると、初期状態になります。ので、あまり再起動しないようにしてます(なるべく@付きで選ばれるユーザーは多くのfollowerさんに行き渡るようにしたいので)。

これはちょっと不便です。僕が。なのでサーバ借りてそっちに移そうかと考えていたところ、GAE(Google App Engine)でいいんじゃん?との提案を受けたので、現在移設チャレンジ中です。

とりあえずGAEというとJavaかPythonかになりますが、Pythonにしてみました。なんとなく未知で楽しそうだから。


■GAE開発環境設定
まず環境を用意しなくてはいけませんが、こちらを参考にさせていただきました。

BOT2UKU
http://sites.google.com/site/bot2uku/

Macなのでほとんどすることなしでした。
一応Hello Worldみたいなのはやってみました。それだけなら簡単。


■早速GAEからPost
次、Postできるかどうか試してみます。
Hello WorldのコードをごそっとTwitter投稿用に書き換えました。
以下の記事を参考にさせていただきました。

無題メモランダム: TwitterボットをOAuthに対応させてみた - Google App Engine(Python)
http://blog.mudaimemo.com/2010/03/google-app-engine-twitteroauth.html

すでにbotはJavaScript動作でOAuth対応は済んでおり、必要なキー等は揃っていたので、上記の記事の「2. Twitterにつぶやく」を参考に、そこのサンプルコードに取得済みのキー等を入れるだけでOKでした。(と、超簡単なはずが、AccessTokenとAccessTokenSecretを逆に入れていてそれに気付かずInvalid tokenとか言われて手こずってました)

ここで、cronの設定とか、その他設定、GAEに関していろいろ試してみたいところですが、いったんおいといて、次はbotの投稿メッセージ選択アルゴリズム(たいしたものではない)の移植に取り組みます。

2010年7月5日月曜日

フォント(Dings)作ったよ


iPadアプリのiFontMakerでフォント作ってみましたよ、と。
画像の左上からA-Za-z0-9!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~にアサインされてます。
UのUNKO以外はあまりキーアサインに関係のない絵です。だいたい思い付くままに描いてます。あ、アップルもキーに合ってるな。

TTFファイルはこちらでDownloadできますので、興味本位で使ってみたい方どうぞ。

2TTF: Piyotori’s Dings

ライセンスとかよくわかりません。普通に使っていいんじゃない?くらいの認識。

参考:iFontMakerで作るディングバット。自作お絵描きフォントのすすめ。

2010年6月17日木曜日

オフィスのトイレではどの便器を使うべきか

くだらない話なので、生暖かい気持ちで流してください。トイレだけに。

今の職場の男子トイレは小が4つ並んでいます。
トイレの入り口に近い方をA、一番奥をDとしましょう。

入り口 A  B  C  D


もっとも使用頻度が高いのは入り口に一番近いAです。これはまあ男性諸氏は感覚的にわかると思います。


以下、それぞれのケースであなたが小用でトイレに入ってきた場合、あなたはA~Dのどこを使うのが正しいでしょうか。

※以下の図では、♂は先客、☆はあなた(正解ポジション)です

◆case 1:
入り口 A  B  C  D
    ♂


Ans:
入り口 A  B  C  D
    ♂     ☆


切羽詰っている、先客が仲のよい知り合いだ、人のに興味がある、といった場合以外は、適切な間隔を保ちましょう。Cではダメな理由は、賢明なあなたならもうおわかりですね。3人目が入ってきた場合に、Bだと3人並んでしまい、Dだと先客のAが先に終わった場合に、奥から2人並んでてちょっちイヤンだからです。

では次のケースです。

◆case 2:
入り口 A  B  C  D
    ♂     ♂


Ans:
入り口 A  B  C  D
    ♂ ☆   ♂


B、Cどちらを選らんでも隣合ってしまいます。が、Bが正解です。なぜか。冒頭に書きましたように、一番手前のAを使う人が多い→誰もいない状態でトイレに入ってくるのはA、そう、一番先に入室してきた人はAである可能性がもっとも高いからです。Aが用を足し終われば、Bを陣取ったあなたに落ち着いたひと時が訪れる可能性が高いのです。

さて次のケース。少し複雑なメンタリティが絡んできますよ。

◆case 3:
入り口 A  B  C  D
      ♂   ♂


Ans:
入り口 A  B  C  D
    ☆ ♂   ♂


AとCどちらに並んでも他の人と隣合ってしまいますが、Cを使う場合、BとDどちらが先に終わっても、結局残った方と隣り合ってしまいます。Aを選んだ場合、もしBが先に終われば、あなたには落ち着いたひと時が訪れますし、なにより「一番入り口に近かったからという理由でAを選んだのであって、Bの隣に来たかったからじゃないんだ」という安心感を、Bに与えることもできます。

次も類似ケースです。

◆case 4:
入り口 A  B  C  D
    ♂   ♂


Ans:
入り口 A  B  C  D
    ♂   ♂ ☆


case3とほぼ同じ理論です。ここのトイレにおいて入り口側はもっとも頻度高く使われますが、実は(これは数が6つくらいまでのトイレにたいがい当てはまりますが)"一番奥"というのも、なにかにつけて好まれるポジションですので「Cの隣に来たのではなく俺は"一番奥"というステータスを得に来たんだ」ということで、Cに安心感を与えられると同時に、自分がそこを選んだ申し分ない理由にもできます。ここでの大切なことは「"一番奥"というステータス」です。

最後は珍しいパターンです。

case 5:
入り口 A  B  C  D
      ♂ ♂

Ans:
入り口 A  B  C  D
    ☆ ♂ ♂


ここまできたらもうおわかりですね。このケースではAが正解です。

あとは3人先客がいたら残りを選ぶしかなく、またA、Bに先客、あるいはC、Dに先客といった場合は、ひとつ開けたところが正解になるのは明白です。


これでこのタイプのトイレはもう完璧ですね。
Have a good toilet life!!.

2010年6月11日金曜日

JavaScriptのencodeURIComponentでハマる

珍しくWeb開発系の話。

奇特な動作方式(詳しくは過去エントリ参照)のTwitter
bot「カーチャンbot」のOAuth対応を行っていたとき、何を思ったか、OAuthをライブラリ等使わずに作ってみようと思いまして、あ、HMAC-SHA1とかbase64とかの部分以外は、ですが、んでいろいろやった過程で、ハマったことを書きたいと思います。
…って思ったけれど時間が経って何に悩んだのか忘れてしまったので、一番最近ハマったことを1つ。


JavaScriptの encodeURIComponentでは「-_.!~*'();/?:@&=+$,%#」といった文字のうち、

-_.!~*'()

がencodeされない、ということ。

これらのうち「!*'()」がOAuthを使ったAPIアクセスで問題に。まあTimeline取得やfavをやるにはこんな文字列使わないから問題ないんだけれど、statusの更新、いわゆるつぶやきの投稿時に、Tweet内容にこれらの文字列があった場合に、Signature違いますって言われてしまいます。

ので、Signature生成前に、この変換されないやつらのうち問題になる5文字はさらに個別にencodeしてあげないとダメでした。
-_.~はそのまんまでいいです。

例えばこんな感じのencodeURI拡張版作っておくとよいです。


function encodeURIextend(str){
str = encodeURIComponent(str);
str = str.replace(/\!/g, "%21");
str = str.replace(/\*/g, "%2A");
str = str.replace(/\'/g, "%27");
str = str.replace(/\(/g, "%28");
str = str.replace(/\)/g, "%29");
return str;
}


formのinput or textareaには生文字列でよくて、あくまでpost時のSignature計算に使うメッセージ、POST&https%3A%2F%2Fapi.twitter.com%2F(略)status=ここの値として設定するときに、拡張encodeURIしておく必要があるということです。

まあJavaScriptのOAuthライブラリ使えば、そんなことでハマらずに済みます。Sample*今見たら、まんまこの5文字対策がしてありました。

*下記Twitter developersのOAuth Librariesで紹介されてるもの:
http://dev.twitter.com/pages/oauth_libraries#javascript

稀に、こういう無駄な経験が将来役に立つこともあるんですが、まあ今回のはないかなw

2010年5月27日木曜日

恋するTL

「やっぱ外見より中身でしょ」と彼女は言う。

ひと呼吸おいてから彼女はスマートフォンを取り出しながら「Twitterでね、あーこの人のつぶやきいいなぁ、なんか合うかもって人いて」とタッチパネルをいじりながら話す。「その人よく写真投稿のつぶやきするんだけど、それがね、雰囲気ある写真で、トイデジっていうので撮ってるんだって。いいよねー」「Playing Now♪って付けて投稿してる曲見てもなんか趣味合うっていうか」などと"その人"について嬉々として語り出す。

話を聞きながら昔何かの記事で見た「つい婚」した人が言っていた"文字列に恋をした"というフレーズを思い出した。彼女の場合はTwitterを通じて垣間見えるその人のソーシャルアクティビティ全般に恋をしているということなのかもしれない。

それが"相手の中身を知る"ことでもあるようで、でも一面的でもあるようで、ちょっとからかいたくなって、私は彼女に聞いてみた。

「ちなみに写真はどこにUploadされてるの?Flickr?Picasa?それともTwitpicとかだけ?」

彼女はこちらの質問の意図がどこにあるかわかりかねて少し不思議そうな顔をしつつ、手に持ったスマートフォンで、Twitterで彼の写真投稿のつぶやきを探し出し、私に見せた。

「あ、Flickrね」

偏見だが、写真好きはFlickr、という印象がある。
他の写真も見ていいか一応彼女に聞いて、少し見せてもらう。写真にとくにタグは付けてない。タイトルも"DSCxxxxx.JPG"だ。とくにそういうところは管理しない人らしい。でも確かに写真はトイデジの性質を活かした"雰囲気のある"写真だ。

Twitterのpostもちょっと見せてもらった。fromがWebだ。クライアントは使わない派なのかな。お、iPadに興味があるようだ。でも"iPAD"なんて書いてある。なるほど、そういうところは気にしない人らしい。

そしてTwitterもFlickrもDefaultアイコンだった。

ふんふんと何やらよからぬ詮索をしているかのような私に、彼女はちょっと不機嫌なトーンで「で、写真Upload先がなんなの?」と聞く。

私が感じ取った"彼の特徴"を説明してみる。そして一通り私の言葉を聞いて彼女は「相変わらず歪んだ見方するのね」と苦笑する程度。さすが私の性格をよく知っているだけあるが、でもそれに対してちょっとは反抗してみせる。

「画面から入ってくるぱっと見の情報だけではなくて、内面の垣間見えるところを、そう、外見より中身を見ようとしてるのよ」

と。「へーりーくーつー」と彼女は頬をふくらませて言う。フォローというわけではないが「でも、写真、いい雰囲気ね」と一言付け足しておいた。それを聞いて少しだけ表情が柔らかくなった彼女は、またスマートフォンを自分の手元に戻し、TwitterのTimeLineを最新に更新する。

「あ…」

と声を漏らした彼女は、無言でこちらにスマートフォンの画面を向けた。さっきまで話題にしていた"彼"の最新のTweetが映し出されている。そこには"アイコン変えてみました!"という言葉と、Defaultアイコンから変更された"アニメか何かの女の子"のアイコンが表示されていた。

俗に言う"2次アイコン"の日本人Twitterユーザはよくいるし、私もそういったものに抵抗がないので気にならなかった。しかし、そういえば彼女は、ずいぶん昔のことではあるが以前付き合っていた人が、アニメにばかりに夢中になっちゃって…という理由で別れたのだった。

「アイコンがアニメの人はちょっとなぁー」

案の定、さっきまでのトキメキがどこかにすっ飛んでいったらしい。

「あれ?外見の"アイコン"じゃなくて中身の"つぶやき"が重要なんじゃないの?」

「ほんと、いじわるね」

彼女はそう言った後、紅茶を一口飲み、微かな笑みを浮かべていた。
そんなんだからお互いなかなか彼氏できないのよ、とでも言いたげな口元だ。

※フィクションです

2010年4月27日火曜日

うたかたbit

Twitter始める前まで、Twitterって何がおもしろいのかわからなかった。
というか、Twitterってそもそもなんなのか、わからなかった。
140文字のミニブログ、つぶやきで繋がるSNS、なんて解説してる記事はしばしばみかけたし、そして「ブログ」も「SNS」もわかる。でもTwitterがなんなのかは、使ってみて、しばらく触れてみるまで、わからなかった。


僕が今一番好きな「Tumblr」も、最初よくわからなかった。使ってみて、しばらく触れてみて、初めてわかった。


TwitterもTumblrも知る前、僕はネットで知り得た情報源についてどこかで説明するときに、こういう言い回しをしていたように思う。

ネットで見た、ネットで見つけた、ブログに書いてあった、ニュース記事にあった、2ちゃんねるに書いてあった…こんな感じだ。

この、ネット、ブログ、ニュース記事、を、今ならTwitter、Tumblrに置き換えることもできるが、そうではない言い方をしている自分に気付いた。

TLで流れてきた、Dashboardに流れてきた、といった表現だ。

TwitterではなくTL、TumblrではなくDashboard、というようにそのサービスの核となるようなViewを示す言葉を使い、そして今までは使うことがなかった「流れてきた」という表現を使うようになった。TLとDashboardはわからない人をおいてけぼりにしている感じで、そういう言い回しを好んで使ってる自分を客観的に見るとちょっと鼻につくし、そこはTwitter/Tumblrとサービス名そのものにしてもいい、というかそうしていることもあるが、やはり「流れてきた」というところは、そのままがいいかなと思う。


なんか、その方がしっくりくる気がする。


あ、でもMLに「流れてきた」、って使うなぁ。なーんだ。

2010年4月12日月曜日

社会人生活何年目かの春の雑記

創造的だとか先進的だとか、20世紀中はちょっとはチヤホヤされていたメーカーに入社してしばらく経った。ずっと同じ部署で仕事してる。部署の名前だけはコロコロ変わるが、やってる仕事の基本はあまり変わらない。

ここ数年は常にコストダウンと効率化、が目標だ。別に革新的手段などない。地道な話。そして効率化を達成したらそのぶん人を切る、人を切る方が先に行われ効率化を達成させる、そんなことの繰り返しで生き抜くシナリオしか組織にはないらしい。


ふと、地方公務員だった両親を思い出した。安定してずっと同じことやってるかと思いきや、数年に一度異動してんだ、あの職業。いやよく考えれば普通だろうけど。清掃課、秘書課、議会なんたら、総務課、緑地課、etc、どれも事務的なことは基本的には通じるんだろうけど、やはりそれぞれ仕事が違うようだ。異動したときの年齢(役職)で同じ課でもやることは違うらしい。

両親ともに地方公務員だったから、家族で食事する機会にも恵まれ(なんせだいたい定時で帰ってくるから)、そして食卓に上る話題は仕事の話=役所の話が多く、いろいろな職場の話は聞いていた。課やその中での係、立場によってほんとにいろいろだ。(あくまで子どもの頃の僕が親の話を聞いてて抱いた印象がベース)

地方公務員さえ数年に一度は異動してジョブローテーション組めてるかのようなことになってるのに、いや本当の組織としての戦略とかは知らないけど、親が数年に一度異動してたのは事実で、それに比べて、民間で、一時は商品だけでなく社内人事システム等までも先進的と言われてたこともあったメーカーにて、マンネリ化しててやることといったら人切りくらいの組織に未だにいるって、どうなんだ自分。(強く脱出したいと願う人は最終的にはどうにか組織を脱出できてはいる、からこそ、「どうなんだ自分」)


親からは昔、公務員には向いてないな、研究開発費が多い企業の研究職が合ってると思う、などと親なりに適正を考えたかのようでいてただの願望ともとれるようなことを言われていた。


父さん、母さん、研究職ではないけれど、それなりの民間企業のエンジニアにはなれましたが、今さら地方公務員になりたいです。と思ったり思わなかったり。すいません思ってないです。


ただできれば人に人として接する人らしさがある職場で人らしさがやどるような仕事をしたいとは思う。別に先進性とか創造性だとか前提条件になくていいんだ。人らしさのあるまともな職場であれば後から必要にかられて、もしくは自発的に発揮するんじゃないだろうか。もともと、そんな先進性だとか創造性だとかを妄信するような人間だったか、最近自分を疑いだしてる。いつからか、会社の(外向け)イメージに染まり過ぎていたというか、社内のできる人に憧れ過ぎていたというか。もとから自分はたいそうな志ももってやいないし。


そんなことに気付いた春。

2010年3月22日月曜日

春先の散歩(with LX1)

春になると散歩していて目に入る花が増えてくるので楽しい。


ヒメオドリコソウ。
purple deadnettle
草むらによく群生しているのを見かける。姫踊子草というWindows用キーバインド変更シェアウェアがあるらしい。なぜその名前を付けたのかと、実際の花と、結びつけようとあれこれ想像する時間は大切だ。検索してはいけない。


ハナニラ。
spring starflower
葉や茎からニラに似た臭いがすることからこの名前になっているらしい。花はそういう香りはしないのに、わざわざそんな名前を付けるのがおもしろい。英語では"spring starflower"(学名ではない)と言うようで、素直に「花」から名前をとっているようで、それと比べると日本人はひねくれているなと感じざるを得ない。そういうひねくれ根性は自分にもしっかり宿っている。


カラスノエンドウ。
bush vetch
やがて豆がなったときに、その黒くて細長いサヤを芋虫と誤認してドキっとすることがよくある。「金網と空」が入っている構図が好きだということに最近気付いた。


つくし。
horsetail
実物をアップで詳しく観察すると少しグロい。地下で繋がっているタイプなので、庭に生えてしまうと完全に除去するのが面倒らしい。胞子はギャグっぽい。子どもの頃に理科の教科書で見た胞子の姿はなんとなく覚えている。春の訪れを感じさせる植物の代表格だったりするわりに、よくよく考えてみるとその存在の「華」の無さは、どうなんだろう。


オオイヌノフグリ。
Veronica persica
名前はともかく、好きな花。野に咲く青い花は好きだ。ツユクサも好きだ。今のところ自分の中では、オオイヌノフグリが一番、春の訪れを感じる花。


ローズクォーツ & フローライト。
fluorite & rose quartz
春関係なし。花ですらなし。
先日、(娘と妻が用があった)手芸用品店でローズクォーツという桜色の石を見かけて、なんとなく欲しくなった。しかし使い道ないしそこそこ値段がするので買わずに店を後にした。その直後に行った100円ショップでローズクォーツが売っていたので、クオリティはだいぶ違うが買った。100円というのをいいことに、フローライトも買った。石の意味など知らない。なんか、きれいだから、欲しかった。

2010年3月6日土曜日

世界は”とくになにもなければ”ゆるやかに分断し安定していく

世界は”とくになにもなければ”ゆるやかに分断し安定していく。

blogに書こうとメモしていたテキストを推敲するの面倒になってそのままTumblrにpostした。
改めて、blogに書き直そうと思ったけど、やっぱそのままでいい気がした。
のでリンクだけ貼る。

2010年2月7日日曜日

最近撮った写真(Dec13, 2009 - Feb06, 2010)

最近撮った写真をいくつかTumblrに放り込みました。

LUMIX LX-1(iPhotoでレタッチ済み)


VQ1005(トイデジ)


iPhone(使用アプリ:ToyCamera, TiltShiftGenerator, PhotoshopMobile)