Innat3 Innat3 - 9 months ago 159
ASP.NET (C#) Question

Setting a dynamic size for an Asp:Chart control

I am trying to make my chart width and height dynamic but I can't get it to work. So far what I've tried:

I've set the Chart inside an Asp:Panel and given the panel the desired percentual values.

<asp:Panel ID="Panel1" runat="server" Width="90%" Height="40%">
<asp:Chart ID="Chart1" runat="server" CssClass="chart">
<Series>
<asp:Series Name="Series1"></asp:Series>
</Series>
<ChartAreas>
<asp:ChartArea Name="ChartArea1"></asp:ChartArea>
</ChartAreas>
</asp:Chart>
</asp:Panel>


Then I try to assign those values to the chart in my C# code

Chart1.Width = Panel1.Width;
Chart1.Height = Panel1.Height;


This however generates an exception, as the chart is receiving the percentual value instead of the amount of pixels. I also tried (int)Panel.Width.Value to no avail.

I tried doing it with CSS as well, fiddling around with position:absolute and other attributes, but again, I can get it to work for a panel but not for a chart.

Could anyone enlighten me with a simple solution which won't require getting into JQuery and such?

EDIT:

The variable value of Panel1.Width will output 90% while Panel1.Width.Value will for some reason output 90 (40% and 40 for Panel1.Height).

Chart1.Width.Value will have a default value of 300px assigned by Visual Studio, therefore:

Chart1.Width = new Unit(Chart1.Width.Value * Panel1.Width.Value / 100, UnitType.Pixel);


will output the same as if I were to do:

Chart1.Width = new Unit(300 * 90 / 100, UnitType.Pixel);


OUTPUT: a static value of 270px

I NEED to get the pixel value retrieved by the Panel1.Width percentage, but I can't figure out a way of doing that

EDIT 2:

The chart stretching bit with css works correctly but the output is a bit underwhelming, so I am trying to to make the javascript example work but I am having no success... I added a button to force a postback and in the page_load event I inserted:

protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
if (panelWidth.Value != "" && panelHeight.Value != "")
{
Chart1.Visible = true;
Chart1.Width = int.Parse(panelWidth.Value);
Chart1.Height = int.Parse(panelHeight.Value);
}
}
else //Initialize the chart with some sample points
{
Chart1.Series[0].Points.AddXY(1, 1);
Chart1.Series[0].Points.AddXY(1, 2);
Chart1.Series[0].Points.AddXY(2, 1);
Chart1.Series[0].Points.AddXY(2, 2);
Chart1.Series[0].Points.AddXY(3, 1);
Chart1.Series[0].Points.AddXY(3, 2);
}
}


If I start the page the chart is obviously not visible, so I also added a button

<asp:Button ID="Button1" runat="server" Text="Button" />


to the form to trigger a postback, which does reload the page but the panelWidth.Value and panelHeight.Value are still empty. Am I missing something? Seems like I can't trigger the javascript code :/

Answer Source

You can use CSS styles to make sure that the chart fills the panel. The chart element, which is an image in the HTML output, will be stretched or compressed when the browser window is resized.

<style>
    html, body, form
    {
        height: 100%;
    }

    .chart
    {
        width: 100% !important;
        height: 100% !important;
    }
</style>

As for setting the Width and Height of the chart, there is a catch: the actual size of the panel is not available until the page has been loaded in the browser. After that, you can get the size with Javascript code and store the values in hidden fields, which are then available in code behind.

You could trigger a postback the first time the page has loaded, to adjust the chart to the size of the panel. To make the adjustment dynamic, other postbacks could be triggered every time the window size changes by a certain amount. With the help of an UpdatePanel, the visual impact of the postbacks can be reduced.

<asp:ScriptManager ID="scriptManager1" runat="server" />
<asp:HiddenField ID="panelWidth" runat="server" Value="" />
<asp:HiddenField ID="panelHeight" runat="server" Value="" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server" style="width: 90%; height: 40%">
    <ContentTemplate>
        <asp:Chart ID="Chart1" runat="server" CssClass="chart" Visible="false">
            <Series>
                <asp:Series Name="Series1"></asp:Series>
            </Series>
            <ChartAreas>
                 <asp:ChartArea Name="ChartArea1"></asp:ChartArea>
            </ChartAreas>
        </asp:Chart>
        <asp:Button ID="btnPostBack" runat="server" Style="display: none" />
    </ContentTemplate>
</asp:UpdatePanel>
<script type="text/javascript">
    (function () {
        var panel = document.getElementById('<%= UpdatePanel1.ClientID %>');
        var panelWidth = document.getElementById('<%= panelWidth.ClientID %>');
        var panelHeight = document.getElementById('<%= panelHeight.ClientID %>');
        var initialWidth = panel.offsetWidth;
        var initialHeight = panel.offsetHeight;

        function getChangeRatio(val1, val2) {
            return Math.abs(val2 - val1) / val1;
        };

        function redrawChart() {
            setTimeout(function () {
                initialWidth = panel.offsetWidth;
                initialHeight = panel.offsetHeight;
                document.getElementById('<%= btnPostBack.ClientID %>').click();
            }, 0);
        };

        function savePanelSize() {
            var isFirstDisplay = panelWidth.value == '';
            panelWidth.value = panel.offsetWidth;
            panelHeight.value = panel.offsetHeight;
            var widthChange = getChangeRatio(initialWidth, panel.offsetWidth);
            var heightChange = getChangeRatio(initialHeight, panel.offsetHeight);
            if (isFirstDisplay || widthChange > 0.2 || heightChange > 0.2) {
                redrawChart();
            }
        };

        savePanelSize();
        window.addEventListener('resize', savePanelSize, false);
    })();
</script>

The Javascript function savePanelSize is called after loading and after resizing the window. Empty values in the hidden fields indicate that the chart is displayed for the first time and that its size must be set in code behind. A redraw is also needed when the window size changes by more than 20%. The hidden button btnPostBack is used to trigger postbacks programmatically.

In code behind, the width and height of the chart are set to the size of the panel:

protected void Page_Load(object sender, EventArgs e)
{
    if (panelWidth.Value != "" && panelHeight.Value != "")
    {
        Chart1.Visible = true;
        Chart1.Width = int.Parse(panelWidth.Value);
        Chart1.Height = int.Parse(panelHeight.Value);
    }
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download