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

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

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

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

JavaScript

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

Q&A

解決済

1回答

2892閲覧

Chart.jsにおける数値の反映とjavascriptでの配列の取得がうまくいかない

asahiko123

総合スコア43

Chart.js

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

JavaScript

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

0グッド

1クリップ

投稿2021/10/25 04:20

前提・実現したいこと

chart.jsに動的に値を設定したいのですが、
グラフに代入する値の取得がうまくいっていないようなので質問させて頂きます。

いま問題なのは、グラフの名前と、その名前に対応する数値のデータがcharts.jsにうまく反映できていないということです。

元データは以下のような配列です。

const group=[ { stuff: {name: 'A'} time: 60 style: {type: 'typeA'}}, { stuff: {name: 'A'} time: 120 style: {type: 'typeB'}}, { stuff: {name: 'A'} time: 83 style: {type: 'typeC'}}, { stuff: {name: 'B'} time: 257 style: {type: 'typeB'}}, { stuff: {name: 'B'} time: 120 style: {type: 'typeD'}}, { stuff: {name: 'B'} time: 66 style: {type: 'typeA'}}, { stuff: {name: 'A'} time: 0 style: {type: 'typeD'}}, { stuff: {name: 'B'} time: 0 style: {type: 'typeC'}} ]

この配列を反映したグラフを見ると、

イメージ説明
イメージ説明

BさんのtypeDの値(time=120)がAさんのtypeDの値に反映されています。
これをBさんのグラフのほうに反映するように直したいです。

グラフに反映するデータが入っている配列groupByは以下のように取得しています。
findIndexの条件を満たすelementの有無によって分類し、mapでtimeの値だけ取り出して
配列を作っています。

const groupBy= group.reduce((result,current)=>{ const element = result.findIndex(x=>x.type === current.style.type); if(element>=0){ result[element]={ stuff:result[element].name, type:result[element].type, values:[...result[element].values,current.time] } }else{ result.push({ stuff:current.stuff.name, type:current.style.type, values:[current.time] }) } return result },[]).map(y=>y.values);

不具合の原因はgroupBy[3]が[120,0]として取得されているせいだと思います。
elseの部分で

{ stuff: {name: 'B'} time: 120 style: {type: 'typeD'}}

が先に処理されるので[0,120]ではなく[120,0]として出力されてきます。
しかし名前と数値の対応が正しくなるためには[0,120]として取得されなければなりません。

groupByの中身 (4) [Array(2), Array(2), Array(2), Array(2)] 0: (2) [60, 66, _chartjs: {…}, push: ƒ, pop: ƒ, shift: ƒ, splice: ƒ, …] 1: (2) [120, 257, _chartjs: {…}, push: ƒ, pop: ƒ, shift: ƒ, splice: ƒ, …] 2: (2) [83, 0, _chartjs: {…}, push: ƒ, pop: ƒ, shift: ƒ, splice: ƒ, …] 3: (2) [120, 0]←これが[0,120]であってほしい length: 4
function drawCharts(){ var ctx = document.getElementById("myChart"); var myChart = new Chart(ctx, { type: 'bar', data: { labels: ['A','B'], datasets: [{ label: "typeA", borderWidth:1, backgroundColor: "#121554", borderColor: "#121554", data: groupBy[0] }, { label: "typeB", borderWidth:1, backgroundColor: "#1d3681", borderColor: "#1d3681", data: groupBy[1] },{ label: "typeC", borderWidth:1, backgroundColor: "#2e70a7", borderColor: "#2e70a7", data: groupBy[2] },{ label: "typeD", borderWidth:1, backgroundColor: "#4eadc7", borderColor: "#4eadc7", data: groupBy[3] },{ label: undefined, borderWidth:1, backgroundColor: "#a7d8bf", borderColor: "#a7d8bf", data: groupBy[4] }] }, options: { title: { display: true, text: '見出し', //グラフの見出し padding:3 }, scales: { xAxes: [{ stacked: true, //積み上げ棒グラフにする設定 categoryPercentage:0.4 //棒グラフの太さ }], yAxes: [{ stacked: true //積み上げ棒グラフにする設定 }] }, legend: { labels: { boxWidth:30, padding:20 //凡例の各要素間の距離 }, display: true }, tooltips:{ mode:'label' //マウスオーバー時に表示されるtooltip } } }); }

else部分になにかしらの条件をつけ足してなんとかならないかと思いましたが、
どのような条件が適切になるか分からなかったので、質問させて頂きました。

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

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

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

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

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

guest

回答1

0

ベストアンサー

たとえば質問文に記載されている配列 group の最後の要素を最初に持ってきてスクリプトを実行すると
groupBy は

text

1(4) [Array(2), Array(2), Array(2), Array(2)] 20: (2) [0, 83, _chartjs: {…}, push: ƒ, pop: ƒ, shift: ƒ, splice: ƒ, …] 31: (2) [60, 66, _chartjs: {…}, push: ƒ, pop: ƒ, shift: ƒ, splice: ƒ, …] 42: (2) [120, 257, _chartjs: {…}, push: ƒ, pop: ƒ, shift: ƒ, splice: ƒ, …] 53: (2) [120, 0]

となり、想定している順番と違ってしまいます。

そこで、groupBy を、ラベルと値を対応付けた連想配列にしてみます。

js

1const groupBy = group.reduce((result, current) => { 2 if (!result.hasOwnProperty(current.style.type)) { 3 result[current.style.type] = {}; 4 } 5 result[current.style.type][current.stuff.name] = current.time; 6 return result; 7}, {});

これにより、groupBy は以下のようなデータになります。

js

1{ 2 typeA: {A: 60, B: 66}, 3 typeB: {A: 120, B: 257}, 4 typeC: {B: 0, A: 83}, 5 typeD: {B: 120, A: 0} 6}

(A, Bの順番はバラバラですが、それぞれのラベルに対応した値になります)

 
これを、ラベルに対応したデータとしてChartのdatasetに適用すればよいのではないでしょうか。

js

1const types = [ 2 { name: "typeA", color: "#121554" }, 3 { name: "typeB", color: "#1d3681" }, 4 { name: "typeC", color: "#2e70a7" }, 5 { name: "typeD", color: "#4eadc7" }, 6 { name: "undefined", color: "#a7d8bf" }, 7]; 8 9const labels = ["A", "B"]; 10 11const datasets = types.map((e) => { 12 return { 13 label: e.name, 14 borderWidth: 1, 15 backgroundColor: e.color, 16 borderColor: e.color, 17 data: labels.map((i) => groupBy[e.name] && groupBy[e.name][i] || 0), 18 }; 19}); 20 21function drawCharts() { 22 var ctx = document.getElementById("myChart"); 23 var myChart = new Chart(ctx, { 24 type: "bar", 25 data: { 26 labels: labels, 27 datasets: datasets, 28 }, 29 // 略 30 }); 31} 32

投稿2021/10/25 12:46

編集2021/10/25 13:14
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

asahiko123

2021/10/26 03:09

ラベルと値を対応させた連想配列を作るという考えは大変参考になりました、 ありがとうございます。BAとさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問