Sphinx-Chart2
Comme tous mes plugins, ce script est publié sous licence CC BY 4.0.
Pourquoi Chart2 ? Parce qu’il y a un petit moment maintenant, j’avais fait une passerelle pour pouvoir utiliser Chart.js dans RPG Maker MV, disponible sur le forum rpgmakervx-fr.com, et je l’avais appelé Sphinx-Chart, tout simplement.
Toutefois, cette passerelle est loin d’être sans défaut. Aussi, j’y repensais et j’ai décidé de faire une version 2.0. Chart.js nécessite un canvas et son contexte 2D pour être utilisé. Et il se trouve que les sprites ont justement un attribut de type contexte 2D de canvas. J’ai donc tenté de passer ce canvas et ce contexte à cette librairie. Mais j’ai obtenu une erreur.
Ne me désarmant pas, j’ai décidé de passer outre, et, laissant derrière moi Chart.js ; qui est malgré tout une très bonne librairie, juste inadaptée pour RPG Maker MV ; j’ai décidé de coder des graphiques dans des sprites. Ce n’était pas chose aisée. Pas que ca ait été trop complexe, juste fastidieux en fait.
Et voilà le résultat : Sphinx-Chart2 !
Et après ?
Ce système s’appuie sur 3 scripts javascript. Le premier, c’est un script plus ou moins fourre-tout où j’enregistre les fonctions qui me servent dans plusieurs plugins, disponible ici : https://genie23.fr/js-rmmv/sphinx-polyfill/.
Ensuite, vous aurez besoin des définitions des différentes fonctions d’accélération. Je les ai réunies dans un sous objet de la classe statique Math, Math.easing, disponible ici : https://genie23.fr/js-rmmv/sphinx-matheasing/.
Ce script contient 22 courbes d’accélération pour animer différement l’ouverture des graphiques. Vous pouvez bien entendu en créer autant d’autres que vous le souhaitez, en les ajoutant à la sous classe Math.easing, elles seront utilisables automatiquement par les graphiques.
Et pour terminer, on va rentrer dans le vif du sujet. On est là pour parler graphiques, alors parlons graphiques :
//=============================================================================
// Sphinx-Chart2.js
//=============================================================================
/*:
* @plugindesc Graphique sous forme de sprite
* @author Sphinx
* @help
* //==========================================================================
* // Plugin : Sphinx-Chart2
* // Date : 29 décembre 2019
* // Auteur : Sphinx
* //==========================================================================
* Ce plugin ne contient aucune commande de plugin. Il met à disposition des
* scripteurs une nouvelle classe de sprite représentant des graphiques.
* Créer un graphique :
* variable = new SphinxChart2(
* type: TYPE_GRAPHIQUE,
* title: TITRE_GRAPHIQUE,
* categoriesLabels: LABELS_DE_CATEGORIES,
* xAxisLabels: LABELS_DES_ABSCISSES,
* datas: DONNEES,
* colors: COULEURS,
* options: OPTIONS
* );
* où :
* TYPE_GRAPHIQUE est l'un des types suivants :
* - line
* - bar
* - radar
* - pie
* - doughnut
* TITRE_GRAPHIQUE est une chaine de caractères qui sera affichée au
* dessus du graphique
* LABELS_DE_CATEGORIES est un tableau contenant la liste des étiquettes
* des légendes à afficher
* LABELS_DES_ABSCISSES est un tableau contenant la liste des étiquettes
* de l'axe des abscisses à afficher
* DONNEES est un tableau à 2 dimensions contenant les données à afficher
* Pour les graphiques pie et doughnut, utiliser un tableau à 1
* dimension
* COULEURS Liste des couleurs des données
* OPTIONS est un objet de configuration du graphique contenant les clés
* suivantes :
* - easing : méthode d'animation de la classe Math.easing
* - duration : durée de l'animation à l'ouverture du graphique
* - forceMinToZero: true - le graphique commencera forcément à 0
* false - configuration par défaut
* Inutilisé par les graphiques pie et doughnut
* - background : couleur(s) d'arrière plan. Chaine de caractères pour
* une couleur unie, tableau de chaines de caractères pour un
* dégradé, un objet Bitmap pour une image de fond
* - position : objet placant le graphique contenant les clés
* suivantes :
* - x : coordonnée X
* - y : coordonnée Y
* - width : largeur
* - height : hauteur
* - padding : objet définissant les marges de chaque côté contenant
* les clés suivantes :
* - top : marge en haut du graphique
* - left : marge à gauche du graphique
* - right : marge à droite du graphique
* - bottom : marge en bas du graphique
*
* Ensuite, il suffit de l'ajouter à la scène ou à une window comme un sprite
* ordinaire.
*
* Exemple de graphique :
* chart = new SphinxChart2({
* type: "line",
* title: "Test",
* categoriesLabels: [
* "Category 1",
* "Category 2",
* "Category 3"
* ],
* xAxisLabels: [
* "1", "2", "3", "4", "5"
* ],
* datas: [
* [ 5, 2, 1, 4, 3 ],
* [ 50, 21, 18, 34, 16 ],
* [ 8, 5, 3, 7, 9 ],
* ],
* colors: [
* "#0099FF",
* "#FF3300",
* "#00CC00",
* "#CC3399",
* "#FF9933",
* "#99CC00",
* "#009999",
* "#CC99FF"
* ],
* options: {
* easing: "easeOutQuart",
* duration: 1,
* background: "transparent",
* forceMinToZero: true,
* position: {
* x: 50,
* y: 50,
* width: 640,
* height: 480,
* },
* padding: {
* top: 0,
* left: 25,
* right: 25,
* bottom: 25,
* }
* }
* });
*
* - Dépendances : Sphinx-Polyfill
* Sphinx-MathEasing
*/
DEFAULT_COLORS = [
"DeepPink", "DodgerBlue", "Gold", "OrangeRed", "WhiteSmoke", "DarkViolet"
];
function SphinxChart2() {
this.initialize.apply(this, arguments);
};
SphinxChart2.prototype = Object.create(Sprite_Button.prototype);
SphinxChart2.prototype.constructor = SphinxChart2;
SphinxChart2.prototype.initialize = function(config) {
Sprite_Button.prototype.initialize.call(this);
// Configuration par défaut
this.config = config || {};
this.config.type = config.type || "line";
this.config.title = config.title || "";
this.config.categoriesLabels = config.categoriesLabels || [];
this.config.xAxisLabels = config.xAxisLabels || [];
this.config.datas = config.datas || [];
this.config.colors = config.colors || DEFAULT_COLORS;
this.config.options = config.options || {};
this.config.options.easing = config.options.easing || "linearTween";
this.config.options.duration = config.options.duration || 1;
this.config.options.background = config.options.background || "transparent";
this.config.options.forceMinToZero = config.options.forceMinToZero || false;
this.config.options.position = config.options.position || {};
this.config.options.position.x = config.options.position.x || 0;
this.config.options.position.y = config.options.position.y || 0;
this.config.options.position.width = config.options.position.width || 0;
this.config.options.position.height = config.options.position.height || 0;
this.config.options.padding = config.options.padding || {};
this.config.options.padding.top = config.options.padding.top || 0;
this.config.options.padding.left = config.options.padding.left || 0;
this.config.options.padding.right = config.options.padding.right || 0;
this.config.options.padding.bottom = config.options.padding.bottom || 0;
// Taille et position du sprite
this.x = this.config.options.position.x;
this.y = this.config.options.position.y;
this.width = this.config.options.position.width;
this.height = this.config.options.position.height;
// Récupération du contexte de dessin et initialisation du compteur de frames
this.frame = 0;
this.bitmap = new Bitmap(this.width, this.height);
this.context = this.bitmap._context;
// Gestion du clic
this.setClickHandler(SphinxChart2.prototype.onTouch.bind(this));
};
SphinxChart2.prototype.update = function() {
Sprite_Button.prototype.update.call(this);
// Mise à jour du graphisme
this.drawFrame();
// Mise à jour du compteur de frames
++this.frame;
};
SphinxChart2.prototype.onTouch = function() {
// Mise à jour du compteur de frames
this.frame = 0;
};
SphinxChart2.prototype.drawFrame = function() {
// Si l'animation est finie, on sort
if(this.frame > this.config.options.duration * 60) return;
// Nettoyage du cache
this.context.clearRect(0, 0, this.width, this.height);
// Dessin de l'arrière plan
if(this.config.options.background instanceof Bitmap) {
backgroundResize = {};
if(this.config.options.background.width / this.config.options.background.height > this.width / this.height) {
backgroundResize.width = this.width;
backgroundResize.height = this.width / (this.config.options.background.width / this.config.options.background.height);
backgroundResize.top = (this.height - backgroundResize.height) / 2;
backgroundResize.left = 0;
} else {
backgroundResize.width = this.height * this.config.options.background.width / this.config.options.background.height;
backgroundResize.height = this.height;
backgroundResize.top = 0;
backgroundResize.left = (this.width - backgroundResize.width) / 2;
}
this.bitmap.blt(this.config.options.background, 0, 0, this.config.options.background.width, this.config.options.background.height, backgroundResize.left, backgroundResize.top, backgroundResize.width, backgroundResize.height);
} else if(this.config.options.background instanceof Array && this.config.options.background.length > 1) {
gradient = this.context.createLinearGradient(0, 0, 0, this.height);
gradient.addColorStop(0, this.config.options.background[0]);
for(i = 1; i < this.config.options.background.length; ++i) {
gradient.addColorStop(i / (this.config.options.background.length - 1), this.config.options.background[i]);
}
this.context.fillStyle = gradient;
this.context.fillRect(0, 0, this.width, this.height);
} else if(this.config.options.background instanceof Array) {
this.context.fillStyle = this.config.options.background[0];
this.context.fillRect(0, 0, this.width, this.height);
} else {
this.context.fillStyle = this.config.options.background;
this.context.fillRect(0, 0, this.width, this.height);
}
// Calcul de la hauteur et écriture du titre
if(this.config.title.length > 0) {
titleHeight = this.bitmap.measureTextHeight(this.config.title);
this.bitmap.fontSize = 28;
this.context.font = this.bitmap._makeFontNameText();
this.context.textAlign = "center";
this.context.fillStyle = "black";
this.context.fillText(this.config.title, this.width / 2, titleHeight + this.config.options.padding.top, this.width);
}
// Math.easing[this.config.options.easing](this.frame, 50, 285, this.config.options.duration * 60);
legendPosition = "bottom";
switch(this.config.type) {
case "line":
this.drawLineFrame();
break;
case "bar":
this.drawBarFrame();
break;
case "radar":
this.drawRadarFrame();
break;
case "pie":
legendPosition = "right";
this.drawPieFrame();
break;
case "doughnut":
legendPosition = "right";
this.drawDoughnutFrame();
break;
}
// Calcul de la largeur des légendes
legendsWidth = 0;
for(category of this.config.categoriesLabels) {
legendsWidth += 60 + this.bitmap.measureTextWidth(category);
}
// Ecriture des légendes
legendsLeft = (this.width - legendsWidth) / 2
for(i = 0; i < this.config.categoriesLabels.length; ++i) {
// Nom de la catégorie
category = this.config.categoriesLabels[i];
// Ecriture de la couleur (rectangle)
this.context.save();
this.context.globalAlpha = 0.59765625;
this.context.fillStyle = this.config.colors[i % this.config.colors.length];
this.context.fillRect(legendsLeft, this.height - categoriesHeight, 30, categoriesHeight - 5);
this.context.restore();
this.context.lineWidth = 2;
this.context.strokeStyle = this.config.colors[i % this.config.colors.length];
this.context.strokeRect(legendsLeft, this.height - categoriesHeight, 30, categoriesHeight - 5);
legendsLeft += 40;
// Ecriture du nom de la catégorie
this.context.textAlign = "left";
this.context.fillStyle = "black";
this.context.fillText(category, legendsLeft, this.height - 8);
legendsLeft += this.bitmap.measureTextWidth(category) + 20;
}
// Réécriture du dessin
this.bitmap._setDirty();
};
//-----------------------------------------------------------------------------
// Line chart
SphinxChart2.prototype.drawLineFrame = function() {
// Récupération de la hauteur du titre
titleHeight = 0;
if(this.config.title.length > 0) {
titleHeight = this.bitmap.measureTextHeight(this.config.title);
}
// Taille de la police des axes
this.bitmap.fontSize = 18;
// Récupération de la police
this.context.font = this.bitmap._makeFontNameText();
// Récupération des bornes des données
datasMin = null;
if(this.config.options.forceMinToZero) datasMin = 0;
datasMax = null;
datasCountMax = 0;
for(datasCategory of this.config.datas) {
if(datasMin == null) datasMin = Math.min(...datasCategory);
else datasMin = Math.min(datasMin, ...datasCategory);
if(datasMax == null) datasMax = Math.max(...datasCategory);
else datasMax = Math.max(datasMax, ...datasCategory);
datasCountMax = Math.max(datasCountMax, datasCategory.length);
}
yAxisLimitMin = Math.floor(datasMin / 5) * 5;
yAxisLimitMax = Math.ceil(datasMax / 5) * 5;
// Calcul de la hauteur des étiquettes de l'axe des abscisses
xAxisHeight = 0;
for(label of this.config.xAxisLabels) {
height = this.bitmap.measureTextHeight(label);
xAxisHeight = Math.max(xAxisHeight, height);
}
// Calcul de la hauteur des catégories
categoriesHeight = 0;
for(category of this.config.categoriesLabels) {
height = this.bitmap.measureTextHeight(category);
categoriesHeight = Math.max(categoriesHeight, height);
}
// Coordonnées de l'axe des abscisses
xAxis = {};
xAxis.width = this.width - Math.max(this.bitmap.measureTextWidth(yAxisLimitMin), this.bitmap.measureTextWidth(yAxisLimitMax)) - this.config.options.padding.left - this.config.options.padding.right;
// Coordonnées de l'axe des ordonnées
yAxis = {};
yAxis.left = this.config.options.padding.left + Math.max(this.bitmap.measureTextWidth(yAxisLimitMin), this.bitmap.measureTextWidth(yAxisLimitMax));
yAxis.top = titleHeight + this.config.options.padding.top + 10;
yAxis.height = this.height - titleHeight - xAxisHeight - categoriesHeight - this.config.options.padding.top - this.config.options.padding.bottom;
// Dessin des axes des abscisses et des ordonnées
this.context.beginPath();
this.context.moveTo(yAxis.left, yAxis.top);
this.context.lineTo(yAxis.left, yAxis.top + yAxis.height);
this.context.lineTo(yAxis.left + xAxis.width, yAxis.top + yAxis.height);
this.context.lineWidth = 2;
this.context.strokeStyle = "#999999";
this.context.stroke();
// Ajout de labels manquants sur l'axe des abscisses
if(this.config.xAxisLabels.length < datasCountMax) {
for(i = this.config.xAxisLabels.length + 1; i <= datasCountMax; ++i) {
this.config.xAxisLabels.push(i);
}
}
// Ajout de labels manquants sur l'axe des ordonnées
if(this.config.categoriesLabels.length < this.config.datas.length) {
for(i = this.config.categoriesLabels.length + 1; i <= this.config.datas.length; ++i) {
this.config.categoriesLabels.push("Category " + i);
}
} else if(this.config.categoriesLabels.length > this.config.datas.length) {
this.config.categoriesLabels = this.config.categoriesLabels.slice(0, this.config.datas.length);
}
// Ecriture des étiquettes des abscisses
xAxisGapWidth = xAxis.width / (datasCountMax - 1);
for(i = 0; i < datasCountMax; ++i) {
// Repère abscisse
this.context.beginPath();
this.context.moveTo(yAxis.left + xAxisGapWidth * i, yAxis.top + yAxis.height - 10);
this.context.lineTo(yAxis.left + xAxisGapWidth * i, yAxis.top + yAxis.height + 10);
this.context.lineWidth = 2;
this.context.strokeStyle = "#999999";
this.context.stroke();
// Prolongement repère abscisse
if(i > 0) {
this.context.beginPath();
this.context.moveTo(yAxis.left + xAxisGapWidth * i, yAxis.top + yAxis.height - 10);
this.context.lineTo(yAxis.left + xAxisGapWidth * i, yAxis.top);
this.context.lineWidth = 2;
this.context.strokeStyle = "#CCCCCC";
this.context.stroke();
}
// Etiquette abscisse
this.context.textAlign = "center";
this.context.fillStyle = "black";
labelHeight = this.bitmap.measureTextHeight(this.config.xAxisLabels[i]);
this.context.fillText(this.config.xAxisLabels[i], yAxis.left + xAxisGapWidth * i, yAxis.top + yAxis.height + labelHeight + 5, xAxisGapWidth);
}
// Ecriture des étiquettes des ordonnées
i = 5;
yAxisTotalGap = Math.ceil((yAxisLimitMax - yAxisLimitMin) / 5) * 5;
yAxisGap = Math.ceil(yAxisTotalGap / i / 5) * 5;
yAxisLimitMax = yAxisLimitMin + (yAxisGap * 5);
yAxisGapHeight = yAxis.height / (yAxisGap * 5 / yAxisGap);
for(i = 5; i >= 0; --i) {
// Label abscisse
yAxisLabel = yAxisLimitMax - yAxisGap * i;
// Repère ordonnée
this.context.beginPath();
this.context.moveTo(yAxis.left - 10, yAxis.top + yAxisGapHeight * i);
this.context.lineTo(yAxis.left + 10, yAxis.top + yAxisGapHeight * i);
this.context.lineWidth = 2;
this.context.strokeStyle = "#999999";
this.context.stroke();
// Prolongement repère ordonnée
if(i < 5) {
this.context.beginPath();
this.context.moveTo(yAxis.left + 10, yAxis.top + yAxisGapHeight * i);
this.context.lineTo(yAxis.left + xAxis.width, yAxis.top + yAxisGapHeight * i);
this.context.lineWidth = 2;
this.context.strokeStyle = "#CCCCCC";
this.context.stroke();
}
// Etiquette ordonnée
this.context.textAlign = "right";
this.context.fillStyle = "black";
labelHeight = this.bitmap.measureTextHeight(yAxisLabel);
this.context.fillText(yAxisLabel, yAxis.left - 15, yAxis.top + yAxisGapHeight * i + labelHeight / 4);
}
// Tracé des données du graphique
easing = Math.easing[this.config.options.easing];
for(i = 0; i < this.config.datas.length; ++i) {
// Données de la catégorie
datasCategory = this.config.datas[i];
// Graphique
this.context.beginPath();
for(j = 0; j < datasCategory.length; ++j) {
data = datasCategory[j];
y = easing(this.frame, yAxis.top + yAxis.height, -yAxisGapHeight * (data - yAxisLimitMin) / yAxisGap, this.config.options.duration * 60);
if(j == 0) {
this.context.moveTo(yAxis.left, y);
} else {
this.context.lineTo(yAxis.left + xAxisGapWidth * j, y);
}
}
this.context.lineWidth = 2;
this.context.strokeStyle = this.config.colors[i % this.config.colors.length];
this.context.stroke();
}
};
//-----------------------------------------------------------------------------
// Bar chart
SphinxChart2.prototype.drawBarFrame = function() {
// Récupération de la hauteur du titre
titleHeight = 0;
if(this.config.title.length > 0) {
titleHeight = this.bitmap.measureTextHeight(this.config.title);
}
// Taille de la police des axes
this.bitmap.fontSize = 18;
// Récupération de la police
this.context.font = this.bitmap._makeFontNameText();
// Récupération des bornes des données
datasMin = null;
if(this.config.options.forceMinToZero) datasMin = 0;
datasMax = null;
datasCountMax = 0;
for(datasCategory of this.config.datas) {
if(datasMin == null) datasMin = Math.min(...datasCategory);
else datasMin = Math.min(datasMin, ...datasCategory);
if(datasMax == null) datasMax = Math.max(...datasCategory);
else datasMax = Math.max(datasMax, ...datasCategory);
datasCountMax = Math.max(datasCountMax, datasCategory.length);
}
yAxisLimitMin = Math.floor(datasMin / 5) * 5;
yAxisLimitMax = Math.ceil(datasMax / 5) * 5;
// Calcul de la hauteur des étiquettes de l'axe des abscisses
xAxisHeight = 0;
for(label of this.config.xAxisLabels) {
height = this.bitmap.measureTextHeight(label);
xAxisHeight = Math.max(xAxisHeight, height);
}
// Calcul de la hauteur des catégories
categoriesHeight = 0;
for(category of this.config.categoriesLabels) {
height = this.bitmap.measureTextHeight(category);
categoriesHeight = Math.max(categoriesHeight, height);
}
// Ajout de labels manquants sur l'axe des abscisses
if(this.config.xAxisLabels.length < datasCountMax) {
for(i = this.config.xAxisLabels.length + 1; i <= datasCountMax; ++i) {
this.config.xAxisLabels.push(i);
}
}
// Ajout de labels manquants sur l'axe des ordonnées
if(this.config.categoriesLabels.length < this.config.datas.length) {
for(i = this.config.categoriesLabels.length + 1; i <= this.config.datas.length; ++i) {
this.config.categoriesLabels.push("Category " + i);
}
} else if(this.config.categoriesLabels.length > this.config.datas.length) {
this.config.categoriesLabels = this.config.categoriesLabels.slice(0, this.config.datas.length);
}
// Coordonnées de l'axe des abscisses
xAxis = {};
xAxis.width = this.width - Math.max(this.bitmap.measureTextWidth(yAxisLimitMin), this.bitmap.measureTextWidth(yAxisLimitMax)) - this.config.options.padding.left - this.config.options.padding.right;
// Coordonnées de l'axe des ordonnées
yAxis = {};
yAxis.left = this.config.options.padding.left + Math.max(this.bitmap.measureTextWidth(yAxisLimitMin), this.bitmap.measureTextWidth(yAxisLimitMax));
yAxis.top = titleHeight + this.config.options.padding.top + 10;
yAxis.height = this.height - titleHeight - xAxisHeight - categoriesHeight - this.config.options.padding.top - this.config.options.padding.bottom;
// Dessin des axes des abscisses et des ordonnées
this.context.beginPath();
this.context.moveTo(yAxis.left, yAxis.top);
this.context.lineTo(yAxis.left, yAxis.top + yAxis.height);
this.context.lineTo(yAxis.left + xAxis.width, yAxis.top + yAxis.height);
this.context.lineWidth = 2;
this.context.strokeStyle = "#999999";
this.context.stroke();
// Ecriture des étiquettes des abscisses
xAxisGapWidth = xAxis.width / datasCountMax;
this.context.beginPath();
this.context.moveTo(yAxis.left, yAxis.top + yAxis.height - 10);
this.context.lineTo(yAxis.left, yAxis.top + yAxis.height + 10);
this.context.lineWidth = 2;
this.context.strokeStyle = "#999999";
this.context.stroke();
for(i = 0; i < datasCountMax; ++i) {
// Repère abscisse
this.context.beginPath();
this.context.moveTo(yAxis.left + xAxisGapWidth * (i + 1), yAxis.top + yAxis.height - 10);
this.context.lineTo(yAxis.left + xAxisGapWidth * (i + 1), yAxis.top + yAxis.height + 10);
this.context.lineWidth = 2;
this.context.strokeStyle = "#999999";
this.context.stroke();
// Prolongement repère abscisse
this.context.beginPath();
this.context.moveTo(yAxis.left + xAxisGapWidth * (i + 1), yAxis.top + yAxis.height - 10);
this.context.lineTo(yAxis.left + xAxisGapWidth * (i + 1), yAxis.top);
this.context.lineWidth = 2;
this.context.strokeStyle = "#CCCCCC";
this.context.stroke();
// Etiquette abscisse
this.context.textAlign = "center";
this.context.fillStyle = "black";
labelHeight = this.bitmap.measureTextHeight(this.config.xAxisLabels[i]);
this.context.fillText(this.config.xAxisLabels[i], yAxis.left + xAxisGapWidth * i + xAxisGapWidth / 2, yAxis.top + yAxis.height + labelHeight + 5, xAxisGapWidth);
}
// Ecriture des étiquettes des ordonnées
i = 5;
yAxisTotalGap = Math.ceil((yAxisLimitMax - yAxisLimitMin) / 5) * 5;
yAxisGap = Math.ceil(yAxisTotalGap / i / 5) * 5;
yAxisLimitMax = yAxisLimitMin + (yAxisGap * 5);
yAxisGapHeight = yAxis.height / (yAxisGap * 5 / yAxisGap);
for(i = 5; i >= 0; --i) {
// Label abscisse
yAxisLabel = yAxisLimitMax - yAxisGap * i;
// Repère ordonnée
this.context.beginPath();
this.context.moveTo(yAxis.left - 10, yAxis.top + yAxisGapHeight * i);
this.context.lineTo(yAxis.left + 10, yAxis.top + yAxisGapHeight * i);
this.context.lineWidth = 2;
this.context.strokeStyle = "#999999";
this.context.stroke();
// Prolongement repère ordonnée
if(i < 5) {
this.context.beginPath();
this.context.moveTo(yAxis.left + 10, yAxis.top + yAxisGapHeight * i);
this.context.lineTo(yAxis.left + xAxis.width, yAxis.top + yAxisGapHeight * i);
this.context.lineWidth = 2;
this.context.strokeStyle = "#CCCCCC";
this.context.stroke();
}
// Etiquette ordonnée
this.context.textAlign = "right";
this.context.fillStyle = "black";
labelHeight = this.bitmap.measureTextHeight(yAxisLabel);
this.context.fillText(yAxisLabel, yAxis.left - 15, yAxis.top + yAxisGapHeight * i + labelHeight / 4);
}
// Tracé des données du graphique
easing = Math.easing[this.config.options.easing];
for(i = 0; i < this.config.datas.length; ++i) {
// Données de la catégorie
datasCategory = this.config.datas[i];
// Graphique
widthWithSpace = xAxisGapWidth / this.config.datas.length;
widthWithoutSpace = xAxisGapWidth / (this.config.datas.length + 1);
widthSpace = widthWithSpace - widthWithoutSpace;
for(j = 0; j < datasCategory.length; ++j) {
data = datasCategory[j];
width = widthWithoutSpace;
height = easing(this.frame, 0, (data - yAxisLimitMin) * yAxisGapHeight / yAxisGap, this.config.options.duration * 60);
x = yAxis.left + xAxisGapWidth * j + widthWithSpace * i + widthSpace / 2;
y = yAxis.top + yAxis.height - height;
this.context.lineWidth = 2;
this.context.strokeStyle = this.config.colors[i % this.config.colors.length];
this.context.strokeRect(x, y, width, height);
this.context.save();
this.context.globalAlpha = 0.59765625;
this.context.fillStyle = this.config.colors[i % this.config.colors.length];
this.context.fillRect(x, y, width, height);
this.context.restore();
}
}
};
//-----------------------------------------------------------------------------
// Radar chart
SphinxChart2.prototype.drawRadarFrame = function() {
// Récupération de la hauteur du titre
titleHeight = 0;
if(this.config.title.length > 0) {
titleHeight = this.bitmap.measureTextHeight(this.config.title);
}
// Taille de la police des axes
this.bitmap.fontSize = 18;
// Récupération de la police
this.context.font = this.bitmap._makeFontNameText();
// Récupération des bornes des données
datasMin = null;
if(this.config.options.forceMinToZero) datasMin = 0;
datasMax = null;
datasCountMax = 0;
for(datasCategory of this.config.datas) {
if(datasMin == null) datasMin = Math.min(...datasCategory);
else datasMin = Math.min(datasMin, ...datasCategory);
if(datasMax == null) datasMax = Math.max(...datasCategory);
else datasMax = Math.max(datasMax, ...datasCategory);
datasCountMax = Math.max(datasCountMax, datasCategory.length);
}
yAxisLimitMin = Math.floor(datasMin / 5) * 5;
yAxisLimitMax = Math.ceil(datasMax / 5) * 5;
// Calcul de la hauteur des étiquettes de l'axe des abscisses
xAxisHeight = 0;
for(label of this.config.xAxisLabels) {
height = this.bitmap.measureTextHeight(label);
xAxisHeight = Math.max(xAxisHeight, height);
}
// Calcul de la hauteur des catégories
categoriesHeight = 0;
for(category of this.config.categoriesLabels) {
height = this.bitmap.measureTextHeight(category);
categoriesHeight = Math.max(categoriesHeight, height);
}
// Ajout de labels manquants sur l'axe des abscisses
if(this.config.xAxisLabels.length < datasCountMax) {
for(i = this.config.xAxisLabels.length + 1; i <= datasCountMax; ++i) {
this.config.xAxisLabels.push(i);
}
}
// Ajout de labels manquants sur l'axe des ordonnées
if(this.config.categoriesLabels.length < this.config.datas.length) {
for(i = this.config.categoriesLabels.length + 1; i <= this.config.datas.length; ++i) {
this.config.categoriesLabels.push("Category " + i);
}
} else if(this.config.categoriesLabels.length > this.config.datas.length) {
this.config.categoriesLabels = this.config.categoriesLabels.slice(0, this.config.datas.length);
}
// Angle, rayon et centre du radar
degreesAngle = 360 / datasCountMax;
ray = Math.min(this.width - 40, this.height - titleHeight - categoriesHeight - 40) / 2;
centerX = this.width / 2;
centerY = titleHeight + ray + 20;
// Dessin des rayons
for(i = 0; i < datasCountMax; ++i) {
this.context.beginPath();
this.context.moveTo(centerX, centerY);
this.context.lineTo(centerX + ray * Math.cos(((270 + degreesAngle * i) % 360) * Math.PI / 180), centerY + ray * Math.sin(((270 + degreesAngle * i) % 360) * Math.PI / 180));
this.context.lineWidth = 2;
this.context.strokeStyle = "#999999";
this.context.stroke();
}
// Ecriture des étiquettes des abscisses
for(i = 0; i < this.config.xAxisLabels.length; ++i) {
label = this.config.xAxisLabels[i];
this.context.textAlign = "center";
this.context.fillStyle = "black";
this.context.fillText(label, centerX + (ray + 10) * Math.cos(((270 + degreesAngle * i) % 360) * Math.PI / 180), centerY + (ray + 10) * Math.sin(((270 + degreesAngle * i) % 360) * Math.PI / 180));
}
// Ecriture des étiquettes des ordonnées
i = 5;
yAxisTotalGap = Math.ceil((yAxisLimitMax - yAxisLimitMin) / 5) * 5;
yAxisGap = Math.ceil(yAxisTotalGap / i / 5) * 5;
yAxisLimitMax = yAxisLimitMin + (yAxisGap * 5);
yAxisGapHeight = ray / (yAxisGap * 5 / yAxisGap);
for(i = 0; i <= 5; ++i) {
// Label abscisse
yAxisLabel = yAxisLimitMin + yAxisGap * i;
y = centerY - (ray / 5 * i);
// Repère ordonnée
this.context.beginPath();
this.context.moveTo(centerX + ray / 5 * i * Math.cos(270 * Math.PI / 180), centerY + ray / 5 * i * Math.sin(270 * Math.PI / 180));
for(j = 0; j <= datasCountMax; ++j) {
this.context.lineTo(centerX + ray / 5 * i * Math.cos(((270 + degreesAngle * j) % 360) * Math.PI / 180), centerY + ray / 5 * i * Math.sin(((270 + degreesAngle * j) % 360) * Math.PI / 180));
}
this.context.lineWidth = 2;
this.context.strokeStyle = "#CCCCCC";
this.context.stroke();
// Etiquette ordonnée
this.context.textAlign = "right";
this.context.fillStyle = "black";
labelHeight = this.bitmap.measureTextHeight(yAxisLabel);
this.context.fillText(yAxisLabel, centerX - 10, centerY - ray / 5 * i + 10);
}
// Tracé des données du graphique
easing = Math.easing[this.config.options.easing];
for(i = 0; i < this.config.datas.length; ++i) {
// Données de la catégorie
datasCategory = this.config.datas[i];
// Graphique
dataRay = easing(this.frame, 0, ray * (datasCategory[0] - yAxisLimitMin) / (yAxisLimitMax - yAxisLimitMin), this.config.options.duration * 60);
this.context.beginPath();
this.context.moveTo(centerX + dataRay * Math.cos(270 * Math.PI / 180), centerY + dataRay * Math.sin(270 * Math.PI / 180));
for(j = 0; j < datasCategory.length; ++j) {
data = datasCategory[j];
dataRay = easing(this.frame, 0, ray * (data - yAxisLimitMin) / (yAxisLimitMax - yAxisLimitMin), this.config.options.duration * 60);
this.context.lineTo(centerX + dataRay * Math.cos(((270 + degreesAngle * j) % 360) * Math.PI / 180), centerY + dataRay * Math.sin(((270 + degreesAngle * j) % 360) * Math.PI / 180));
}
this.context.lineWidth = 2;
this.context.strokeStyle = this.config.colors[i % this.config.colors.length];
this.context.stroke();
this.context.save();
this.context.globalAlpha = 0.59765625;
this.context.fillStyle = this.config.colors[i % this.config.colors.length];
this.context.fill();
this.context.restore();
}
};
//-----------------------------------------------------------------------------
// Pie chart
SphinxChart2.prototype.drawPieFrame = function() {
// Récupération de la hauteur du titre
titleHeight = 0;
if(this.config.title.length > 0) {
titleHeight = this.bitmap.measureTextHeight(this.config.title);
}
// Taille de la police des axes
this.bitmap.fontSize = 18;
// Récupération de la police
this.context.font = this.bitmap._makeFontNameText();
// Calcul de la hauteur des catégories
categoriesHeight = 0;
for(category of this.config.categoriesLabels) {
height = this.bitmap.measureTextHeight(category);
categoriesHeight = Math.max(categoriesHeight, height);
}
// Ajout de labels manquants sur l'axe des ordonnées
if(this.config.categoriesLabels.length < this.config.datas.length) {
for(i = this.config.categoriesLabels.length + 1; i <= this.config.datas.length; ++i) {
this.config.categoriesLabels.push("Category " + i);
}
} else if(this.config.categoriesLabels.length > this.config.datas.length) {
this.config.categoriesLabels = this.config.categoriesLabels.slice(0, this.config.datas.length);
}
// Rayon et centre du camembert
ray = Math.min(this.width - 40, this.height - titleHeight - categoriesHeight - 40) / 2;
centerX = this.width / 2;
centerY = titleHeight + ray + 20;
// Tracé des données du graphique
easing = Math.easing[this.config.options.easing];
// Calcul du total des données
sumDatas = 0;
for(data of this.config.datas) {
sumDatas += data;
}
// Dessin du camembert
lastDegreesAngle = 270;
for(i = 0; i < this.config.datas.length; ++i) {
// Données de la catégorie
data = this.config.datas[i];
nextDegreesAngle = (lastDegreesAngle + easing(this.frame, 0, 360 * data / sumDatas, this.config.options.duration * 60)) % 360;
// Graphique
this.context.beginPath();
this.context.moveTo(centerX, centerY);
this.context.lineTo(centerX + ray * Math.cos(lastDegreesAngle * Math.PI / 180), centerY + ray * Math.sin(lastDegreesAngle * Math.PI / 180));
this.context.arc(centerX, centerY, ray, lastDegreesAngle * Math.PI / 180, nextDegreesAngle * Math.PI / 180);
this.context.lineWidth = 2;
this.context.strokeStyle = this.config.colors[i % this.config.colors.length];
this.context.stroke();
this.context.save();
this.context.globalAlpha = 0.59765625;
this.context.fillStyle = this.config.colors[i % this.config.colors.length];
this.context.fill();
this.context.restore();
// Décallage
lastDegreesAngle = nextDegreesAngle;
}
};
//-----------------------------------------------------------------------------
// Doughnut chart
SphinxChart2.prototype.drawDoughnutFrame = function() {
// Récupération de la hauteur du titre
titleHeight = 0;
if(this.config.title.length > 0) {
titleHeight = this.bitmap.measureTextHeight(this.config.title);
}
// Taille de la police des axes
this.bitmap.fontSize = 18;
// Récupération de la police
this.context.font = this.bitmap._makeFontNameText();
// Calcul de la hauteur des catégories
categoriesHeight = 0;
for(category of this.config.categoriesLabels) {
height = this.bitmap.measureTextHeight(category);
categoriesHeight = Math.max(categoriesHeight, height);
}
// Ajout de labels manquants sur l'axe des ordonnées
if(this.config.categoriesLabels.length < this.config.datas.length) {
for(i = this.config.categoriesLabels.length + 1; i <= this.config.datas.length; ++i) {
this.config.categoriesLabels.push("Category " + i);
}
} else if(this.config.categoriesLabels.length > this.config.datas.length) {
this.config.categoriesLabels = this.config.categoriesLabels.slice(0, this.config.datas.length);
}
// Rayon et centre du camembert
ray = Math.min(this.width - 40, this.height - titleHeight - categoriesHeight - 40) / 2;
centerX = this.width / 2;
centerY = titleHeight + ray + 20;
// Tracé des données du graphique
easing = Math.easing[this.config.options.easing];
// Calcul du total des données
sumDatas = 0;
for(data of this.config.datas) {
sumDatas += data;
}
// Dessin du camembert
lastDegreesAngle = 270;
for(i = 0; i < this.config.datas.length; ++i) {
// Données de la catégorie
data = this.config.datas[i];
nextDegreesAngle = (lastDegreesAngle + easing(this.frame, 0, 360 * data / sumDatas, this.config.options.duration * 60)) % 360;
// Graphique
this.context.beginPath();
this.context.moveTo(centerX + ray / 2 * Math.cos(lastDegreesAngle * Math.PI / 180), centerY + ray / 2 * Math.sin(lastDegreesAngle * Math.PI / 180));
this.context.lineTo(centerX + ray * Math.cos(lastDegreesAngle * Math.PI / 180), centerY + ray * Math.sin(lastDegreesAngle * Math.PI / 180));
this.context.arc(centerX, centerY, ray, lastDegreesAngle * Math.PI / 180, nextDegreesAngle * Math.PI / 180);
this.context.lineTo(centerX + ray / 2 * Math.cos(nextDegreesAngle * Math.PI / 180), centerY + ray / 2 * Math.sin(nextDegreesAngle * Math.PI / 180));
this.context.arc(centerX, centerY, ray / 2, nextDegreesAngle * Math.PI / 180, lastDegreesAngle * Math.PI / 180, true);
this.context.lineWidth = 2;
this.context.strokeStyle = this.config.colors[i % this.config.colors.length];
this.context.stroke();
this.context.save();
this.context.globalAlpha = 0.59765625;
this.context.fillStyle = this.config.colors[i % this.config.colors.length];
this.context.fill();
this.context.restore();
// Décallage
lastDegreesAngle = nextDegreesAngle;
}
};
C’est un sacré bloc. Il contient la définition des 5 formes de graphiques actuellement prises en charge.
Bon d’accord, et comment on s’en sert ?
Actuellement, ce plugin ne pourra être utile qu’à des scripteurs qui souhaiteraient intégrer l’affichage d’un ou de plusieurs graphiques dans leur script. Un exemple d’utilisation pourraient être d’afficher les statistiques du joueur différemment, sous forme d’un graphique (type radar par exemple).
Ca doit être tordu à utiliser sans doute…
Effectivement, pour afficher un graphique, il faut en passer par une étape assez éprouvante : dire au système ce qu’il doit afficher et comment. Toutes les informations à ce sujet sont disponibles dans l’entête du plugin.
Du boulot, du boulot, encore du boulot… Et pour quel résultat d’abord ?
Pour tester ces graphiques, j’ai bricolé une scène dans un plugin annexe. Celui-ci n’est pas requis pour utiliser le système, mais si vous voulez un apercu des possibilités, je vous recommande de l’ajouter et de démarrer la scène :
//=============================================================================
// Sphinx-Chart2Scene.js
//=============================================================================
/*:
* @plugindesc Scène de démonstration du plugin Sphinx-Chart2
* @author Sphinx
*
* @help
* //==========================================================================
* // Plugin : Sphinx-Chart2Scene
* // Date : 30 décembre 2019
* // Auteur : Sphinx
* //==========================================================================
*
* Dépendances :
* - Sphinx-Chart2
* @param background
* @text Image d'arrière plan de la scène
* @type file
* @dir img/titles1/
* @require 1
*
* @param enemies
* @text Images d'arrière plan des graphiques
* @type file[]
* @dir img/enemies/
* @require 1
*/
CHART_TYPES = [ "line", "bar", "radar", "pie", "doughnut" ];
AVAILABLE_EASING = [ "linearTween", "easeInQuad", "easeOutQuad", "easeInOutQuad", "easeInCubic", "easeOutCubic", "easeInOutCubic", "easeInQuart", "easeOutQuart", "easeInOutQuart", "easeInQuint", "easeOutQuint", "easeInOutQuint", "easeInSine", "easeOutSine", "easeInOutSine", "easeInExpo", "easeOutExpo", "easeInOutExpo", "easeInCirc", "easeOutCirc", "easeInOutCirc" ];
SYLLABES_DEBUT = [ "Bi", "Tor", "Teri", "Alim", "Cre", "Dri", "Epi", "Fra", "Gro", "Hima", "Jutu", "Kima", "Lu", "Mi", "No", "Noto", "Ori", "Pru", "Qu", "Ria", "Su", "Umako", "Vime", "Wito", "Xi", "Ya", "Zumo", "Api", "Bele", "Cepi", "Do", "Ea", "Fe", "Gato", "Holo", "Ipe", "Jo", "Kala", "Lara", "Meta", "Noxa", "Orra", "Pi", "Quima", "Ro", "Sele", "Ule", "Vi", "Waxa", "Xo", "Yora", "Zuli" ];
SYLLABES_FIN = [ "von", "oll", "tol", "gon", "prim", "tes", "lup", "vim", "qua", "pip", "am", "lm", "thor", "gig", "ve", "qum", "la", "leuth", "bas", "ro", "porr", "lia", "w", "kra", "cor", "mmon" ];
BACKGROUND_IMAGES = JSON.parse(PluginManager.parameters("Sphinx-Chart2Scene")["enemies"]);
CSS_COLORS = [ "AliceBlue", "AntiqueWhite", "Aqua", "Aquamarine", "Azure", "Beige", "Bisque", "Black", "BlanchedAlmond", "Blue", "BlueViolet", "Brown", "BurlyWood", "CadetBlue", "Chartreuse", "Chocolate", "Coral", "CornflowerBlue", "Cornsilk", "Crimson", "Cyan", "DarkBlue", "DarkCyan", "DarkGoldenRod", "DarkGray", "DarkGrey", "DarkGreen", "DarkKhaki", "DarkMagenta", "DarkOliveGreen", "DarkOrange", "DarkOrchid", "DarkRed", "DarkSalmon", "DarkSeaGreen", "DarkSlateBlue", "DarkSlateGray", "DarkSlateGrey", "DarkTurquoise", "DarkViolet", "DeepPink", "DeepSkyBlue", "DimGray", "DimGrey", "DodgerBlue", "FireBrick", "FloralWhite", "ForestGreen", "Fuchsia", "Gainsboro", "GhostWhite", "Gold", "GoldenRod", "Gray", "Grey", "Green", "GreenYellow", "HoneyDew", "HotPink", "IndianRed", "Indigo", "Ivory", "Khaki", "Lavender", "LavenderBlush", "LawnGreen", "LemonChiffon", "LightBlue", "LightCoral", "LightCyan", "LightGoldenRodYellow", "LightGray", "LightGrey", "LightGreen", "LightPink", "LightSalmon", "LightSeaGreen", "LightSkyBlue", "LightSlateGray", "LightSlateGrey", "LightSteelBlue", "LightYellow", "Lime", "LimeGreen", "Linen", "Magenta", "Maroon", "MediumAquaMarine", "MediumBlue", "MediumOrchid", "MediumPurple", "MediumSeaGreen", "MediumSlateBlue", "MediumSpringGreen", "MediumTurquoise", "MediumVioletRed", "MidnightBlue", "MintCream", "MistyRose", "Moccasin", "NavajoWhite", "Navy", "OldLace", "Olive", "OliveDrab", "Orange", "OrangeRed", "Orchid", "PaleGoldenRod", "PaleGreen", "PaleTurquoise", "PaleVioletRed", "PapayaWhip", "PeachPuff", "Peru", "Pink", "Plum", "PowderBlue", "Purple", "RebeccaPurple", "Red", "RosyBrown", "RoyalBlue", "SaddleBrown", "Salmon", "SandyBrown", "SeaGreen", "SeaShell", "Sienna", "Silver", "SkyBlue", "SlateBlue", "SlateGray", "SlateGrey", "Snow", "SpringGreen", "SteelBlue", "Tan", "Teal", "Thistle", "Tomato", "Turquoise", "Violet", "Wheat", "White", "WhiteSmoke", "Yellow", "YellowGreen" ];
//-----------------------------------------------------------------------------
// Game_Interpreter
//
// Commandes de plugin
Sphinx_Chart_Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args) {
Sphinx_Chart_Game_Interpreter_pluginCommand.call(this, command, args);
if(command === "DEMO_GRAPH") {
SceneManager.push(Scene_Chart2);
}
};
//-----------------------------------------------------------------------------
// Scene_Chart2
//
// Scène de démonstration du plugin Sphinx-Chart2
function Scene_Chart2() {
this.initialize.apply(this, arguments);
};
Scene_Chart2.prototype = Object.create(Scene_Base.prototype);
Scene_Chart2.prototype.constructor = Scene_Chart2;
Scene_Chart2.prototype.initialize = function() {
Scene_Base.prototype.initialize.call(this);
};
Scene_Chart2.prototype.create = function() {
Scene_Base.prototype.create.call(this);
this.createWindowLayer();
this.createBackground();
this.createWindows();
this.createTexts();
};
Scene_Chart2.prototype.start = function() {
Scene_Base.prototype.start.call(this);
this.startFadeIn(this.fadeSpeed(), false);
this._windowTypeChart.open();
};
Scene_Chart2.prototype.terminate = function() {
Scene_Base.prototype.terminate.call(this);
SceneManager.goto(Scene_Map);
this.startFadeOut(this.fadeSpeed(), false);
};
Scene_Chart2.prototype.update = function() {
Scene_Base.prototype.update.call(this);
if(Input.isTriggered("cancel")) {
SoundManager.playCancel();
this.terminate();
}
};
Scene_Chart2.prototype.createBackground = function() {
this._background = new Sprite_Base();
background = PluginManager.parameters("Sphinx-Chart2Scene")["background"];
this._background.bitmap = ImageManager.loadTitle1(background);
this.addChildAt(this._background, 0);
};
Scene_Chart2.prototype.createWindows = function() {
this._windowTypeChart = new Window_TypeChart();
for(type of CHART_TYPES) {
this._windowTypeChart.setHandler("draw_" + type, this.chooseEasing.bind(this, type));
}
this.addWindow(this._windowTypeChart);
this._windowChooseEasing = new Window_ChooseEasing();
for(easing of AVAILABLE_EASING) {
this._windowChooseEasing.setHandler("choose_" + easing, this.changeGraph.bind(this, easing));
}
this.addWindow(this._windowChooseEasing);
};
Scene_Chart2.prototype.createTexts = function() {
this._titleText = new Sprite_Base();
this._titleText.x = 0;
this._titleText.y = 0;
this._titleText.width = Graphics.boxWidth;
this._titleText.height = (Graphics.boxHeight - 480) / 2;
this._titleText.bitmap = new Bitmap(Graphics.boxWidth, (Graphics.boxHeight - 480) / 2);
this._titleText.bitmap.drawText("Démonstration - Sphinx-Chart2", 0, 16, Graphics.boxWidth - 32, 40, "center");
this.addChildAt(this._titleText, 2);
this._explicationText1 = new Sprite_Base();
this._explicationText1.x = 0;
this._explicationText1.y = Graphics.boxHeight - ((Graphics.boxHeight - 480) / 2);
this._explicationText1.width = Graphics.boxWidth;
this._explicationText1.height = (Graphics.boxHeight - 480) / 4;
this._explicationText1.bitmap = new Bitmap(Graphics.boxWidth, (Graphics.boxHeight - 480) / 4);
this._explicationText1.bitmap.fontSize = 18;
this._explicationText1.bitmap.drawText("Choisissez un type de graphique, puis un type d'accélération.", 0, 8, Graphics.boxWidth - 32, 20, "center");
this.addChildAt(this._explicationText1, 3);
this._explicationText2 = new Sprite_Base();
this._explicationText2.x = 0;
this._explicationText2.y = Graphics.boxHeight - ((Graphics.boxHeight - 480) / 4);
this._explicationText2.width = Graphics.boxWidth;
this._explicationText2.height = (Graphics.boxHeight - 480) / 4;
this._explicationText2.bitmap = new Bitmap(Graphics.boxWidth, (Graphics.boxHeight - 480) / 4);
this._explicationText2.bitmap.fontSize = 18;
this._explicationText2.bitmap.drawText("Vous pouvez cliquer sur le graphique pour relancer l'animation.", 0, 8, Graphics.boxWidth - 32, 20, "center");
this.addChildAt(this._explicationText2, 4);
};
Scene_Chart2.prototype.chooseEasing = function(type) {
if(this.chart) this.removeChild(this.chart);
this.type = type;
this._windowChooseEasing.open();
this._windowChooseEasing.activate();
}
Scene_Chart2.prototype.changeGraph = function(easing) {
this._windowChooseEasing.close();
categories = this.getCategories(this.type);
xLabels = this.getXLabels(this.type);
datas = this.getDatas(this.type);
background = this.getRandomChartBackground();
console.log(this.type, datas);
this.chart = new SphinxChart2({
type: this.type,
title: this.type.capitalize() + " - " + easing.capitalize(),
categoriesLabels: categories,
xAxisLabels: xLabels,
datas: datas,
options: {
easing: easing,
duration: 1,
background: background,
forceMinToZero: false,
position: {
x: 166,
y: (Graphics.boxHeight - 480) / 2,
width: 640,
height: 480,
},
padding: {
top: 10,
left: 25,
right: 25,
bottom: 25,
}
}
});
this.addChildAt(this.chart, 1);
this._windowTypeChart.activate();
};
Scene_Chart2.prototype.getCategories = function(type) {
switch(type) {
case "line":
case "bar":
case "radar":
case "pie":
case "doughnut":
noms = [];
for(i = 1; i <= 10; ++i) {
noms.push(SYLLABES_DEBUT[Math.randomIntBetween(0, SYLLABES_DEBUT.length)] + SYLLABES_FIN[Math.randomIntBetween(0, SYLLABES_FIN.length)]);
}
return noms;
}
};
Scene_Chart2.prototype.getXLabels = function(type) {
switch(type) {
case "line":
return [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
case "bar":
case "radar":
noms = [];
for(i = 1; i <= 10; ++i) {
noms.push(SYLLABES_DEBUT[Math.randomIntBetween(0, SYLLABES_DEBUT.length)] + SYLLABES_FIN[Math.randomIntBetween(0, SYLLABES_FIN.length)]);
}
return noms;
case "pie":
case "doughnut":
return null;
}
};
Scene_Chart2.prototype.getDatas = function(type) {
switch(type) {
case "line":
case "bar":
case "radar":
datas = [];
numberDatasInCategory = Math.randomIntBetween(2, 11);
maxI = Math.randomIntBetween(2, 6);
for(i = 1; i <= maxI; ++i) {
datasCategory = [];
for(j = 1; j <= numberDatasInCategory; ++j) {
datasCategory.push(Math.randomIntBetween(5, 51));
}
datas.push(datasCategory);
}
return datas;
case "pie":
case "doughnut":
datas = [];
for(i = 1; i <= Math.randomIntBetween(2, 6); ++i) {
datas.push(Math.randomIntBetween(5, 51));
}
return datas;
}
};
Scene_Chart2.prototype.getRandomChartBackground = function() {
switch(Math.randomIntBetween(0, 4)) {
case 0:
return "transparent";
case 1:
if(BACKGROUND_IMAGES.length == 0) return "transparent";
return ImageManager.loadEnemy(BACKGROUND_IMAGES[Math.randomIntBetween(0, BACKGROUND_IMAGES.length)]);
case 2:
colors = [];
for(i = 1; i <= Math.randomIntBetween(2, 11); ++i) {
colors.push(CSS_COLORS[Math.randomIntBetween(0, CSS_COLORS.length)]);
}
return colors;
case 3:
return CSS_COLORS[Math.randomIntBetween(0, CSS_COLORS.length)];
}
};
Scene_Chart2.prototype.fastForwardRate = function() {
return 3;
};
Scene_Chart2.prototype.isFastForward = function() {
return (Input.isPressed('ok') || Input.isPressed('shift') || TouchInput.isPressed());
};
Scene_Chart2.prototype.updateFade = function() {
if(this._fadeDuration > 0) {
var d = this._fadeDuration;
if(this.isFastForward()) {
d -= this.fastForwardRate() - 1;
this._fadeDuration -= this.fastForwardRate();
} else {
this._fadeDuration--;
}
if(this._fadeSign > 0) {
this._fadeSprite.opacity -= this._fadeSprite.opacity / d;
} else {
this._fadeSprite.opacity += (255 - this._fadeSprite.opacity) / d;
}
}
};
Scene_Chart2.prototype.fadeSpeed = function(ignoreFast) {
return 30;
};
//-----------------------------------------------------------------------------
// Window_TypeChart
//
// Fenêtre de sélection du type du graphique
function Window_TypeChart() {
this.initialize.apply(this, arguments);
};
Window_TypeChart.prototype = Object.create(Window_Command.prototype);
Window_TypeChart.prototype.constructor = Window_TypeChart;
Window_TypeChart.prototype.initialize = function() {
Window_Command.prototype.initialize.call(this, 0, 0);
this.updatePlacement();
};
Window_TypeChart.prototype.windowWidth = function() {
return 150;
};
Window_TypeChart.prototype.updatePlacement = function() {
this.x = 8;
this.y = (Graphics.boxHeight - this.height) / 2;
};
Window_TypeChart.prototype.makeCommandList = function() {
for(type of CHART_TYPES) {
this.addCommand(type.capitalize(), "draw_" + type);
}
};
Window_TypeChart.prototype.isContinueEnabled = function() {
return DataManager.isAnySavefileExists();
};
//-----------------------------------------------------------------------------
// Window_ChooseEasing
//
// Fenêtre de sélection du type d'accélération
function Window_ChooseEasing() {
this.initialize.apply(this, arguments);
};
Window_ChooseEasing.prototype = Object.create(Window_Command.prototype);
Window_ChooseEasing.prototype.constructor = Window_ChooseEasing;
Window_ChooseEasing.prototype.initialize = function() {
Window_Command.prototype.initialize.call(this, 0, 0);
this.close();
this.updatePlacement();
};
Window_ChooseEasing.prototype.maxCols = function() {
return 3;
};
Window_ChooseEasing.prototype.windowWidth = function() {
return Graphics.boxWidth - 64;
};
Window_ChooseEasing.prototype.updatePlacement = function() {
this.x = (Graphics.boxWidth - this.width) / 2;
this.y = (Graphics.boxHeight - this.height) / 2;
};
Window_ChooseEasing.prototype.makeCommandList = function() {
for(easing of AVAILABLE_EASING) {
this.addCommand(easing.capitalize(), "choose_" + easing);
}
};
Window_ChooseEasing.prototype.isContinueEnabled = function() {
return DataManager.isAnySavefileExists();
};
Cette scène se démarre au moyen de la commande de plugin suivante : DEMO_GRAPH.
Voici quelques exemples de graphiques (réalisés au moyen de cette scène de démonstration) :



Outre ces types de graphiques, le système permet de gérer également des graphiques camenbert et donnuts.
Enjoy it !