フロントエンドエンジニアになりたい

デザイナーなのかコーダーなのかディレクターなのかよくわからない人のブログ。趣味で絵を描きました(過去形)

FireFoxで2回目のCSSアニメーションが動かない

特定の条件下で、FireFoxでは2回目のアニメーションが実行されません。 発生条件は、「アニメーションの実行時にその要素の親要素のdisplayがnoneからblockに変更されるような処理」の場合です。 入れ子にせず、その要素だけでアニメーションする場合は大丈夫でした。

デモ

対策としてはJSでreflowさせてあげれば良いかと思いますが、デモをFirefoxで開くとわかるとおり、offsetWidthやgetBoundingClientRectを取得してあげてもFirexoxは改善せず。諦めてcloneNodeして置き換えてあげるとうまくいくようです。

ちなみにこの時注意しなければならないのは、デベロッパーツールなど表示していると、何もしなくてもうまく動いてしまったりする事です。おそらくビジュアルでDOMを表示させるためにreflowが起っているのでしょう。(嘘かも)

jQueryの場合はwidth()を呼んであげれば一発で大丈夫でした。

CSSのみで解決するのは今のところ方法を発見できていません。。。

カーソルと傾きでパララックスするやつ作った

github.com

軽量なのが欲しかったので作りました。わりと軽いと思います。 スマホなどでの傾きでも動くんですが、実際さわってみると45度ぐらいを角度0でやったほうがいいのかもと思ったり。。。

デモ

それぞれの.layerの要素にdata-depthを設定します。 0~1の間で奥にあるものほど大きな数字にします。 ちなみに.layerはすべて同じ大きさなので、例えば動きの大きい奥のものほど大きくしたい場合は、 その子要素で適当にCSSで大きくしてあげてください。

<div class="parallax-wrapper">
  <!-- set depth 0 ~ 1 -->
  <div class="layer" data-depth="1">
    <!-- something to contents -->
  </div>
  <div class="layer" data-depth=".5">
    <!-- something to contents -->
  </div>
  <div class="layer" data-depth="0">
    <!-- something to contents -->
  </div>
</div>

設定はCSSと同じ要領でやってあげます。

var elm = document.querySelector('.parallax-wrapper');
var cursorParallax = new CursorParallax(elm, {
  easing: 'ease-out',
  duration: '.6s',
  mousemoveRatio: 0.5,
  deviceorientationRatio: 1,
  mousemove: true,
  deviceorientation: true
});

mousemoveRatiodeviceorientationRatioというのはそれぞれの動きに対する倍率です。 この値を適当に調整してあげて好みの動きの大きさにしてあげると良いと思います。

Pixi.jsでAndroid4.0系だけCROS時にSECURITY_ERR: DOM Exception 18 エラー

情報がなくて2日もはまってしまいました。。。

結論、Android4.0系の標準ブラウザでWebGLを使うとどうあがいてもこのエラーになる場合があります。なので、Canvasを使うようにしてあげるといいです。(4.1とかは大丈夫)

PIXI.autoDetectRendererの第4引数にtrueを設定すると強制的にCanvasになるのでそこで適当に倒してあげると楽かもです。

var ua = navigator.userAgent;
var androidversion =  parseFloat(ua.slice(ua.indexOf('Android')+8));
var renderer = PIXI.autoDetectRenderer(
  300,
  300,
  {},
  androidversion === 4 ? true : false // noWebGL flag
);

追記:4.0系の標準ブラウザでもWebGLに対応してる機種としていない機種があるみたいです。

GClue HTML5 blog: スマートフォンブラウザのWebGL対応状況調査(2013年7月版)

forever-monitorでNode.jsスクリプトを簡単デーモン化

Node.jsを定常運用しようとするとデーモン化しなくてはとなりますが、forever-monitorを使うとコードでいろいろと制御できて便利です。

インストールは省略。

./
├── monitor.js // 監視用
└── something.js // これをデーモン化

monitor.js

var forever = require('forever-monitor');
// something.js の子プロセスの初期化
var child = new (forever.Monitor)('something.js', {
  'args': [
    '-some', 'thing' // 子プロセスのパラメータ
  ]
});
// イベントを定義できます
child.on('watch:restart', function(info) {
    console.error('Restaring script because ' + info.file + ' changed');
});
child.on('restart', function() {
    console.error('Forever restarting script for ' + child.times + ' time');
});
child.on('exit:code', function(code) {
    console.error('Forever detected script exited with code ' + code);
});
// プロセススタート
child.start();
$ node monitor.js

spritesmith-texturepacker使用時にクエリストリングをつける

CSSだとgulp-cachebustにパイプかなと思いますが、jsonなのでそういうものは見当たらず、、。 あまりいい方法ではないですが、ファイルを解析して置き換えするのもコストが高いのでspritesmith-texturepackerのパラメータに細工してつけると楽です。

