[tech] デカい文字をA4で分割して印刷するツールをJSで書いた | Sat, Mar 7. 2015 - 氾濫原 では、実寸サイズを扱うので、多くの場所で mm や cm やら pt などの単位で数値を書きたくなる。
いろんな方法
mm を係数にして毎回乗算する方法
var mm = dpi / 25.4; 10*mm
mm を係数にして毎回除算する方法
var mm = 25.4 / dpi; 10/mm
乗算の逆。
変換を関数にする方法
function mm (num) { ... } mm(10)
Number のプロトタイプ拡張
Number.prototype.mm = function () { ... }; 10..mm()
しかし JSLint とかは 10..mm みたいな呼びかたをすると怒る。
Number のアクセサディスクリプタ
単純なプロトタイプ拡張と比べ、括弧がいらない。
10..mm
function setDPI (dpi) { var dpmm = dpi / 25.4; var pt = dpi / 72; var units = { 'in' : dpi, 'pt' : pt, 'mm' : dpmm, 'cm' : dpmm * 10, 'm' : dpmm * 1000 }; for (var unit in units) if (units.hasOwnProperty(unit)) (function (factor) { Object.defineProperty(Number.prototype, unit, { get: function () { return this.valueOf() * factor; } }); })(units[unit]); } setDPI(150); console.log(10..mm); console.log(10..cm);
しかし JSLint とかは 10..mm みたいな呼びかたをすると怒る。
アクロバティックな方法
'10 mm'
とかを数値に変換する形
var UnitConverter = function () { this.init.apply(this, arguments) };
UnitConverter.prototype = {
init : function (opts) {
if (!opts) opts = {};
this.setDPI(opts.dpi || 96);
},
setDPI : function (dpi) {
this.dpi = dpi;
var dpmm = dpi / 25.4;
var pt = dpi / 72;
this.units = {
'in' : dpi,
'pt' : pt,
'mm' : dpmm,
'cm' : dpmm * 10,
'm' : dpmm * 1000
};
var unitNames = [];
for (var key in this.units) if (this.units.hasOwnProperty(key)) {
unitNames.push(key);
}
this.re = new RegExp('([0-9.]+) (' + unitNames.join('|') + ')');
},
unit : function (string) {
if (string.match(new RegExp('^' + this.re.source + '$'))) {
return +RegExp.$1 * this.units[RegExp.$2];
} else {
return null;
}
},
context : function (fun) {
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
fun = eval('(' + fun.toString().replace(new RegExp("'(" + this.re.source + ")'", 'g'), function (_, s) {
return self.unit(s);
}) + ')');
fun.apply(null ,args);
}
};
文字列化した関数を置換する。みためクロージャなのにクロージャになってないので変数アクセスで混乱する。つくれない。
結論
普通に係数使うのが一番シンプル。除算のほうがかっこいい気がする。ただし演算子の優先順位に気をつかわないとハマる。