Last active
December 6, 2015 03:39
-
-
Save mitsuru793/5b113f0f2f724df7267e to your computer and use it in GitHub Desktop.
impress.jsのinit部分をコードリーディングする
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 全体図が分かるように、initに関係するものだけ抜き取りました。 | |
(function ( document, window ) { | |
'use strict'; | |
// data of all presentation steps | |
var stepsData = {}; | |
// rootには<div id="impress">のDOMツリーが入っています。 | |
var roots = {}; | |
var defaults = { | |
width: 1024, | |
height: 768, | |
maxScale: 1, | |
minScale: 0, | |
perspective: 1000, | |
transitionDuration: 1000 | |
}; | |
var impress = window.impress = function ( rootId ) { | |
var currentState = null; | |
var initialized = false; | |
var init = function () { | |
if (initialized) { return; } | |
var meta = $("meta[name='viewport']") || document.createElement("meta"); | |
meta.content = "width=device-width, minimum-scale=1, maximum-scale=1, user-scalable=no"; | |
// 省略 | |
}; | |
}; | |
})(document, window); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var init = function () { | |
// init()を実行済みなら何もしない | |
if (initialized) { return; } | |
// First we set up the viewport for mobile devices. | |
// For some reason iPad goes nuts when it is not done properly. | |
var meta = $("meta[name='viewport']") || document.createElement("meta"); | |
// metaタグのcontent属性をセットします。 | |
// Elementオブジェクトは、作成したタグで使える属性は、プロパティとして用意されています。(idなど) | |
meta.content = "width=device-width, minimum-scale=1, maximum-scale=1, user-scalable=no"; | |
// document.headで現在のheadタグを取得します。 | |
// metaタグがheadタグの直下にあるかを確認しています。 | |
// metaタグが取得できずに、新規作成した場合は親ノードはないのでfalseです。 | |
if (meta.parentNode !== document.head) { | |
meta.name = 'viewport'; | |
document.head.appendChild(meta); | |
} | |
// rootには<div id="impress">のDOMツリーが入っています。 | |
// datasetはHTML5のdata属性にアクセスするための属性です。詳細:http://uhyohyo.net/javascript/12_4.html | |
var rootData = root.dataset; // DOMStringMap {} | |
config = { | |
width: toNumber( rootData.width, defaults.width ), | |
height: toNumber( rootData.height, defaults.height ), | |
maxScale: toNumber( rootData.maxScale, defaults.maxScale ), | |
minScale: toNumber( rootData.minScale, defaults.minScale ), | |
perspective: toNumber( rootData.perspective, defaults.perspective ), | |
transitionDuration: toNumber( rootData.transitionDuration, defaults.transitionDuration ) | |
}; | |
// 縦・横のスケールを求めて、小さい方を返します。 | |
windowScale = computeWindowScale( config ); | |
// div#impressの子要素をすべて、canvasにコピーします。 | |
arrayify( root.childNodes ).forEach(function ( el ) { | |
canvas.appendChild( el ); | |
}); | |
root.appendChild(canvas); | |
// set initial styles | |
document.documentElement.style.height = "100%"; | |
css(body, { | |
height: "100%", | |
overflow: "hidden" | |
}); | |
var rootStyles = { | |
position: "absolute", | |
transformOrigin: "top left", | |
transition: "all 0s ease-in-out", | |
transformStyle: "preserve-3d" | |
}; | |
css(root, rootStyles); | |
css(root, { | |
top: "50%", | |
left: "50%", | |
transform: perspective( config.perspective/windowScale ) + scale( windowScale ) | |
}); | |
css(canvas, rootStyles); | |
// classListは、HTML5で追加されました。classを追加、削除がピンポイントで可能です。 | |
body.classList.remove("impress-disabled"); | |
body.classList.add("impress-enabled"); | |
// root要素からstepクラスがついた要素を取得します。 | |
steps = $$(".step", root); | |
// initStepには、各DOM要素と、そのインデックス番号が渡ります。 | |
steps.forEach( initStep ); | |
// set a default initial state of the canvas | |
// 外のコンテキストで定義された変数なので、 | |
// クロージャによって値はinit()実行後も保持されます。 | |
currentState = { | |
translate: { x: 0, y: 0, z: 0 }, | |
rotate: { x: 0, y: 0, z: 0 }, | |
scale: 1 | |
}; | |
initialized = true; | |
// root要素に"impress:init"というイベントを発行します。 | |
// 第3引数には、イベントハンドラに渡したいデータを設定します。 | |
triggerEvent(root, "impress:init", { api: roots[ "impress-root-" + rootId ] }); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// init()で使われる内部関数です。登場する順番に記述してあります。 | |
// そのため、実際に定義されている順番とは違います。 | |
// numeric: Number型に変換する | |
// fallback: numbercが非数の場合の戻り値。デフォルトでは、0が返ります。 | |
var toNumber = function (numeric, fallback) { | |
// isNaNは、非数(数値ではない)の場合にtrueを返します。 | |
// 数値だけでなく、文字列の数字でもfalseを返します。 | |
return isNaN(numeric) ? (fallback || 0) : Number(numeric); | |
}; | |
// 縦・横のスケールを求めて、小さい方を返します。 | |
var computeWindowScale = function ( config ) { | |
var hScale = window.innerHeight / config.height, | |
wScale = window.innerWidth / config.width, | |
// 縦・横、小さい方のスケールを取得します。 | |
scale = hScale > wScale ? wScale : hScale; | |
// config.maxScaleが存在してるかを、まず確認してから比較しています。 | |
if (config.maxScale && scale > config.maxScale) { | |
scale = config.maxScale; | |
} | |
if (config.minScale && scale < config.minScale) { | |
scale = config.minScale; | |
} | |
return scale; | |
}; | |
// 配列である引数をコピーして返します。 | |
var arrayify = function ( a ) { | |
// sliceは引数がないと全要素を返します。 | |
// 配列をコピーするのに使っています。concatで代用も可能です。 | |
return [].slice.call( a ); | |
}; | |
// el(DOM)に、props(オブジェクト)にあるスタイルを設定して返します。 | |
var css = function ( el, props ) { | |
var key, pkey; | |
for ( key in props ) { | |
// 親クラスのプロパティまで参照しないようにします。 | |
if ( props.hasOwnProperty(key) ) { | |
pkey = pfx(key); | |
if ( pkey !== null ) { | |
el.style[pkey] = props[key]; | |
} | |
} | |
} | |
return el; | |
}; | |
// 引数propから、現在のブラウザで使えるCSSプロパティ名を探して取得します。 | |
var pfx = (function () { | |
// styleのプロパティ名が使えるかをチェックするために使います。 | |
var style = document.createElement('dummy').style, | |
// タイプ数を減らす、配列の作り方です。 | |
prefixes = 'Webkit Moz O ms Khtml'.split(' '), | |
// クロージャで使われるので、この変数の値はずっと残ります。 | |
memory = {}; | |
// memoryにキャッシュしてある、CSSプロパティ名を取り出します。 | |
return function ( prop ) { | |
// memoryにキャッシュしていない場合は、キャッシュします。 | |
if ( typeof memory[ prop ] === "undefined" ) { | |
// ucはUpperCaseの略だと思います。 | |
// プロパティ名の先頭を大文字にします。 | |
var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1), | |
// そのまま、ベンダープレフィックスをつけたものと、先頭大文字のスタイル名を含んだ配列を作ります。 | |
props = (prop + ' ' + prefixes.join(ucProp + ' ') + ucProp).split(' '); | |
// 使えるスタイル名がなかった時のために、nullを入れます。 | |
memory[ prop ] = null; | |
// 使えるスタイル名があったら、スタイル名を入れてブレイクします。 | |
for ( var i in props ) { | |
if ( style[ props[i] ] !== undefined ) { | |
memory[ prop ] = props[i]; | |
break; | |
} | |
} | |
} | |
return memory[ prop ]; | |
}; | |
})(); | |
// context以下のdomツリーからセレクタに当てはまる要素を取得します。 | |
// contextのデフォルト値はdocumentです。 | |
var $$ = function ( selector, context ) { | |
context = context || document; | |
// 取得した配列をコピーして返します。 | |
return arrayify( context.querySelectorAll(selector) ); | |
}; | |
// `initStep` initializes given step element by reading data from its | |
// data attributes and setting correct styles. | |
var initStep = function ( el, idx ) { | |
// HTML5で追加されたdata属性のためのインターフェースです。 | |
var data = el.dataset, | |
step = { | |
translate: { | |
x: toNumber(data.x), | |
y: toNumber(data.y), | |
z: toNumber(data.z) | |
}, | |
rotate: { | |
x: toNumber(data.rotateX), | |
y: toNumber(data.rotateY), | |
z: toNumber(data.rotateZ || data.rotate) | |
}, | |
scale: toNumber(data.scale, 1), | |
el: el | |
}; | |
if ( !el.id ) { | |
el.id = "step-" + (idx + 1); | |
} | |
stepsData["impress-" + el.id] = step; | |
css(el, { | |
position: "absolute", | |
transform: "translate(-50%,-50%)" + | |
translate(step.translate) + | |
rotate(step.rotate) + | |
scale(step.scale), | |
transformStyle: "preserve-3d" | |
}); | |
}; | |
// cssの値(文字列)を組み立てます。 | |
var translate = function ( t ) { | |
return " translate3d(" + t.x + "px," + t.y + "px," + t.z + "px) "; | |
}; | |
// cssの値(文字列)を組み立てます。 | |
// revertはx,y,zの値を逆から書けるオプションです。 | |
var rotate = function ( r, revert ) { | |
var rX = " rotateX(" + r.x + "deg) ", | |
rY = " rotateY(" + r.y + "deg) ", | |
rZ = " rotateZ(" + r.z + "deg) "; | |
return revert ? rZ+rY+rX : rX+rY+rZ; | |
}; | |
// cssの値(文字列)を組み立てます。 | |
var scale = function ( s ) { | |
return " scale(" + s + ") "; | |
}; | |
// cssの値(文字列)を組み立てます。 | |
var perspective = function ( p ) { | |
return " perspective(" + p + "px) "; | |
}; | |
// `triggerEvent` builds a custom DOM event with given `eventName` and `detail` data | |
// and triggers it on element given as `el`. | |
var triggerEvent = function (el, eventName, detail) { | |
var event = document.createEvent("CustomEvent"); | |
// initCustomEventは非推奨です。https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/initCustomEvent | |
// 引数:(イベントの種類, イベントがバブルするか, イベントがキャセル可能か, イベントデータ) | |
// 上記の引数を用いてCustomEventを初期化します。http://webkledgeb.blogspot.jp/2014/08/dom-customevent-3-customeventinitcustom.html | |
event.initCustomEvent(eventName, true, true, detail); | |
// 要素elに、eventイベントを発行します。イベントをエミュレートできます。 | |
el.dispatchEvent(event); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment