質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Chart.js

Chart.jsは、多様なグラフを組み込めるJavaScriptのライブラリ。折れ線グラフや棒グラフ、円グラフ、レーダーチャートなどのグラフの種類が用意されています。HTML5のCanvasを用いて描画され、マークアップも分かりやすく、簡単に編集することが可能です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

0回答

1822閲覧

chart.js 円グラフの外にラベルを表示したい

Kino104

総合スコア10

Chart.js

Chart.jsは、多様なグラフを組み込めるJavaScriptのライブラリ。折れ線グラフや棒グラフ、円グラフ、レーダーチャートなどのグラフの種類が用意されています。HTML5のCanvasを用いて描画され、マークアップも分かりやすく、簡単に編集することが可能です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2021/09/29 09:07

実現したいこと

イメージ説明
上の画像のように、円グラフの外側に00時〜23時までを表すラベルを表示したいです。

現在のコード

react

1import {Pie} from "react-chartjs-2"; 2import styled from "styled-components"; 3import { useEffect, useState } from "react"; 4import axios from "axios"; 5import ChartDataLabels from 'chartjs-plugin-datalabels'; 6import "chart.js"; 7import EditTimeRecord from "../pages/EditTimeRecord"; 8 9// styled-components → 10const Container = styled.div` 11 position: relative; 12 width: 330px; 13 margin: 30px auto 0 auto; 14 @media(min-width: 376px) { 15 width: 360px; 16 } 17 @media(min-width: 600px) { 18 width: 440px; 19 } 20 @media(min-width: 600px) and (min-height: 1000px) { 21 width: 570px; 22 } 23 @media(min-width: 900px) { 24 width: 50%; 25 max-width: 550px; 26 padding: 0; 27 margin-top: 0; 28 margin-left: 20px; 29 } 30 @media(min-width: 900px) and (min-height: 1000px) { 31 width: 750px; 32 max-width: 700px; 33 margin: 0 auto; 34 } 35`; 36const EditIcon = styled.i` 37 font-size: 30px; 38 position: absolute; 39 top: 0; 40 cursor: pointer; 41 &:hover { 42 opacity: 0.8; 43 } 44`; 45const NoDataContainer = styled.div` 46 position: relative; 47 width: 100%; 48 &::before { 49 padding-top: 100%; 50 content: ""; 51 display: block; 52 } 53`; 54const NoDataTitle = styled.div` 55 position: absolute; 56 top: 0; 57 left: 0; 58 bottom: 0; 59 right: 0; 60 display: flex; 61 align-items: center; 62 justify-content: center; 63 font-size: 20px; 64 border: 2px solid #0d0d0d; 65 border-radius: 50%; 66`; 67// ← styled-components 68 69const TimeChart = (props) => { 70 71 const [chartData, setChartData] = useState([]); 72 const [db, setDb] = useState(true); 73 const changeDb = () => { 74 setDb(!db); 75 } 76 77 let dateString = `${props.nowDay.getFullYear()},${props.nowDay.getMonth()+1},${props.nowDay.getDate()}` 78 79 useEffect(() => { 80 axios.get(`http://localhost:3001/timeLog/timeChart/${dateString}`, 81 { 82 headers: {accessToken: localStorage.getItem("accessToken")} 83 } 84 ).then((res) => { 85 const tmp = []; 86 res.data.forEach((data) => { 87 const startTimeData = data.start_time.split(","); 88 const startTime = new Date(startTimeData[0], startTimeData[1]-1, startTimeData[2], startTimeData[3], startTimeData[4]); 89 const finishTimeData = data.finish_time.split(","); 90 const finishTime = new Date(finishTimeData[0], finishTimeData[1]-1, finishTimeData[2],finishTimeData[3], finishTimeData[4]); 91 data.start_time = startTime; 92 data.finish_time = finishTime; 93 if (finishTime - startTime > 0) tmp.push(data); 94 }); 95 setChartData(tmp); 96 }); 97 }, [dateString, db, props.isDoing]); 98 99 if (chartData.length !== 0) { 100 chartData.sort((a, b) => a.start_time - b.start_time); 101 102 // アクションの開始日と終了日が異なっているときの処理 → 103 if ( 104 chartData[0].start_time.getDate() !== chartData[0].finish_time.getDate() 105 ) { 106 let tmp = chartData; 107 const newDate = chartData[0].start_time.getDate()+1; 108 tmp[0].start_time = new Date(chartData[0].start_time.getFullYear(), chartData[0].start_time.getMonth(), newDate); 109 setChartData(tmp); 110 } 111 if ( 112 chartData[chartData.length-1].start_time.getDate() !== chartData[chartData.length-1].finish_time.getDate() 113 ) { 114 let tmp = chartData; 115 const newDate = chartData[chartData.length-1].finish_time.getDate()-1; 116 tmp[chartData.length-1].finish_time = new Date(chartData[chartData.length-1].finish_time.getFullYear(), chartData[chartData.length-1].finish_time.getMonth(), newDate, 23, 59); 117 setChartData(tmp); 118 } 119 // ← アクションの開始日と終了日が異なっているときの処理 120 121 const makeFree = (start_time, finish_time) => { 122 return { 123 id: 'free', 124 item_name: "空き時間", 125 start_time: start_time, 126 finish_time: finish_time, 127 color: '#d5d5d5' 128 } 129 } 130 const ts = chartData[0].start_time; 131 if (ts - new Date(ts.getFullYear(), ts.getMonth(), ts.getDate()) > 0) { 132 const free = makeFree(new Date(ts.getFullYear(), ts.getMonth(), ts.getDate()), ts); 133 setChartData([...chartData, free]); 134 } 135 136 const tf = chartData[chartData.length -1].finish_time; 137 if (new Date(tf.getFullYear(), tf.getMonth(), tf.getDate(), 23, 59) - tf > 4*6000) { 138 const free = makeFree(tf, new Date(tf.getFullYear(), tf.getMonth(), tf.getDate(), 23, 59)); 139 setChartData([...chartData, free]); 140 } 141 142 for (let i = 0; i < chartData.length-1; i++) { 143 const timeLog = chartData[i+1].start_time - chartData[i].finish_time; 144 if (timeLog > 4) { 145 const free = makeFree(chartData[i].finish_time, chartData[i+1].start_time); 146 setChartData([...chartData, free]); 147 } 148 } 149 } 150 151 const times = []; 152 const labels = []; 153 const backgroundColors = []; 154 chartData.forEach((data) => { 155 let time = (data.finish_time - data.start_time) / (60 * 1000); 156 if (chartData[chartData.length-1] === data) time += 1; 157 times.push(time); 158 labels.push(data.item_name); 159 backgroundColors.push(data.color); 160 }); 161 162 const data = { 163 labels: labels, 164 datasets: [{ 165 data: times, 166 backgroundColor: backgroundColors, 167 borderWidth: 0, 168 //borderColor: '#fff', 169 datalabels: { 170 labels: { 171 data: { 172 align: 'start', 173 formatter: (value, context) => { 174 const label = context.chart.data.labels[context.dataIndex]; 175 let hour = ~~(value / 60); 176 const tmp = hour * 60; 177 let minutes = value - tmp; 178 hour = ("0" + hour).slice(-2); 179 minutes = ("0" + minutes).slice(-2); 180 if (label === "空き時間") return null; 181 return `${label}\n${hour}:${minutes}`; 182 }, 183 }, 184 } 185 } 186 }] 187 } 188 189 const options = { 190 plugins: { 191 datalabels: { 192 color: '#0d0d0d', 193 anchor: 'end', 194 font: { 195 size: 10, 196 }, 197 clamp: true, 198 }, 199 legend: { 200 display: false 201 }, 202 }, 203 } 204 205 const [isEditRecord, setIsEditRecord] = useState(false); 206 const changeIsEditRecord = (boolean) => { 207 setIsEditRecord(boolean); 208 } 209 210 return ( 211 <Container> 212 { 213 !isEditRecord ? ( 214 times.length !== 0 ? ( 215 <> 216 <Pie 217 data={data} 218 plugins={[ChartDataLabels]} 219 options={options} 220 /> 221 <EditIcon className="fas fa-edit" onClick={() => setIsEditRecord(true)}></EditIcon> 222 </> 223 ) : ( 224 <NoDataContainer> 225 <NoDataTitle>データがありません</NoDataTitle> 226 </NoDataContainer> 227 ) 228 ) : ( 229 <EditTimeRecord 230 chartData={chartData} 231 nowDay={props.nowDay} 232 changeIsEditRecord={changeIsEditRecord} 233 changeDb={changeDb} 234 /> 235 ) 236 } 237 </Container> 238 ); 239 240} 241 242export default TimeChart;

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問