スポンサーリンク

JavaScriptで解像度からアスペクト比を算出する

今朝ツイッターを眺めていたら、10.8型のモバイルノートで解像度が2560×1600のノートパソコンのレビューが流れてきたんですけど、アスペクト比がパッと思い浮かびませんでした。

横2560pxで縦1440pxならぼくが使っている31.5型のWQHDと同じなので16:9だとすぐわかります。それよりは縦が長いから16:10?3:2?

えーと、2560 ÷ 1600 = 1.6だから、1.6:1、つまり16:10か。なるほど。

そんなふうに頭の中で計算したのですが、いやまてよ、1920 ÷ 1080とか1.77777…になっちゃうし、割り切れないときにパッとわからないな。どうやって計算したら良いのだろう、と疑問に思いました。

スポンサーリンク

1920 x 1080の縦横比は1920対1080

アホみたいな見出しですが、1920px × 1080pxの縦横比は1920対1080です。
…………………いやいやいや、そういう話じゃないですよね。

じゃあなぜ16:9と表現するのだろうか。ググってみたら、PCモニター等の縦横比は2辺の(ピクセルサイズの)最大公約数で割った値で表現する、みたいなことが書いてあるページがたくさんヒットしました。

うーん?でも16:10ってちょっと違くない? 最大公約数で割ったら8:5になるよね。これは何というか、一般的に普及しているテレビやモニターの縦横比16:9に近いから16:10という書き方をしているのでしょうか。

…なら、2辺の最大公約数で割った後、16未満だったときは16に近づくまで2倍にする…?

そこまで考え始めると面倒になったので、そこはいったん置いておくとして、はてさて最大公約数を求める処理はプログラムではどう書けば良いのかな、と悩みはじめました。

JavaScriptで最大公約数を求める

こちらもググってみると色々なコーディング例が紹介されていましたが、どれも基本はユークリッド互除法。特に秀逸だと感じたのが再帰表現を使ったこちら。

function gcd(a, b){
	if(b == 0) return a;
	return gcd(b, a % b);
}

参考にした記事:https://tech.arc-one.jp/asepct-ratio

ユークリッド互除法とは2つの値を割って、その余りが0でなければまた余りで割り続けて最大公約数を求める方法で、具体例を挙げるとこんな感じ。

  • 1920 ÷ 1080 の余り 840
  • 1080 ÷ 840 の余り 240
  • 840 ÷ 240 の余り 120
  • 240 ÷ 120 の余り 0

以上のことから、1920と1080の最大公約数は120だとわかります。

while文のループ処理で実行している例も多くありましたが、先述の再帰表現を使ったやり方は実にシンプルでわかりやすい例だと感じました。プログラミングの初学者等、稀に再帰表現がピンとこない方もいるようなので、そういう場合は別に無理せずwhile文で書けば良いと思います。

そして、最大公約数が120だとわかったら、今度はそれぞれの値で割ります。
1920 ÷ 120 = 16
1080 ÷ 120 = 9

これで、1920×1080は16:9だとわかるわけですね。

JavaScriptで解像度から縦横比を算出する

というわけで、さっそく先ほどの最大公約数を求める関数をお借りし、解像度から縦横比を求めるプログラムを書いてみました。それだけだと芸がないので、ついでにイメージしやすいよう、1:1の赤枠の中に算出された縦横比でブルーバックの四角を表示するようにしています。

実行例

アスペクト比:

これを作ってはじめて気が付いたのですが、一般的に21:9と言われているウルトラワイドモニターは正確には21:9じゃないんですね。

3440×1440のウルトラワイドは43:18 (21.5:9)
2560×1080のウルトラワイドは64:27  (21.333:9)

という計算になります。マジかー…知らずに使ってたわー。

HTMLとCSS

<p>
	<input type="number" id="w" value="1920" list="w_list">
	<input type="number" id="h" value="1080" list="h_list">
	<button id="calc">計算</button>
</p>
<datalist id="w_list">
	<option value="1280">
	<option value="1600">
	<option value="1920">
	<option value="2560">
	<option value="3840">
</datalist>
<datalist id="h_list">
	<option value="720">
	<option value="900">
	<option value="1080">
	<option value="1440">
	<option value="2160">
</datalist>

<p>アスペクト比:<span id="aspect_ratio"></span></p>

<div id="preview_wrapper">
	<div id="preview"></div>
</div>

<style>
#preview_wrapper {
	max-width:100%;
	width:500px;
	border:1px solid red;
	aspect-ratio:1/1;
}
#preview {
	width:100%;
	height:10px;
	background-color:blue;
}
</style>

画面サイズの入力部分は普通のINPUTタグで、オマケ要素としてdatalistからよくある解像度を選べるようにしています。

ただ、この後のJavaScriptにあるとおり、デフォルトで現在の解像度をセットしているのでいまいち使い勝手がよくないかも。

赤枠で表現された1:1の正方形はブラウザのサイズが違ってもちゃんと正方形になるように、CSS側でaspect-ratio:1/1;を指定しています。そう、CSSで普通に縦横比設定できるんですよねー。

でもJavaScriptからCSSのaspect-ratioが設定できるかわからなかったので、#previewについては幅を100%設定にし、高さはJavaScript側で計算してセットするようにしてみました。

JavaScriptのソース

<script>
window.addEventListener('load', function () {
	document.getElementById('w').value = screen.width;
	document.getElementById('h').value = screen.height;
	previewImage();
	document.getElementById('calc').onclick = function () {
		previewImage();
	};
});
function gcd(a, b){
	if(b == 0) return a;
	return gcd(b, a % b);
}
function previewImage()
{
	//画面サイズ
	let w = document.getElementById('w').value;
	let h = document.getElementById('h').value;
	//横:縦の最大公約数を算出
	let g = gcd(w, h);
	//最大公約数で割った値をアスペクト比として表示
	document.getElementById('aspect_ratio').textContent = (w / g) + ':' + (h / g);
	//プレビューの最大幅を取得
	let base_size = document.getElementById('preview_wrapper').clientWidth;
	//プレビューの最大幅を基準として縮小率を算出
	let ratio = base_size / w;
	//プレビューの高さを縮小率に従って割合で指定
	document.getElementById('preview').style.height = (h * ratio) / base_size * 100 + '%';
}
</script>

コメントに書いたまんまですが、↓こんな流れです。

  • ページのロード完了時に現在のスクリーンサイズをINPUTタグにセット
  • そしてすぐに縦横比のプレビュー画面を表示するpreviewImage関数を呼び出す
  • previewImage関数では設定された幅、高さの最大公約数を算出
  • その最大公約数で横/縦を割り、アスペクト比として表示
  • ブラウザのサイズが変わっている可能性を考え、その時点でのpreview_wrapperの幅を取得
  • プレビューの最大幅から画面サイズの幅を割り、縮小率を算出
  • その縮小率に基づいて、プレビューの青枠の高さを変更

縦横比の算出よりも、プレビューの青枠出す処理のほうが長いっすね。

正方形の赤枠で囲った中に描いたほうがアスペクト比を感覚的に理解しやすいかと思ってそんな作りにしたのですが、ブラウザのサイズが環境によって異なるため、そのへんの縮小率をアレコレしていたらちょっぴりコードが長くなりました。

まとめ

たまたま今朝見かけたノートPCの解像度2560×1600の縦横比がわかりづらかったので、算出するツールを作ってみました。

最近のSurfaceとか、解像度2736 x 1824だったりするのですが、この数字だけ見て3:2だとはあまりパッと思い浮かばないんですよねぇ。Surfaceだから3:2だろう、という予測は付くかもですがw

こんな縦横比計算ツールはそこかしこに転がっているのですが、どうやってJavaScriptで書くのかなーと考えはじめたら、実際に書かずにはいられなくなったので記事として投稿してみました。

いつもどおりの誰得記事ですが、こんなところまでお読み頂きありがとうございます。

コメント

タイトルとURLをコピーしました