PDA

View Full Version : [CLOSED] Chart in code behind



slavina
Mar 03, 2015, 3:17 PM
My mistake, I create subject in the wrong section : Link (http://forums.ext.net/showthread.php?55691-Chart-in-code-behind&p=257731) You can delete the other topic, this one is the good one.

For my project, I need to build my chart in code behind because we can draw different curves in the same chart.

This is my test code :


<%@ Page Title="Page" Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="WebApplication3._Default" %>

<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>


<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!X.IsAjaxRequest)
{
ICollection<object> datas=new List<object>();
datas.Add(new{Data1 = 1,Data2 = 10,Data3 = 10});
datas.Add(new{Data1 = 2,Data2 = 20,Data3 = 30});
datas.Add(new{Data1 = 3, Data2 = 30,Data3 = 30});
datas.Add(new{Data1 = 4,Data2 = 20,Data3 = 20});
datas.Add(new{Data1 = 5,Data2 = 20,Data3 = 10});

Chart1.LegendConfig = new ChartLegend() { Position = LegendPosition.Bottom, BoxStroke = "#FFFFFF", BoxFill = "#FFFFFF" };

CategoryAxis axisX = new CategoryAxis();
axisX.Fields = new string[1] { "Data1" };
axisX.Position = Position.Bottom;
this.Chart1.Axes.Add(axisX);

NumericAxis axisY = new NumericAxis();
axisY.Fields = new string[2] { "Data2", "Data3" };
axisY.Position = Position.Left;
this.Chart1.Axes.Add(axisY);

ModelField m = new ModelField();
m.Name = "Data1";
m.Type = ModelFieldType.Auto;
Model1.Fields.Add(m);

m = new ModelField();
m.Name = "Data2";
m.Type = ModelFieldType.Float;
m.UseNull = true;
Model1.Fields.Add(m);

m = new ModelField();
m.Name = "Data3";
m.Type = ModelFieldType.Float;
m.UseNull = true;
Model1.Fields.Add(m);

LineSeries s1 = new LineSeries();
s1.Axis = Position.Left;
s1.Smooth = 3;
s1.HighlightConfig = new SpriteAttributes() { Size = 6, Radius = 6, Fill = "#BB12BB" };
s1.MarkerConfig = new SpriteAttributes() { Size = 3, Radius = 3, Fill="#BB12BB", StrokeWidth = 0, Type = SpriteType.Circle };
s1.Style = new SpriteAttributes() { StrokeWidth = 2, Fill = "#BB12BB" };
s1.Title = "Serie 1";
s1.XField = new string[1] { "Data1" };
s1.YField = new string[1] { "Data2" };

ColumnSeries s2 = new ColumnSeries();
s2.Axis = Position.Left;
s2.Style = new SpriteAttributes() { Fill = "#DBD8D4", FillOpacity = 0.4, Stroke = "#DBD8D4" };
s2.Title = "Serie 2";
s2.XField = new string[1] { "Data1" };
s2.YField = new string[1] { "Data3" };

this.Chart1.Series.Add(s1);
this.Chart1.Series.Add(s2);

this.StoreData.DataSource = datas;
this.StoreData.DataBind();
}
}
</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
<style type="text/css">
</style>
<script type="text/javascript">
</script>
</head>
<body>
<form id="form1" runat="server">
<ext:ResourceManager ID="ResourceManager1" runat="server" />

<ext:Store ID="StoreData" runat="server">
<Model>
<ext:Model ID="Model1" runat="server">
<Fields>
</Fields>
</ext:Model>
</Model>
</ext:Store>
<ext:Viewport ID="Viewport1" runat="server" Layout="FitLayout">
<Items>
<ext:Chart ID="Chart1" runat="server" StyleSpec="background:#fff;" Animate="true" Flex="1" StoreID="StoreData">
</ext:Chart>

</Items>
</ext:Viewport>
</form>
</body>
</html>


And these are my questions :