var _ = require('lodash');
var gulp = require('gulp');
var spritesmith = require('gulp.spritesmith');
var spritesmith_texturepacker = require('spritesmith-texturepacker');

gulp.task('make_sprite', function(cb){
  var queryString = '?somethingQuery';
  var src_dir = './images';
  var dist_dir = './sprite';
  var sprite_name = 'sprite.png';
  gulp.src(src_dir+'/*.png')
    .pipe(spritesmith({
      imgName: 'sprite.png',
      cssName: 'sprite.json',
      algorithm: 'binary-tree',
      cssTemplate: function (params) {
        var _params = _.cloneDeep(params);
        _params.items[0].image += queryString;
        return spritesmith_texturepacker(_params);
      }
    }))
    .pipe(gulp.dest('./dist_dir'));
});

PIXI.js用にスプライトのテクスチャをGulpで生成する

gulp.spritesmithspritesmith-texturepackerを使います。

インストールは省略。

var gulp = require('gulp');
var spritesmith = require('gulp.spritesmith');
var spritesmith_texturepacker = require('spritesmith-texturepacker');

gulp.task('make_sprite', function(cb){
  var src_dir = './images';
  var dist_dir = './sprite';
  var sprite_name = 'sprite.png';
  gulp.src(src_dir+'/*.png')
    .pipe(spritesmith({
      imgName: 'sprite.png',
      cssName: 'sprite.json',
      algorithm: 'binary-tree',
      cssTemplate: spritesmith_texturepacker
    }))
    .pipe(gulp.dest('./dist_dir'));
});

こんな感じです。 PIXI.jsでの読み込みは以下

var loader = new PIXI.loaders.Loader();
loader.add('sprite', 'dist_dir/sprite.json');

var texture  = new PIXI.Texture.fromFrame('画像のファイル名');

注意したいのは複数のスプライトを読んでもframeIdは同じ名前空間になるので画像のファイル名は重複ができません。(多分)

各スプライト内で1.pngとか同じ名前をつけたい時は生成するときに一回リネームとか一時処理をしたほうがいいかもです(もっといい方法があるのかな...)

Three.jsの初歩

Three.jsの勉強を始めようと思います。

まずは初歩。立方体をつくって、それぞれの面に画像を貼り付けて、適当に回転してみました。 (リビジョンは79です)

https://yossiy.github.io/study_three/1.html

// シーンを作成
var scene = new THREE.Scene();
// カメラを作成
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
// レンダラーを作成
var renderer = new THREE.WebGLRenderer();
// レンダラーを画面の大きさにセット
renderer.setSize( window.innerWidth, window.innerHeight );
// レンダラーをdomへ挿入
document.body.appendChild( renderer.domElement );
// 横幅 1 高さ 1 深さ 1 の立方体(頂点の集合)を作成
var geometry = new THREE.CubeGeometry( 10, 10, 10);
// マテリアル(表面)を作成
var materials = [];
var texloader = new THREE.TextureLoader();
materials.push( new THREE.MeshPhongMaterial( { map: texloader.load('img/1.jpg') } ) );
materials.push( new THREE.MeshPhongMaterial( { map: texloader.load('img/2.jpg') } ) );
materials.push( new THREE.MeshPhongMaterial( { map: texloader.load('img/3.jpg') } ) );
materials.push( new THREE.MeshPhongMaterial( { map: texloader.load('img/4.jpg') } ) );
materials.push( new THREE.MeshPhongMaterial( { map: texloader.load('img/5.jpg') } ) );
materials.push( new THREE.MeshPhongMaterial( { map: texloader.load('img/6.jpg') } ) );
var material = new THREE.MeshFaceMaterial(materials);

// メッシュを作成
var cube = new THREE.Mesh( geometry, material );
// シーンにメッシュを追加
scene.add( cube );
// カメラの座標を手前へ 50 に設定(+で手前、-で前方)
camera.position.z = 50;
// ライトを作成
var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 50, 50, 50 ).normalize();
scene.add(light);

// ライトを作成
var light2 = new THREE.DirectionalLight( 0x555555 );
light2.position.set( -50, -50, 50 ).normalize();
scene.add(light2);

// 動きの初期化
var angle = 0;
var xl = 20;
var zl = 20;
var yl = 20;
var radius = zl;

// アニメーション
var render = function () {
  requestAnimationFrame( render);

  // rotationで回転
  cube.rotation.x += 0.05;
  cube.rotation.y += 0.05;
  angle += 0.01;

  // 斜めに回転運動
  var cos = Math.cos(angle);
  var sin = Math.sin(angle);
  var x = xl + cos * radius;
  var y = yl + cos * radius;
  var z = zl + sin * radius;
  cube.position.x = x - xl;
  cube.position.y = y - yl;
  cube.position.z = z - zl;

  // レンダリング
  renderer.render(scene, camera);
}
render();