web-dev-qa-db-fra.com

Comment contrôler le positionnement de la légende de mon graphique à secteurs Chart.JS, ainsi que son apparence?

Je suis capable de créer un camembert en utilisant Chart.JS avec ce code:

HTML

<div>
    <canvas id="top10ItemsChart" style="padding-left:20px" width="320" height="320"></canvas>
    <div id="top10Legend" class="chart-legend"></div>
</div>

jQuery

var data = [{
    value: 2755,
    color: "#FFE135",
    label: "Bananas"
}, {
    value: 2256,
    color: "#3B5323",
    label: "Lettuce, Romaine"
}, {
    value: 1637,
    color: "#fc6c85",
    label: "Melons, Watermelon"
}, {
    value: 1608,
    color: "#ffec89",
    label: "Pineapple"
}, {
    value: 1603,
    color: "#021c3d",
    label: "Berries"
}, {
    value: 1433,
    color: "#3B5323",
    label: "Lettuce, Spring Mix"
}, {
    value: 1207,
    color: "#046b00",
    label: "Broccoli"
}, {
    value: 1076,
    color: "#cef45a",
    label: "Melons, Honeydew"
}, {
    value: 1056,
    color: "#421C52",
    label: "Grapes"
}, {
    value: 1048,
    color: "#FEA620",
    label: "Melons, Cantaloupe"
}];

var optionsPie = { 
   legend: {
       display: true,
       position: 'right',
       labels: {
           fontColor: 'rgb(255, 99, 132)'
       }
  }
}

var ctx = $("#top10ItemsChart").get(0).getContext("2d");
var top10PieChart = new Chart(ctx).Pie(data, optionsPie);
document.getElementById('top10Legend').innerHTML = top10PieChart.generateLegend();

Le problème est qu’il place la légende au bas de la tarte, et même déborde et saigne en dehors des limites de la div à laquelle je veux que la tarte se limite:

enter image description here

Il présente également la légende comme une simple liste non ordonnée. Ce que je veux faire est de contrôler la couleur des différents éléments de la légende ("Banana" doit être de la même couleur (# FFE135) que le morceau de tarte à la banane (pour ainsi dire), etc.).

Comment puis-je faire correspondre les éléments individuels à la couleur de leur point de données respectif?

MISE À JOUR

La rubrique "Configuration de l'étiquette de légende" dans la documentation officielle ici indique que vous pouvez définir la police de caractères de la légende, mais cela s'applique à l'ensemble du Shebang; Ce que je veux savoir, c'est comment est-il possible de contrôler la couleur de chaque article?

MISE À JOUR 2

Pour tenter au moins d’afficher la légende à l’endroit désiré, j’ajoute ceci à jQuery:

var optionsPie = {
            legend: {
                display: true,
                position: 'right',
                labels: {
                    fontColor: 'rgb(255, 99, 132)'
                }
            }
        }

. . .
var myPieChart = new Chart(ctx).Pie(data, optionsPie);
document.getElementById("legendDiv").innerHTML = myPieChart.generateLegend();

... mais cela ne fait aucune différence - la légende est toujours suspendue au bas du graphique à secteurs et sa police reste le noir par défaut.

MISE À JOUR 3

J'ai utilisé certains codes suggérés, mais la légende est toujours alimentée par gravité au lieu d'être suspendue à droite:

enter image description here

Ainsi, la légende frappe le tableau en dessous, plutôt que de se limiter à son propre voisinage.

En outre, je ne veux pas que les points de balle infestent la légende - les carrés colorés (et le verbiage - mais aussi les valeurs) sont tout ce dont j'ai besoin. Comment puis-je pousser la légende du sud de la tourte à l'est de la tourte?

MISE À JOUR 4

J'ai refactored le code basé sur this et ça a l'air mieux (j'ai ajouté plus de données à la valeur "label" du tableau de données, aussi):

enter image description here

Cependant, comme vous pouvez le constater, la légende empiète sur le quadrant situé en dessous. Il y a cependant une "tonne" d'espace vide/perdu autour de la tarte. Je souhaite déplacer la tarte vers la gauche et la légende vers la droite. Cela permettrait également à la tarte de gagner de l’espace vertical.

Comment puis je faire ça? Voici le code que j'utilise maintenant:

HTML

<div>
    <canvas id="top10ItemsChart" class="pie" style="padding-left:20px"></canvas>
    <div id="top10Legend"></div>
</div>

CSS

.pie-legend {
    list-style: none;
    margin: 0;
    padding: 0;
}

    .pie-legend span {
        display: inline-block;
        width: 14px;
        height: 14px;
        border-radius: 100%;
        margin-right: 16px;
        margin-bottom: -2px;
    }

    .pie-legend li {
        margin-bottom: 10px;
        display: inline-block;
        margin-right: 10px;
    }

JQUERY

    var data = [{
        value: 2755,
        color: "#FFE135",
        label: "Bananas: 2,755 (18%)"
    }, {
. . .            
}, {
        value: 1048,
        color: "#FEA620",
        label: "Melons, Cantaloupe: 1,048 (7%)"
    }];

    var optionsPie = {
        responsive: true,
        scaleBeginAtZero: true,
        legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
    }

    var ctx = $("#top10ItemsChart").get(0).getContext("2d");
    var top10PieChart = new Chart(ctx).Pie(data, optionsPie);
    $("#top10Legend").html(top10PieChart.generateLegend());

[~ # ~] note [~ # ~] : ajout de ceci à optionsPie:

legend: {
    display: true,
    position: 'right'
},

... ne fait rien - la légende reste alourdie comme une grenouille remplie jusqu'au menton par une balle de caille.

MISE À JOUR 5

J'ai joué avec l'exemple de Teo, essayant de le faire fonctionner correctement mais, bien que ce soit mieux, la tarte est très chétive, et la légende devrait être plus large, mais je n'arrive pas à comprendre comment étirer la légende horizontalement et la tarte dans toutes les directions. Voici à quoi cela ressemble maintenant:

enter image description here

C'est le code maintenant (JQUERY est le même):

HTML

<div class="col-md-6">
    <div class="topleft">
        <h2 class="sectiontext">Top 10 Items</h2>
        <br />
        <div class="legendTable">
            <div class="legendCell">
                <canvas id="top10ItemsChart" class="pie" style="padding-left:20px"></canvas>
            </div>
            <div class="legendCell" id="top10Legend">
            </div>
        </div>
    </div>
</div>

CSS

    .topleft {
        margin-top: -4px;
        margin-left: 16px;
        margin-bottom: 16px;
        padding: 16px;
        border: 1px solid black;
    }

canvas {
    width: 100% !important;
    height: auto !important;
}

.legendTable {
    border: 1px solid forestgreen;
    display: table;
    width: 100%;
    table-layout: fixed;
}

.legendCell {
    display: table-cell;
    vertical-align: middle;
}

.pie-legend ul {
    list-style: none;
    margin: 0;
    padding: 0;
    width: 300px;
}

.pie-legend span {
    display: inline-block;
    width: 14px;
    height: 12px;
    border-radius: 100%;
    margin-right: 4px;
    margin-bottom: -2px;
}

.pie-legend li {
    margin-bottom: 4px;
    display: inline-block;
    margin-right: 4px;
}

Quelque chose écrase la tarte et rapproche les bords extérieurs de la légende.

MISE À JOUR 6

Ochi, et al: Voici ce que je vois après l'ochification de mon code:

enter image description here

Ceci est mon code - j'ai même commandé le jQuery de la façon dont vous l'avez, bien que je doute que ce soit vraiment nécessaire:

HTML

    <div class="row" id="top10Items">
        <div class="col-md-6">
            <div class="topleft">
                <h2 class="sectiontext">Top 10 Items</h2>
                <br />
                @*<div class="legendTable">
                    <div class="legendCell">
                        <canvas id="top10ItemsChart" class="pie" style="padding-left:20px"></canvas>
                    </div>
                    <div class="legendCell" id="top10Legend">
                    </div>
                </div>*@
                <div class="chart">
                    <canvas id="top10ItemsChart" class="pie"></canvas>
                    <div id="pie_legend"></div>
                </div>
            </div>
        </div>
    . . .
</div>

CSS

.pie-legend {
  list-style: none;
  margin: 0;
  padding: 0;
}

.pie-legend span {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 100%;
  margin-right: 16px;
  margin-bottom: -2px;
}

.pie-legend li {
  margin-bottom: 10px;
  display: block;
  margin-right: 10px;
}

.chart,
#priceComplianceBarChart,
#pie_legend {
  display: inline-flex;
  padding: 0;
  margin: 0;
}

JQUERY

var optionsPie = {
    responsive: true,
    scaleBeginAtZero: true,
    legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
}

var ctx = $("#top10ItemsChart").get(0).getContext("2d");

var data = [{
    value: 2755,
    color: "#FFE135",
    label: "Bananas: 2,755 (18%)"
    . . .
}, {
    value: 1048,
    color: "#FEA620",
    label: "Melons, Cantaloupe: 1,048 (7%)"
}];

var top10PieChart = new Chart(ctx).Pie(data, optionsPie);
$("#pie_legend").html(top10PieChart.generateLegend());

... et pourtant la tarte est plus extensible que le pantalon stretch d'un éléphant.

MISE À JOUR 7

Peut-être il y a un problème de configuration ou quelque chose. J'ai décidé de "passer" à la version 2.1.3 de Chart.JS (démarrée avec la version 1.0.2):

@*<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js"></script>*@
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.js"></script>

... et copié presque exactement le CodePen de Teo Dragovic ici .

Les seules choses que j'ai changées étaient les noms de deux classes CSS ("table" est devenu "legendTable" et "cell" est devenu "legendCell") et la couleur de la bordure de la table allant du rouge au vert forêt, et je comprends maintenant:

enter image description here

Dois-je également référencer un fichier CSS Chart.JS ou quelque chose de ce genre?

21
B. Clay Shannon

C'est ce qui fonctionne (plus ou moins) avec la version 2 de Chart.JS:

HTML

<h2 class="sectiontext">Top 10 Items</h2>
<br />
<div class="chart">
    <canvas id="top10ItemsChart" class="pie"></canvas>
    <div id="pie_legend"></div>
</div>

JQUERY

var data = {
    labels: [
        "Bananas: 2,755 (18%)",
        "Lettuce, Romaine: 2,256 (14%)",
        "Melons, Watermelon: 1,637 (10%)",
        "Pineapple: 1,608 (10%)",
        "Berries: 1,603 (10%)",
        "Lettuce, Spring Mix: 1,433 (9%)",
        "Broccoli: 1,207 (8%)",
        "Melons, Honeydew: 1,076 (7%)",
        "Grapes: 1,056 (7%)",
        "Melons, Cantaloupe: 1,048 (7%)"
    ],
    datasets: [
        {
            data: [2755, 2256, 1637, 1608, 1603, 1433, 1207, 1076, 1056, 1048],
            backgroundColor: [
                "#FFE135",
                "#3B5323",
                "#fc6c85",
                "#ffec89",
                "#021c3d",
                "#3B5323",
                "#046b00",
                "#cef45a",
                "#421C52",
                "#FEA620"
            ],
        }]
};

var optionsPie = {
    responsive: true,
    scaleBeginAtZero: true
}

var ctx = $("#top10ItemsChart").get(0).getContext("2d");
var top10PieChart = new Chart(ctx,
{
    type: 'pie',
    data: data,
    options: optionsPie
});

$("#top10Legend").html(top10PieChart.generateLegend());

Je dis "plus ou moins" parce que les morceaux de tarte sont encore pitoyablement chétifs:

enter image description here

0
B. Clay Shannon

Je pense que ce que vous voulez: DÉMO

Tout d’abord, vous devez rendre canvas réactif en remplaçant la largeur et la hauteur fixes et en l’enveloppant dans un supplément de div pouvant être utilisé pour le positionnement. J'ai utilisé display: table pour le centrage des éléments mais le réglage de la division intérieure sur inline-block fonctionne également si vous souhaitez que le graphique et la légende occupent un espace différent de 50:50.

HTML:

<div class="table">
    <div class="cell">
        <canvas id="top10ItemsChart" class="pie"></canvas>
    </div>
    <div class="cell" id="top10Legend"></div>
</div>

CSS:

canvas {
    width: 100% !important;
    height: auto !important;
}

.table {
    border: 1px solid red;
    display: table;
    width: 100%;
    table-layout: fixed;
}

.cell {
    display: table-cell;
    vertical-align: middle;
}

UPDATE: A effectué un ajustement basé sur des informations supplémentaires fournies par OP NEW DEMO

HTML:

<div class="container">
<div class="row">
<div class="col-md-6">
    <div class="topleft">
        <h2 class="sectiontext">Top 10 Items</h2>
        <br />
        <div class="chart">
            <div class="pie">
                <canvas id="top10ItemsChart" class="pie"></canvas>
            </div>
            <div class="legend" id="top10Legend">
            </div>
        </div>
    </div>
</div>
</div>
</div>

CSS:

    .topleft {
        margin-top: -4px;
        margin-left: 16px;
        margin-bottom: 16px;
        padding: 16px;
        border: 1px solid black;
    }

canvas {
    width: 100% !important;
    height: auto !important;
    margin-left: -25%;
}

.chart {
    border: 1px solid forestgreen;
    width: 100%;
    overflow: hidden;
    position: relative;
}

.pie {
    position: relative;
    padding: 10px 0;
    // adjust as necessary
    padding-left: 10px;
    padding-right: 0;
}

.legend {
    position: absolute;
    right: 10px;
    top: 10px;
    height: 100%;
    // adjust as necessary:
    width: 48%;
}

@media (max-width: 480px) {
    .legend {
        position: relative;
        width: 100%;
    }
    .pie {
        margin: 0;
    }
}

.pie-legend ul {
    list-style: none;
    margin: 0;
    padding: 0;
    width: 300px;
}

.pie-legend span {
    display: inline-block;
    width: 14px;
    height: 12px;
    border-radius: 100%;
    margin-right: 4px;
    margin-bottom: -2px;
}

.pie-legend li {
    margin-bottom: 4px;
    display: inline-block;
    margin-right: 4px;
}
14
Teo Dragovic

Comme @ B.ClayShannon l'a mentionné, la version 2 est assez différente de la version 1. Voici un exemple de personnalisation du modèle de légende à l'aide de la version 2.

options: {
    legendCallback: function (chart) {
        var text = [];
        text.Push('<ul class="' + chart.id + '-legend" style="list-style:none">');
        for (var i = 0; i < chart.data.datasets[0].data.length; i++) {
            text.Push('<li><div style="width:10px;height:10px;display:inline-block;background:' + chart.data.datasets[0].backgroundColor[i] + '" />&nbsp;');
            if (chart.data.labels[i]) {
                text.Push(chart.data.labels[i]);
            }
            text.Push('</li>');
        }
        text.Push('</ul>');

        return text.join('');
    },
    legend: {display: false},
}

Ce n'est pas indiqué directement dans la solution acceptée ci-dessus, mais pour rendre votre légende ailleurs, vous voudrez appeler:

$("#myChartLegend").html(myChart.generateLegend()); 

Enfin, du code HTML à rassembler (note clearfix est une classe Bootstrap qui:

<div class="chart">
    <div style="float:left">
        <canvas id="myChart" class="pie" style="max-width:300px;"></canvas>
    </div>

    <div class="legend" id="myChartLegend" style="float:left;"></div>
    <div style="clear: both;"/>
</div>
2
Domenic D.