Added category distribution charts. Improved software charts.
This commit is contained in:
parent
34b574b023
commit
0bc73f661e
9 changed files with 277 additions and 19 deletions
|
@ -52,6 +52,7 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import fr.devinsy.strings.StringList;
|
import fr.devinsy.strings.StringList;
|
||||||
import fr.devinsy.strings.StringsUtils;
|
import fr.devinsy.strings.StringsUtils;
|
||||||
|
import fr.devinsy.xidyn.utils.XidynUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Class StatoolInfosUtils.
|
* The Class StatoolInfosUtils.
|
||||||
|
@ -80,6 +81,30 @@ public class StatoolInfosUtils
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape JSONXML.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* the data
|
||||||
|
* @return the string
|
||||||
|
*/
|
||||||
|
public static String escapeJSONXML(final String data)
|
||||||
|
{
|
||||||
|
String result;
|
||||||
|
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = XidynUtils.escapeXmlBlank(data.replace('\'', ' '));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File local date time.
|
* File local date time.
|
||||||
*
|
*
|
||||||
|
|
|
@ -67,10 +67,6 @@ public class FederationStatsPage
|
||||||
|
|
||||||
TagDataManager data = new TagDataManager();
|
TagDataManager data = new TagDataManager();
|
||||||
|
|
||||||
data.setContent("serviceCountMonthChart", Htmlizer.htmlizeServiceCountMonthChart(federation));
|
|
||||||
data.setContent("serviceCountYearChart", Htmlizer.htmlizeServiceCountYearChart(federation));
|
|
||||||
data.setContent("serviceDateStatusChart", Htmlizer.htmlizeServiceDateStatusChart(federation.getAllServices()));
|
|
||||||
|
|
||||||
data.setContent("turnoutChart", Htmlizer.htmlizeOrganizationTurnoutChart(federation.getOrganizations()));
|
data.setContent("turnoutChart", Htmlizer.htmlizeOrganizationTurnoutChart(federation.getOrganizations()));
|
||||||
data.setContent("organizationCountryChart", Htmlizer.htmlizeOrganizationCountryChart(federation.getOrganizations()));
|
data.setContent("organizationCountryChart", Htmlizer.htmlizeOrganizationCountryChart(federation.getOrganizations()));
|
||||||
data.setContent("organizationCountChart", Htmlizer.htmlizeOrganizationCountChart(federation));
|
data.setContent("organizationCountChart", Htmlizer.htmlizeOrganizationCountChart(federation));
|
||||||
|
@ -113,6 +109,15 @@ public class FederationStatsPage
|
||||||
data.setContent("registrationClientTypeChart", DoughnutChartView.build(pie));
|
data.setContent("registrationClientTypeChart", DoughnutChartView.build(pie));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.setContent("serviceCountMonthChart", Htmlizer.htmlizeServiceCountMonthChart(federation));
|
||||||
|
data.setContent("serviceCountYearChart", Htmlizer.htmlizeServiceCountYearChart(federation));
|
||||||
|
data.setContent("serviceDateStatusChart", Htmlizer.htmlizeServiceDateStatusChart(federation.getAllServices()));
|
||||||
|
|
||||||
|
data.setContent("softwareDistributionChart", Htmlizer.htmlizeSoftwareDistributionChart());
|
||||||
|
data.setContent("softwareDistributionPieChart", Htmlizer.htmlizeSoftwareDistributionPieChart(federation.getAllServices()));
|
||||||
|
data.setContent("categoryDistributionChart", Htmlizer.htmlizeCategoryDistributionChart());
|
||||||
|
data.setContent("categoryDistributionPieChart", Htmlizer.htmlizeCatergoryDistributionPieChart(federation.getAllServices()));
|
||||||
|
|
||||||
//
|
//
|
||||||
String content = PresenterUtils.dynamize("/fr/devinsy/statoolinfos/htmlize/federationStats.xhtml", data).toString();
|
String content = PresenterUtils.dynamize("/fr/devinsy/statoolinfos/htmlize/federationStats.xhtml", data).toString();
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import fr.devinsy.statoolinfos.HtmlizerContext;
|
import fr.devinsy.statoolinfos.HtmlizerContext;
|
||||||
|
import fr.devinsy.statoolinfos.core.Categories;
|
||||||
import fr.devinsy.statoolinfos.core.Category;
|
import fr.devinsy.statoolinfos.core.Category;
|
||||||
import fr.devinsy.statoolinfos.core.Configuration;
|
import fr.devinsy.statoolinfos.core.Configuration;
|
||||||
import fr.devinsy.statoolinfos.core.Federation;
|
import fr.devinsy.statoolinfos.core.Federation;
|
||||||
|
@ -49,12 +50,16 @@ import fr.devinsy.statoolinfos.htmlize.charts.PieChartView;
|
||||||
import fr.devinsy.statoolinfos.properties.PathProperty;
|
import fr.devinsy.statoolinfos.properties.PathProperty;
|
||||||
import fr.devinsy.statoolinfos.properties.PathPropertyList;
|
import fr.devinsy.statoolinfos.properties.PathPropertyList;
|
||||||
import fr.devinsy.statoolinfos.stats.StatAgent;
|
import fr.devinsy.statoolinfos.stats.StatAgent;
|
||||||
|
import fr.devinsy.statoolinfos.stats.categories.CategoryStat;
|
||||||
|
import fr.devinsy.statoolinfos.stats.categories.CategoryStats;
|
||||||
import fr.devinsy.statoolinfos.stats.country.CountryStats;
|
import fr.devinsy.statoolinfos.stats.country.CountryStats;
|
||||||
import fr.devinsy.statoolinfos.stats.organizations.OrganizationTurnoutStats;
|
import fr.devinsy.statoolinfos.stats.organizations.OrganizationTurnoutStats;
|
||||||
import fr.devinsy.statoolinfos.stats.services.HostProviderTypeStats;
|
import fr.devinsy.statoolinfos.stats.services.HostProviderTypeStats;
|
||||||
import fr.devinsy.statoolinfos.stats.services.HostServerTypeStats;
|
import fr.devinsy.statoolinfos.stats.services.HostServerTypeStats;
|
||||||
import fr.devinsy.statoolinfos.stats.services.RegistrationStats;
|
import fr.devinsy.statoolinfos.stats.services.RegistrationStats;
|
||||||
import fr.devinsy.statoolinfos.stats.services.ServiceInstallTypeStats;
|
import fr.devinsy.statoolinfos.stats.services.ServiceInstallTypeStats;
|
||||||
|
import fr.devinsy.statoolinfos.stats.softwares.SoftwareStat;
|
||||||
|
import fr.devinsy.statoolinfos.stats.softwares.SoftwareStats;
|
||||||
import fr.devinsy.statoolinfos.util.URLUtils;
|
import fr.devinsy.statoolinfos.util.URLUtils;
|
||||||
import fr.devinsy.strings.StringList;
|
import fr.devinsy.strings.StringList;
|
||||||
|
|
||||||
|
@ -201,6 +206,92 @@ public class Htmlizer
|
||||||
SocialNetworksPage.buildAll();
|
SocialNetworksPage.buildAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Htmlize category distribution chart.
|
||||||
|
*
|
||||||
|
* @return the string
|
||||||
|
* @throws StatoolInfosException
|
||||||
|
* the statool infos exception
|
||||||
|
*/
|
||||||
|
public static String htmlizeCategoryDistributionChart() throws StatoolInfosException
|
||||||
|
{
|
||||||
|
String result;
|
||||||
|
|
||||||
|
BarChart chart;
|
||||||
|
|
||||||
|
chart = new BarChart("Distribution des catégories les plus proposées");
|
||||||
|
chart.addDataset("Catégories");
|
||||||
|
|
||||||
|
Federation federation = HtmlizerContext.instance().getFederation();
|
||||||
|
Categories categories = HtmlizerContext.instance().getCategories();
|
||||||
|
|
||||||
|
CategoryStats stats = StatAgent.statAllCategories(federation, categories);
|
||||||
|
stats.sortByServiceCount().reverse();
|
||||||
|
|
||||||
|
for (CategoryStat stat : stats)
|
||||||
|
{
|
||||||
|
if (stat.getServiceCount() > 0)
|
||||||
|
{
|
||||||
|
chart.add(stat.getCategory().getName(), stat.getServiceCount(), ChartColor.PURPLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = BarChartView.build(chart);
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Htmlize catergory distribution pie chart.
|
||||||
|
*
|
||||||
|
* @param services
|
||||||
|
* the services
|
||||||
|
* @return the string
|
||||||
|
* @throws StatoolInfosException
|
||||||
|
* the statool infos exception
|
||||||
|
*/
|
||||||
|
public static String htmlizeCatergoryDistributionPieChart(final Services services) throws StatoolInfosException
|
||||||
|
{
|
||||||
|
String result;
|
||||||
|
|
||||||
|
Federation federation = HtmlizerContext.instance().getFederation();
|
||||||
|
Categories categories = HtmlizerContext.instance().getCategories();
|
||||||
|
|
||||||
|
CategoryStats stats = StatAgent.statAllCategories(federation, categories);
|
||||||
|
stats.sortByServiceCount().reverse();
|
||||||
|
|
||||||
|
ChartColors colors = ChartColor.valueList();
|
||||||
|
colors.remove(ChartColor.BLUE);
|
||||||
|
|
||||||
|
PieChart pie = new PieChart("Distribution des catégories");
|
||||||
|
int index = 0;
|
||||||
|
while ((index < stats.size() && (index < 10)))
|
||||||
|
{
|
||||||
|
ChartColor color = colors.get(index);
|
||||||
|
CategoryStat stat = stats.get(index);
|
||||||
|
pie.add(StringUtils.abbreviate(stat.getCategory().getName(), 30), stat.getServiceCount(), color);
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int others = 0;
|
||||||
|
while (index < stats.size())
|
||||||
|
{
|
||||||
|
CategoryStat stat = stats.get(index);
|
||||||
|
others += stat.getServiceCount();
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
pie.add("Autres", others, ChartColor.BLUE);
|
||||||
|
pie.setLegendPosition(Position.RIGHT);
|
||||||
|
|
||||||
|
result = DoughnutChartView.build(pie);
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Htmlize host provider type chart.
|
* Htmlize host provider type chart.
|
||||||
*
|
*
|
||||||
|
@ -514,7 +605,7 @@ public class Htmlizer
|
||||||
|
|
||||||
BarChart chart;
|
BarChart chart;
|
||||||
|
|
||||||
chart = new BarChart("Nombre de services (mois)");
|
chart = new BarChart("Nombre de services déclarés (mois)");
|
||||||
chart.addDataset("Services");
|
chart.addDataset("Services");
|
||||||
|
|
||||||
YearMonth now = YearMonth.now();
|
YearMonth now = YearMonth.now();
|
||||||
|
@ -691,7 +782,7 @@ public class Htmlizer
|
||||||
|
|
||||||
BarChart chart;
|
BarChart chart;
|
||||||
|
|
||||||
chart = new BarChart("Nombre de services");
|
chart = new BarChart("Nombre de services déclarés");
|
||||||
chart.addDataset("Services");
|
chart.addDataset("Services");
|
||||||
|
|
||||||
int now = LocalDate.now().getYear();
|
int now = LocalDate.now().getYear();
|
||||||
|
@ -808,6 +899,92 @@ public class Htmlizer
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Htmlize software distribution chart.
|
||||||
|
*
|
||||||
|
* @param services
|
||||||
|
* the services
|
||||||
|
* @return the string
|
||||||
|
* @throws StatoolInfosException
|
||||||
|
* the statool infos exception
|
||||||
|
*/
|
||||||
|
public static String htmlizeSoftwareDistributionChart() throws StatoolInfosException
|
||||||
|
{
|
||||||
|
String result;
|
||||||
|
|
||||||
|
BarChart chart = new BarChart("Distribution des logiciels proposés par au moins deux services");
|
||||||
|
chart.addDataset("Logiciel");
|
||||||
|
|
||||||
|
Federation federation = HtmlizerContext.instance().getFederation();
|
||||||
|
Categories categories = HtmlizerContext.instance().getCategories();
|
||||||
|
|
||||||
|
SoftwareStats stats = StatAgent.statAllSoftwares(federation, categories);
|
||||||
|
stats.sortByServiceCount().reverse();
|
||||||
|
|
||||||
|
for (SoftwareStat stat : stats)
|
||||||
|
{
|
||||||
|
if (stat.getServiceCount() > 1)
|
||||||
|
{
|
||||||
|
chart.add(stat.getName(), stat.getServiceCount(), ChartColor.PURPLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = BarChartView.build(chart);
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Htmlize software used chart.
|
||||||
|
*
|
||||||
|
* @param services
|
||||||
|
* the services
|
||||||
|
* @return the string
|
||||||
|
* @throws StatoolInfosException
|
||||||
|
* the statool infos exception
|
||||||
|
*/
|
||||||
|
public static String htmlizeSoftwareDistributionPieChart(final Services services) throws StatoolInfosException
|
||||||
|
{
|
||||||
|
String result;
|
||||||
|
|
||||||
|
Federation federation = HtmlizerContext.instance().getFederation();
|
||||||
|
Categories categories = HtmlizerContext.instance().getCategories();
|
||||||
|
|
||||||
|
SoftwareStats stats = StatAgent.statAllSoftwares(federation, categories);
|
||||||
|
stats.sortByServiceCount().reverse();
|
||||||
|
|
||||||
|
ChartColors colors = ChartColor.valueList();
|
||||||
|
colors.remove(ChartColor.BLUE);
|
||||||
|
|
||||||
|
PieChart pie = new PieChart("Distribution des logiciels");
|
||||||
|
int index = 0;
|
||||||
|
while ((index < stats.size() && (index < 10)))
|
||||||
|
{
|
||||||
|
ChartColor color = colors.get(index);
|
||||||
|
SoftwareStat stat = stats.get(index);
|
||||||
|
pie.add(stat.getName(), stat.getServiceCount(), color);
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int others = 0;
|
||||||
|
while (index < stats.size())
|
||||||
|
{
|
||||||
|
SoftwareStat stat = stats.get(index);
|
||||||
|
others += stat.getServiceCount();
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
pie.add("Autres", others, ChartColor.BLUE);
|
||||||
|
pie.setLegendPosition(Position.RIGHT);
|
||||||
|
|
||||||
|
result = DoughnutChartView.build(pie);
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To bar chart.
|
* To bar chart.
|
||||||
*
|
*
|
||||||
|
|
|
@ -21,6 +21,7 @@ package fr.devinsy.statoolinfos.htmlize.charts;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import fr.devinsy.statoolinfos.core.StatoolInfosUtils;
|
||||||
import fr.devinsy.strings.StringList;
|
import fr.devinsy.strings.StringList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,8 +79,10 @@ public class BarChart
|
||||||
*/
|
*/
|
||||||
public void add(final String label, final double value, final ChartColor color)
|
public void add(final String label, final double value, final ChartColor color)
|
||||||
{
|
{
|
||||||
this.labels.add(label);
|
String escapedLabel = StatoolInfosUtils.escapeJSONXML(label);
|
||||||
this.datasets.get(0).add(new BarChartData(label, value, color));
|
|
||||||
|
this.labels.add(escapedLabel);
|
||||||
|
this.datasets.get(0).add(new BarChartData(escapedLabel, value, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -81,4 +81,24 @@ public enum ChartColor
|
||||||
//
|
//
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To list.
|
||||||
|
*
|
||||||
|
* @return the chart colors
|
||||||
|
*/
|
||||||
|
public static ChartColors valueList()
|
||||||
|
{
|
||||||
|
ChartColors result;
|
||||||
|
|
||||||
|
result = new ChartColors();
|
||||||
|
ChartColor[] values = values();
|
||||||
|
for (int index = 0; index < values.length; index++)
|
||||||
|
{
|
||||||
|
result.add(values[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,21 @@ public class ChartColors extends ArrayList<ChartColor>
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From.
|
||||||
|
*
|
||||||
|
* @param colors
|
||||||
|
* the colors
|
||||||
|
* @return the chart colors
|
||||||
|
*/
|
||||||
|
public void addAll(final ChartColor[] colors)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < colors.length; index++)
|
||||||
|
{
|
||||||
|
add(colors[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the ChartColor of the index with safe overflow.
|
* Gets the ChartColor of the index with safe overflow.
|
||||||
*
|
*
|
||||||
|
|
|
@ -21,6 +21,7 @@ package fr.devinsy.statoolinfos.htmlize.charts;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import fr.devinsy.statoolinfos.core.StatoolInfosUtils;
|
||||||
import fr.devinsy.strings.StringList;
|
import fr.devinsy.strings.StringList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,7 +79,9 @@ public class PieChart
|
||||||
*/
|
*/
|
||||||
public void add(final String label, final double value, final ChartColor color)
|
public void add(final String label, final double value, final ChartColor color)
|
||||||
{
|
{
|
||||||
this.datas.add(new PieChartData(label, value, color));
|
String targetLabel = StatoolInfosUtils.escapeJSONXML(label);
|
||||||
|
|
||||||
|
this.datas.add(new PieChartData(targetLabel, value, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,11 +15,6 @@
|
||||||
|
|
||||||
<h2 id="title" class="center">Statistiques</h2>
|
<h2 id="title" class="center">Statistiques</h2>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
|
||||||
<div id="serviceCountMonthChart" class="chartborder" style="width: 500px; height: 200px; display: inline-block;"/>
|
|
||||||
<div id="serviceDateStatusChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
|
||||||
<div id="serviceCountYearChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<div id="turnoutChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
<div id="turnoutChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
||||||
<div id="organizationCountryChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
<div id="organizationCountryChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
||||||
|
@ -45,6 +40,21 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<div id="serviceCountMonthChart" class="chartborder" style="width: 500px; height: 200px; display: inline-block;"/>
|
||||||
|
<div id="serviceDateStatusChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
||||||
|
<div id="serviceCountYearChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div id="categoryDistributionPieChart" class="chartborder" style="width: 500px; height: 300px; display: inline-block;"/>
|
||||||
|
<div id="softwareDistributionPieChart" class="chartborder" style="width: 500px; height: 300px; display: inline-block;"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div id="softwareDistributionChart" class="chartborder" style="width: 1000px; height: 300px; display: inline-block;"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div id="categoryDistributionChart" class="chartborder" style="width: 1000px; height: 400px; display: inline-block;"/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -15,11 +15,6 @@
|
||||||
|
|
||||||
<h2 id="title" class="center">Statistiques</h2>
|
<h2 id="title" class="center">Statistiques</h2>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
|
||||||
<div id="serviceCountMonthChart" class="chartborder" style="width: 500px; height: 200px; display: inline-block;"/>
|
|
||||||
<div id="serviceDateStatusChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
|
||||||
<div id="serviceCountYearChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<div id="turnoutChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
<div id="turnoutChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -42,6 +37,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<div id="serviceCountMonthChart" class="chartborder" style="width: 500px; height: 200px; display: inline-block;"/>
|
||||||
|
<div id="serviceDateStatusChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
||||||
|
<div id="serviceCountYearChart" class="chartborder" style="width: 250px; height: 200px; display: inline-block;"/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
Loading…
Reference in a new issue