LoginSignup
3
2

More than 3 years have passed since last update.

HTMLタグにdatasetを指定して進捗サークルチャートを表示させるスクリプト

Posted at

こちらの記事の続きです。

HTMLドキュメント内のタグにdatasetを指定して進捗サークルチャートを表示させるためのスクリプトです。
ユーザー操作や時間経過等で可変させることは想定していません。

スクリプト

circle_chart.js
'use strict';
{
    window.addEventListener('DOMContentLoaded', function() {
        for(const e of document.querySelectorAll('[data-circleChart]')) {
            if(e.querySelector('.circleChart') === null) {
                e.innerHTML +=
                    '<div class="circleChart">' +
                    '  <div class="graph"></div>' +
                    '  <div class="percent"><div>**.*%</div></div>' +
                    '</div>';

                const
                    d1 = e.querySelector('.circleChart'),
                    d2 = d1.querySelector('.graph'),
                    d3 = d1.querySelector('.percent');

                d1.style.position = 'relative';
                d1.style.display = 'inline-block';

                d2.style.position = 'absolute';
                d2.style.mixBlendMode = 'multiply';

                d3.style.position = 'absolute';
                d3.style.width = '100%';
                d3.style.height = '100%';

                const params = e.dataset.circlechart;

                let size        = 100,
                    weight      = 10,
                    color       = '#08f',
                    backcolor   = '#ccc',
                    holecolor   = 'transparent',
                    percent     = 50,
                    fixed       = 1,
                    textcolor   = '#fff',
                    textmixblendmode = 'difference',
                    textleft    = '',
                    textright   = '',
                    texttop     = '',
                    textbottom  = '',
                    textdisplay = '';

                params.split(';').forEach(v => {
                    if(v.trim() !== '') {
                        const
                            param = v.split(':'),
                            key = param[0].trim().toLowerCase(),
                            value = param[1].trim().toLowerCase();

                        if(key === 'size') {
                            size = parseInt(value);
                        }
                        else if(key === 'weight') {
                            weight = parseFloat(value);
                            if(weight <= 0) weight = -100;
                        }
                        else if(key === 'color') {
                            if(checkProperty(value)) color = value;
                        }
                        else if(key === 'backcolor') {
                            if(checkProperty(value)) backcolor = value;
                        }
                        else if(key === 'holecolor') {
                            if(checkProperty(value)) holecolor = value;
                        }
                        else if(key === 'textcolor') {
                            if(checkProperty(value)) textcolor = value;
                        }
                        else if(key === 'textmixblendmode') {
                            if(checkProperty(value, 'mixBlendMode')) textmixblendmode = value;
                        }
                        else if(key === 'textleft') {
                            if(checkProperty(value, 'left')) textleft = value;
                        }
                        else if(key === 'textright') {
                            if(checkProperty(value, 'right')) textright = value;
                        }
                        else if(key === 'texttop') {
                            if(checkProperty(value, 'top')) texttop = value;
                        }
                        else if(key === 'textbottom') {
                            if(checkProperty(value, 'bottom')) textbottom = value;
                        }
                        else if(key === 'textdisplay') {
                            if(checkProperty(value, 'display')) textdisplay = value;
                        }
                        else if(key === 'value') {
                            percent = parseFloat(value);
                        }
                        else if(key === 'fixed') {
                            fixed = Math.floor(value);
                            if(fixed < 0) fixed = 0;
                            else if(fixed > 10) fixed = 10;
                        }
                    }
                });

                d1.style.width  =
                d1.style.height =
                d2.style.width  =
                d2.style.height = `${size}px`;

                const r1 = size / 2;
                const r2 = r1 - r1 / 100 * weight;
                const deg = percent * 3.6;

                d1.style.background = `radial-gradient(${holecolor} ${r2 - 1}px, #fff ${r2}px, #fff ${r1 - 1}px, #0000 ${r1}px)`;
                d2.style.background = `radial-gradient(#fff ${r2 - 1}px, #0000 ${r2}px, #0000 ${r1 - 1}px, #fff ${r1}px), conic-gradient(${color} ${deg}deg, ${backcolor} 0)`;

                const d3c = d3.querySelector('div');
                d3c.textContent = `${percent.toFixed(fixed)}%`;

                d3.style.fontSize = `${(r1 / 4).toFixed(1)}px`;
                d3.style.color = textcolor;
                d3.style.mixBlendMode = textmixblendmode;

                if(textleft === '' && textright === '') {
                    d3c.style.position = 'relative';
                    d3.style.textAlign = 'center';
                }
                else {
                    d3c.style.position = 'absolute';
                    if(textleft !== '') d3c.style.left = textleft;
                    if(textright !== '') d3c.style.right = textright;
                }
                if(texttop === '' && textbottom === '') {
                    d3c.style.top = '60%';
                }
                else {
                    if(texttop !== '') d3c.style.top = texttop;
                    if(textbottom !== '') d3c.style.bottom = textbottom;
                }
                if(textdisplay !== '') d3c.style.display = textdisplay;

                function checkProperty(str, p) {
                    const dummy = document.createElement('p');
                    if(p === undefined) p = 'color';
                    dummy.style[p] = str;
                    return dummy.style[p] === '' ? false : true;
                }
            }
        }
    });
}

使用方法

<script src='circle_chart.js'></script>でスクリプトを読み込んでおき、チャートを表示させたい要素にdata-circleChartを付加することで表示できます。

<div data-circleChart='プロパティリスト'></div>

以下のプロパティを指定できます。

size: チャートの直径(pixel)
weight: チャートの半径に対する太さの割合(0~100)
color: チャートのメインカラー(CSSのcolorで指定可能な値)
backColor: チャートのバックカラー(CSSのcolorで指定可能な値)
holeColor: チャートの穴の色(CSSのcolorで指定可能な値 デフォルトは透明)
textColor: 文字カラー(CSSのcolorで指定可能な値)
textMixBlendMode: 文字ブレンドモード(CSSのmix-blend-modeで設定可能な値 デフォルトはdifference)
textLeft: 文字の横表示位置 左基準(CSSのleftで設定可能な値)
textRight: 文字の横表示位置 右基準(CSSのrightで設定可能な値)
  textLeft,textRight共に無指定の場合は中央に表示
textTop: 文字の縦表示位置 上基準(CSSのtopで設定可能な値)
textBottom: 文字の縦表示位置 下基準(CSSのbottomで設定可能な値)
  textTop,textBottom共に無指定の場合は上から60%の位置に表示
textDisplay: 文字の表示形式(CSSのdisplayで設定可能な値 非表示にするためにnoneを指定するケースが多いと思います)
value: チャートの進捗度(0~100)
fixed: 進捗度の数字の少数表示桁数(0~10)

サンプル

動作デモ

<script src='./circle_chart.js'></script>

<body bgcolor='#ddeedd'>
    <!-- プロパティ無指定 -->
    <div data-circleChart></div>

    <!-- プロパティ指定例 -->
    <span data-circleChart='size:150; weight:100; backColor:#fca; color:#fa0; value:45.67; fixed:1'></span>
    <span data-circleChart='size:200; value:56.7; fixed:0; weight:30; color:#f8a; holecolor:pink; textColor:red; textMixBlendMode:normal; textright:5%; textTop:44%'></span>
    <div data-circleChart='textDisplay:none;'></div>

    <!-- 親要素のstyle併用 -->
    <div data-circleChart='size:150; fixed:2' style='position:absolute; top:5px; right:5px;font-family:serif;'></div>
</body>
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2