SVGに輪を描く


🍩 ドーナツを描く


 最近プロジェクトをする時にドーナツを描きたいです.divブロックを削って作ろうとしたが、opggデスクトップアプリケーションのこの美しいグラフを見ると、divには明らかに限界がある.特にあの太いショットは...可能ですか.

 グラフライブラリを書きたいのですが、勉強している人の立場に立って、何でも、できるだけ本機(?)を使います.実施はいいんじゃないですか...
以下の資料は助かります.
https://a11y.gitbook.io/graphics-aria/svg-graphics/svg-basic-shapes
https://wit.nts-corp.com/2021/04/23/6338
環境はtypescript/reactです.
 svgを使用して円を描く場合は、svgタグと円タグを使用するか、svg内でpathを使用して直接描くことができます.path方式は複雑に見えるし、必要もないのでcircle方式を使ってみます.体現すべき資料は大体以下の通りである.
KDAPerMatch: 0
champUseRatio: 25
deathPerMatch: 0
foreignLanguageRatio: 0
isPrevSeason: 25
maxDeathPerCount: 0
positionRatio: 7.5
userLevel: 23
winRate: 0
 それらの最高和は100で、点数からドーナツのグラフを求めればいいです.まず、各アイテムの色を披露しました.index署名が必要なので、タイプも事前に宣言します.
const scoreColor:{[index:string]:string} = {
    deathPerMatch:'red',
    KDAPerMatch:'orange',
    winRate:'yellow',
    maxDeathPerCount:'green',
    foreignLanguageRatio:'blue',
    positionRatio:'navy',
    champUseRatio:'purple',
    userLevel:'black',
    isPrevSeason:'white',
}
虹色...ほほほ
正式にラベルを入力します.実際、ラベル内のpropertyの大部分は直接見ればわかります.
 <svg  width={size} height={size} viewBox={"0 0 100 100"} style={{transform:'rotate(-90deg)'}}>
           {Object.keys(offset).length>0 && Object.keys(score).map((prop, index)=>{
               const value = score[prop]
               const color = scoreColor[prop]
               if(typeof value=="number"&& value){
                    console.log(offset)
                    return(
                        <circle 
                        stroke={color} 
                        cx={50} 
                        cy={50} 
                        r={45} 
                        strokeDasharray={`${2*Math.PI*45*(value/100)} ${2*Math.PI*45*(1-(value/100))}`} 
                        strokeDashoffset={`${2*Math.PI*45*(offset[prop])/100}`} 
                        fill={'none'} strokeWidth={10} />
                    )
               }
              
            })
            }
	</svg>
  上から下へ
  • ViewBoxは、サイズ値によって変化するSVGボックス値を100×100サイズに統一する役割を果たす.
  • 変換要求円環筆画は12時方向から始まる.
  • の値は、タイプチェックを行うために事前に宣言しなければならないため、定数として宣言されます.
  • cx、cy、rはそれぞれ円心の座標、半径である.
  • を充填することなくドーナツ
  • を作成する.
  • 周波数幅は線の太さです.
  • 一番頭が痛いのはStrokeDasharray、StrokeDashoffset、わかりましたが、不思議なことに実現に時間がかかりました.

    strokeDasharray


    よく見られる資料から見ると,この属性は破線の点長を意味する.周長で表すので、2πrという円の周長の公式を覚え続けたほうがいいです.重要なのは、1つのアトリビュート値を書くと、繰り返し撮影される点線の長さしか定義できませんが、2つのアトリビュート値を書くと、点線間の空白に調整できます.歯を食いしばる
    StrokeDasharray={(私が望む弧の周長)(円の周長-1)}
    入力すれば、私が望むように線を引くことができます.
    ex) strokeDasharray = {2πr*0.25 2πr0.75}

    strokeDashoffset


    こいつは線を引く起点を設定する.これも円の周長値から簡単に計算できます.上の図で同じ弧を9点から12点に引くには、円の周長(1/4)のstrokeDashoffsetを設定するだけです.
    最初は12時がデフォルトになるように変換しました.ディポルトは3時だったのか.
    ex)strokeDasharray = {2πr0.25 2πr0.75} strokeDashoffset={2πr0.25}

    これを利用して、strokeDashoffsetを加算すればドーナツグラフを描くことができます.私はuseEffectレンダリング時にすべてのoffset値を事前に求め、useState配列に配置することで実現します.
    私は無責任にコードをあなたに投げて、あなたは自分で理解して、未来の私は......
    import React ,{useState, useEffect}from "react";
    import { algoScoreType } from "../types/algorithm.type";
    
    type ScoreCircleType = {
        size:number,
        stroke:number,
        score:algoScoreType
    }
    
    const scoreColor:{[index:string]:string} = {
        deathPerMatch:'red',
        KDAPerMatch:'orange',
        winRate:'yellow',
        maxDeathPerCount:'green',
        foreignLanguageRatio:'blue',
        positionRatio:'navy',
        champUseRatio:'purple',
        userLevel:'black',
        isPrevSeason:'white',
    }
    
    export default function ScoreCircle({size, stroke , score}:ScoreCircleType){
        const [offset, setOffset] = useState<{[index:string]:number}>({});
    
        useEffect(() => {
            setOffset(getOffset(score))
        }, [score]);
    
        const getOffset = (score:algoScoreType) =>{
            const arr:{[index:string]:number} = {};
            let prev = 0;
            Object.keys(score).forEach((v:string)=>{
                const value = score[v]
                console.log(prev)
                if(typeof value=="number"&& value){
                    arr[v] = value+prev
                    prev = value+prev
                }
                
            })
            console.log(arr)
            return arr
        }
        return(
           <svg  width={size} height={size} viewBox={"0 0 100 100"} style={{transform:'rotate(-90deg)'}}>
               {Object.keys(offset).length>0 && Object.keys(score).map((prop, index)=>{
                   const value = score[prop]
                   const color = scoreColor[prop]
                   if(typeof value=="number"&& value){
                        console.log(offset)
                        return(
                            <circle 
                            style={{zIndex:Object.keys(score).length-index}} 
                            stroke={color} 
                            cx={50} 
                            cy={50} 
                            r={45} 
                            strokeDasharray={`${2*Math.PI*45*(value/100)} ${2*Math.PI*45*(1-(value/100))}`} 
                            strokeDashoffset={`${2*Math.PI*45*(offset[prop])/100}`} 
                            fill={'none'} strokeWidth={stroke} />
                        )
                   }
                  
                })
                }
           </svg>
        )
    }
    ボロボロだけど…ははは

    考えましたが、特に太いタッチは必要ありません・・・
    ショートショット
    strokeLinecap={"round"}
    あげるなら使えます.
    それを理解すれば、アニメーションや上質なアプリケーションを与えることができます.