Why the "Fill" on the ColumnSeries dos not work? It works in the legend (grey) but not in the chart (blue)?
How can I change the colors of the highlight markers on the line curve? My curve is purple but when I highlight a marker, there is blue for the highlight.
When I load the chart, I can see other colors and en empty chart. How can we change that? I also saw that with a bigger chart (more values), on the load, the values of the axisY are between 0 and 1 and it takes 0.5s to show the real axis values.
This is what I see on the load of the test case :

http://forums.ext.net/attachment.php?attachmentid=22031&stc=1

And this is what I see in my complete project on load :

http://forums.ext.net/attachment.php?attachmentid=22032&stc=1
I saw many old subjects on the legend cut in two lines/columns. Is there an update on this?


Thank you

fabricio.murta
Mar 03, 2015, 4:11 PM
Hello @slavina!

Instead of the s2.Style, set a renderer to color your chart.

Your attempt both matches the Ext.NET code and the resulting code matches ExtJS documentation but still, it does not work. In our examples explorer there are examples with custom chart colors, you could base your charts on them.

Your s2.Style, for example would become:

s2.Renderer.Handler = "attributes.fill = '#DBD8D4'; attributes.stroke = '#DBD8D4'; attributes.fillOpacity = 0.4; return attributes";

You can look thru this example for more effects you can add to your chart: Column Charts - Browser Stats (http://examples2.ext.net/#/Chart/Column/Browser_Stats/)

I hope this helps!

slavina
Mar 04, 2015, 2:06 PM
Hello

In your example (http://examples2.ext.net/#/Chart/Column/Browser_Stats/), I saw that the column is above the axis while in this example (http://examples2.ext.net/#/Chart/Column/Basic/), columns are under. Is it due to the renderer?

If I only apply :

s2.Renderer.Handler = "attributes.fill = '#DBD8D4'; attributes.stroke = '#DBD8D4'; attributes.fillOpacity = 0.3; attributes.strokeWidth =0; return attributes";
I have this :
22081

You can see that the columns are above and the legend color is not the same that the column color.
Does I have to apply
s2.Style also?

Do you have answers for questions 2-3-4?

Thanks

fabricio.murta
Mar 04, 2015, 5:52 PM
Hello, @slavina!

Sorry, somewhat I thought the directions from the reply applied to all your questions.

So, let me reply (or try to) them one by one.

1. Yes, it seems setting also the .Style does the trick.
Or you can just set a custom "theme" for the chart with the colors. There's a bug getting the color for the column series in the legend, and it is addressed with the example I'll show you in the end of this post. It will be your sample reviewed to use themes.

2. You needed to set the color adding the Stroke attribute in your line 52. Stroke="#BB12BB". Although you had set strokeWidth=0, this is what worked.
But with the sample I'm going to provide you, it seems this problem does not happen.

3. Remove the Animate="True" from your chart definition. It'll show the ready chart with no fancy effects.

4. I honestly don't know what the issue is to respond you. You wanted to wrap the legend on different lines in the legend box?
If that's the case, I believe this is not yet fixed. But I could easily find an alternative for it that might work for you.

Add this script to the page where you want charts to wrap legends thru:


Ext.chart.Legend.override({
createItems: function () {
var me = this,
chart = me.chart,
surface = chart.surface,
items = me.items,
padding = me.padding,
itemSpacing = me.itemSpacing,
spacingOffset = 2,
itemWidth = 0,
itemHeight = 0,
totalWidth = 0,
totalHeight = 0,
vertical = me.isVertical,
math = Math,
mfloor = math.floor,
mmax = math.max,
index = 0,
i = 0,
len = items ? items.length : 0,
x, y, item, bbox, height, width,
// chart dimensions
chartBBox = chart.chartBBox,
chartInsets = chart.insetPadding,
chartWidth = chartBBox.width - (chartInsets * 2),
chartHeight = chartBBox.height - (chartInsets * 2),
xOffset = 0, yOffset = 0,
legendWidth = 0, legendHeight = 0,
legendXOffset = 50, legendYOffset = 50,
hSpacing, vSpacing;

//remove all legend items
if (len) {
for (; i < len; i++) {
items[i].destroy();
}
}
//empty array
items.length = [];

// Create all the item labels, collecting their dimensions and positioning each one
// properly in relation to the previous item
chart.series.each(function (series, i) {
if (series.showInLegend) {
Ext.each([].concat(series.yField), function (field, j) {
item = new Ext.chart.LegendItem({
legend: this,
series: series,
surface: chart.surface,
yFieldIndex: j
});
bbox = item.getBBox();

width = bbox.width;
height = bbox.height;

itemWidth = mmax(itemWidth, width);
itemHeight = mmax(itemHeight, height);

items.push(item);
}, this);

}
}, me);

//spacing = itemSpacing / (vertical ? 2 : 1);
vSpacing = itemSpacing / 2;
hSpacing = itemSpacing;
if (vertical) {
if (chartHeight - legendYOffset < items.length * (itemHeight + vSpacing) + 2 * padding + vSpacing) {
legendHeight = chartHeight - legendYOffset;
yOffset = mfloor((legendHeight - mfloor((legendHeight - 2 * padding - vSpacing) / (itemHeight + vSpacing)) * (itemHeight + vSpacing)) / 2);
}
else {
legendHeight = items.length * (itemHeight + vSpacing) + 2 * padding + vSpacing;
yOffset = vSpacing + padding;
}
xOffset = hSpacing + padding;
totalWidth = xOffset;
totalHeight = yOffset;
}
else {
if (chartWidth - legendXOffset < items.length * (itemWidth + hSpacing) + 2 * padding + hSpacing) {
legendWidth = chartWidth - legendXOffset;
xOffset = mfloor((legendWidth - mfloor((legendWidth - 2 * padding - hSpacing) / (itemWidth + hSpacing)) * (itemWidth + hSpacing)) / 2);
}
else {
legendWidth = items.length * (itemWidth + hSpacing) + 2 * padding + hSpacing;
xOffset = padding + hSpacing;
}
yOffset = padding + vSpacing;
totalHeight = yOffset;
totalWidth = xOffset;
}

Ext.each(items, function (item, j) {
if (vertical && (totalHeight + vSpacing + itemHeight > chartHeight - legendYOffset)) {
totalHeight = yOffset;
totalWidth += itemWidth + hSpacing;
}
else if (!vertical && (totalWidth + hSpacing + itemWidth > chartWidth - legendXOffset)) {
totalWidth = xOffset;
totalHeight += itemHeight + vSpacing;
}
item.x = totalWidth;
item.y = mfloor(totalHeight + itemHeight / 2);

// Collect cumulative dimensions
if (vertical)
totalHeight += itemHeight + vSpacing;
else
totalWidth += itemWidth + hSpacing;

}, me);

// Store the collected dimensions for later
me.width = mfloor(vertical ? totalWidth + itemWidth + xOffset : legendWidth);
me.height = mfloor(vertical ? legendHeight : totalHeight + itemHeight + yOffset);
me.itemHeight = itemHeight;
me.itemWidth = itemWidth;
}
});

Credits for above code: komodon (http://www.sencha.com/forum/showthread.php?174127-chart-legend-items-truncated&p=752120&viewfull=1#post752120)

Now, the reviewed code supporting your requests 1, 2 and 3 would be:


<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!X.IsAjaxRequest)
{
ICollection<object> datas=new List<object>();
datas.Add(new{Data1 = 1,Data2 = 10,Data3 = 10});
datas.Add(new{Data1 = 2,Data2 = 20,Data3 = 30});
datas.Add(new{Data1 = 3, Data2 = 30,Data3 = 30});
datas.Add(new{Data1 = 4,Data2 = 20,Data3 = 20});
datas.Add(new{Data1 = 5,Data2 = 20,Data3 = 10});

Chart1.LegendConfig = new ChartLegend() { Position = LegendPosition.Bottom, BoxStroke = "#FFFFFF", BoxFill = "#FFFFFF" };
Chart1.Theme = ct1.ThemeName;

CategoryAxis axisX = new CategoryAxis();
axisX.Fields = new string[1] { "Data1" };
axisX.Position = Position.Bottom;
this.Chart1.Axes.Add(axisX);

NumericAxis axisY = new NumericAxis();
axisY.Fields = new string[2] { "Data2", "Data3" };
axisY.Position = Position.Left;
this.Chart1.Axes.Add(axisY);

ModelField m = new ModelField();
m.Name = "Data1";
m.Type = ModelFieldType.Auto;
Model1.Fields.Add(m);

m = new ModelField();
m.Name = "Data2";
m.Type = ModelFieldType.Float;
m.UseNull = true;
Model1.Fields.Add(m);

m = new ModelField();
m.Name = "Data3";
m.Type = ModelFieldType.Float;
m.UseNull = true;
Model1.Fields.Add(m);

LineSeries s1 = new LineSeries();
s1.Axis = Position.Left;
s1.Smooth = 3;
s1.HighlightConfig = new SpriteAttributes() { Size = 6, Radius = 6 };
s1.MarkerConfig = new SpriteAttributes() { Size = 3, Radius = 3, StrokeWidth = 0, Type = SpriteType.Circle };
s1.Style = new SpriteAttributes() { StrokeWidth = 2 };
s1.Title = "Serie 1";
s1.XField = new string[1] { "Data1" };
s1.YField = new string[1] { "Data2" };

ColumnSeries s2 = new ColumnSeries();
s2.Axis = Position.Left;
s2.Title = "Serie 2";
s2.XField = new string[1] { "Data1" };
s2.YField = new string[1] { "Data3" };

this.Chart1.Series.Add(s1);
this.Chart1.Series.Add(s2);

this.StoreData.DataSource = datas;
this.StoreData.DataBind();
}
}
</script>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
<style type="text/css">
</style>
<script type="text/javascript">
Ext.chart.series.Column.override({
getLegendColor: function (index) {
index = this.seriesIdx;
return this.callParent(arguments);
}
});
</script>
</head>
<body>
<form id="form1" runat="server">
<ext:ResourceManager ID="ResourceManager1" runat="server" ScriptMode="Debug" SourceFormatting="true" />

<ext:ChartTheme runat="server" ID="ct1" ThemeName="EnterpriseColors" Colors="#BB12BB,#DBD8D4" />
<ext:Store ID="StoreData" runat="server">
<Model>
<ext:Model ID="Model1" runat="server">
<Fields>
</Fields>
</ext:Model>
</Model>
</ext:Store>
<ext:Viewport ID="Viewport1" runat="server" Layout="FitLayout">
<Items>
<ext:Chart ID="Chart1" runat="server" Flex="1" StoreID="StoreData">
</ext:Chart>
</Items>
</ext:Viewport>
</form>
</body>
</html>


If you want to test the legend wrapping functionality, just paste the code in the script block that starts on line 74. And also add lots of (empty) series to the chart. Just a repeated this.Chart1.Series.Add(new ColumnSeries()); various times will do.

I hope the suggestions help you build your page!

slavina
Mar 05, 2015, 8:16 AM
Thanks a lot fabricio!

For the legend on 2 lines, it works great on my first try :)

For the theme, can we chose each color for each series?
For example : first color for serie1, second color for serie2 and second color again for serie3? Perhaps with a renderer this time.

I tried to disable "animate" for the load and enable it after the first load but i can't find a good event to do this...

And a last question, why do I have this problem with your example :

22161

Points are not align with axis for the line curve.

EDIT : Can we build a chartTheme in code behind?

fabricio.murta
Mar 05, 2015, 4:24 PM
Hello, slavina!

Try adding other series using the theme from my example. Just by looking on the legend you'll notice that it'll cycle thru the colors defined.

You may try some events in the listeners list for the chart like "Load" or "AfterLayout", use intelliSense to see what are available, I am sure you'll find a fitting event.

It is misaligned because the series are aligned with the bar and the numbers are bound to the axis' start and end. See how the middle number (6) is centered? Its just a matter of formatting.

The example I provided focused on the questions you had, sorry that passed unnoticed. If you are unable to fix this display on your own, let us know.

And yes, you can define a chartTheme in code behind. Just define and add it as you've done with the chart.
You can also keep the main definition of the chartTheme and just change the color scheme from code behind. Did you notice how I got the name of the theme, directly from the control, in the example I provided, yes, thats all in these lines. :)

I hope this helps!