カテゴリー
【Sass実践勉強会】続・cssだけで折れ線チャートを描く方法〜要素の回転と変形を使う
※ 当ページには【広告/PR】を含む場合があります。
2021/06/06

前の回の試みで、cssのlinear-gradient属性を使って擬似的な直線を作成する方法からCSS純正折れ線チャートを描いてみましたが、使いものにならないことが分かりました。
そこで今回は前々から検証して見たかった試みの一つである、
ブロック要素の回転と変形の基礎
まずは実線にみたてたブロック要素を折れ線として接続できるようにしたいので、まずは回転と変形の基礎を説明しておきましょう。
回転・transform
cssでの要素の回転は
transform
trandformを回転操作として使う基本的な用法として、
transform: rotate(<傾ける角度>);
transform-origin: <左からの位置> <上からの位置>;
をセットで使います。
transform-originでブロック要素の相対位置から回転の原点を指定し、その原点に対し回転する角度(時計回りが正方向)を指定して利用します。
例えば以下のブロック要素の回転に関与するcssスタイルを適用すると、
.黒線 {
width: 200px;
height: 4px;
background: black;
}
.緑線 {
width: 200px;
height: 4px;
background: green;
transform: rotate(30deg);
transform-origin: 0 50%;
}
.黄線 {
width: 200px;
height: 4px;
background: yellow;
transform: rotate(-30deg);
transform-origin: 0 50%;
}
以下のような感じに回転することが出来ます。
この回転を折れ線チャートで利用する場合にもっとも重要な点は回転位置を
transform-origin: 0 50%;

これで出来るだけ折れ線の継ぎ目を目だたないようにできると思います。
長さの修正
現在の点を次のデータ点へ接続する場合に、角度を計算して回しただけでは回転後に距離が足らない・伸び過ぎな状態に陥るので、回転後にブロック要素の幅(width)を再計算・補正しなくてはなりません。
この長さの補正計算はSassで与えるので、具体的な説明は後述します。
Sassの実装
では先ほどのテクニックを元にして本題の折れ線チャートを仕上げていきましょう。
まずはデータとチャート描画に役割分けでscssファイルを分割しておきます。
$ tree
.
├── index.html
├── style.scss
└── _data.scss
Sassプロジェクトのファイル分割方法に関しては以下のリンク記事で説明していますので詳しくはそちらの方を確認ください。
では描画するデータ部分
_data.scss
$sim_xydata: [
[0,1],
[1,0],
[2,0],
//...中略
[99,7],
];
Sass式の2次元配列で(x,y)の折れ線チャート用データセットを記述しています。 ここでは単純な例として、100点をサンプリング点としてy軸用のデータを0〜9のランダムな整数にしております。
なおファイルのフルバージョンは
次にスタイルを割り当てるhtmlファイルも作成しておきます。
<html>
<head><link rel="stylesheet" type="text/css" href="style.css"></head>
<body>
<div class="line-chart">
<div class="line-0"></div>
<div class="line-1"></div>
<!-- 中略 -->
<div class="line-99"></div>
</div>
</body>
</html>
以前の
このindex.htmlのフルバージョンも
さて、これでお膳立ては整いましたので、メインのscssファイル(
style.scss
@use 'sass:math';
@use 'data';
@mixin generic_line(
$line_index,
$chart_width,
$chart_height,
$rect_width,
$line_width,
$data
) {
.line-#{$line_index - 1} {
position: absolute;
box-sizing: border-box;
margin: 0;
padding: 0;
left: $rect_width * ($line_index - 1);
width: $rect_width;
height: $line_width;
top: $chart_height * (1 - nth(nth($data, $line_index), 2) / 10);
$diff: nth(nth($data, $line_index + 1), 2) - nth(nth($data, $line_index), 2);
$rect_height: $chart_height * abs($diff) / 10;
//👇①回転後の補正距離の計算
width: 1px*math.pow(math.pow($rect_width/1px,2)+math.pow($rect_height/1px,2), 0.5);
//👇②回転角の計算
$tilte_angle: math.atan(-1*$chart_height*$diff/10/$rect_width);
@if $diff > 0 {
background: blue;
transform: rotate($tilte_angle);
transform-origin: 0 50%;
} @else if $diff < 0 {
background: red;
transform: rotate($tilte_angle);
transform-origin: 0 50%;
} @else {
background: black;
}
&:before {
display: block;
position: absolute;
border-radius: 50%;
content: "";
top: 0;
left: 0;
width: $line_width;
height: $line_width;
background: yellow;
}
}
}
.line-chart {
$chart_width: 600px;
$chart_height: 200px;
$section_num: 99;
display: block;
position: relative;
width: $chart_width;
height: $chart_height;
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: darkgray;
@for $i from 1 through $section_num {
@include generic_line($i, $chart_width, $chart_height, $chart_width/$section_num, 2px, data.$sim_xydata);
}
}
ここではモジュールの呼び出しやforループ処理などのSassテクニックを色々と利用しています。
それぞれ細かいテクニックを話すとキリがないのですので、ここでは以下の個別のトピックで説明した内容で詳細を確認ください。
ここでは、伸縮(コード内の①)と回転(コード内の②)の再計算の考え方を解説します。
まずは伸縮ですが現在の点$$(x
Eq. (1)
なお、関数パラメータに単位を含んだままでは計算が通りませんので、
1px
なお、現時点で多次元での距離を返してくれる
もう一つ回転角$$\theta_\mathrm{rot}$$の計算は以下のように考えます。
Eq. (2)
ここでは仰角を割り出せるようにアークタンジェント関数を利用します。
ここでの式中の補正比率$$\alpha$$は、チャートの描画領域とブロック要素の比率にマイナスを掛けたものです。 Sassの回転系は通常の回転系とは逆に時計回りを正にとっているので、マイナスを掛けていることに注意してください。
ともあれこれを計算することでデータの座標値から接続された折れ線がスタイルとして生成されます。
以上、説明が長くなりましたが、ここまでで完成した折れ線チャートは以下のようになります。
いい感じのcss純正折れ線チャートに仕上がりました。
まとめ
今回はSassの能力を最大限に活用した例としてcssだけで折れ線チャートを作ってみた話を順を追って説明していきました。
今回のブロック要素を回転・伸縮させてcss純正の折れ線グラフを作るというアイデア自体は全然新しいものではないのですが、cssコードのハードコーディングではあまりに複雑になりすぎるので、到底Sassなどのcss系フレームワークを力添えなしでは作成不可能なものでした。
改めてSassを使ったスタイル表現のポテンシャルを感じていただけたら幸いです。
参考サイト
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー