Hi,
I've got the chart how i would like it apart form having multiple category axis, please see attached image.
As you can see i have one CategoryAxis working the persons name, ideally i'd like each Column name to appear above that.(series.stack)
Here's my current code:
@(Html.Kendo().Chart()
.Name(
"chart"
)
.Title(
"Project Management"
)
.Legend(legend => legend
.Position(ChartLegendPosition.Top)
)
.SeriesDefaults(seriesDefaults =>
seriesDefaults.Column().Stack(
true
)
)
.Series(series =>
{
foreach
(var def
in
Model.Series)
{
series.Column(def.Data).Name(def.Name).Stack(def.Stack);
}
})
.SeriesColors(Colours.Blue, Colours.Orange, Colours.Grey, Colours.Yellow, Colours.LightBlue, Colours.Green)
// This should be the Stack Name (Overhead)
.CategoryAxis(axis => axis.Labels(l => l.Rotation(90).Template(
"#= series.stack #"
)))
// This should be the Persons Name (FullName)
.CategoryAxis(axis => axis.Categories(Model.Categories))
.Tooltip(tooltip => tooltip
.Visible(
true
)
.Template(
"#= series.name #: #= kendo.format('{0:N2}', value) #"
)
)
)
What's the easiest way to achieve this? This is based off of your example project: https://github.com/telerik/ui-for-aspnet-mvc-examples/tree/master/chart/dynamic-series
Thanks,
Lee.
12 Answers, 1 is accepted
Showing each series stack name in a CategoryAxis would not be possible because the number of stacks are determined on the fly in this case and the category axis needs to have a list of categories set. What I can suggest is to use the label of the bottom series in each stack to display the stack value and offset it to the bottom of the Chart using a margin setting:
@model DynamicSeries.Models.MyViewModel
@(Html.Kendo().Chart()
.Name(
"Chart"
)
.Series(series => {
foreach (
var
def
in
Model.Series) {
series.Column(def.Data).Name(def.Name).Stack(def.Stack)
.Labels(lbl=>lbl
.VisibleHandler(
"showLabel"
)
.Position(ChartBarLabelsPosition.InsideBase)
.Margin(0, 0, -20, 0)
.Template(
"#:series.stack#"
)
.Background(
"transparent"
)
);
}
})
.CategoryAxis(axis => axis
.Labels(lbl=>lbl.Visible(
false
)) // empty category axis to look like the labels are rendered in it
)
.CategoryAxis(axis => axis
.Categories(Model.Categories)
)
)
<script>
var
lastStack;
function
showLabel(e) {
// show label only for first series in each stack
var
isInNewStack = e.series.stack != lastStack;
lastStack = e.series.stack;
return
isInNewStack;
}
</script>
You can see what the result looks like in the attached image. Is this the look that you are trying to achieve?
Regards,
Tsvetina
Progress Telerik
Hi Tsvetina,
From your image that looks exactly like what i need. Again you provide a great answer!
Thank you very much!
It looks like the VisibleHandler function does not produce the expected result on your side. Can you share your code, including the JavaScript to determine the labels visibility? You can put a breakpoint in the function and debug it to see why it always returns true. One guess would be if you have not declared the global variable used to keep the stack name of the previous series:
<script>
var
lastStack;
// => global variable needed to store the name of the previous series stack, so we can show the label if the current series belongs to a new stack
function
showLabel(e) {
// show label only for first series in each stack
var
isInNewStack = e.series.stack != lastStack;
lastStack = e.series.stack;
return
isInNewStack;
}
</script>
Regards,
Tsvetina
Progress Telerik
Hi Tsvetina,
I have copied it like you had it:
<
script
>
var lastStack;
function showLabel(e)
{
// show label only for first series in each stack
var isInNewStack = e.series.stack != lastStack;
console.log(e.series.stack + ' != ' + lastStack + ' = ' + isInNewStack);
lastStack = e.series.stack;
return isInNewStack;
}
</
script
>
I added some logging as you can see and the result is this:
Chargeable != undefined = true
Overhead != Chargeable = true
Sick Leave != Overhead = true
Annual Leave != Sick Leave = true
RDO != Annual Leave = true
Chargeable != RDO = true
Overhead != Chargeable = true
Sick Leave != Overhead = true
[...]
Lee
I have managed to get it to work using this:See attached Photo
<script>
var
lastStack;
function
showLabel(e)
{
// show label only for first series in each stack
var
isInNewStack = e.series.stack !== lastStack
&& (e.index >= 0 && e.index < e.series.data.length)
&& (e.series.index >= 0 && e.series.index < e.series.data.length);
lastStack = e.series.stack;
return
isInNewStack;
}
</script>
My only remaining question is how can i make the category axis higher so i can fit them in vertically and align them? (refer to image again)
I also noticed if i click on of the key items off the label disappears so maybe my code isn't that great.
You can see the labels have shifted to the left when i unselect "Chargeable - 2017-Jul"
My logic also does not cover scenarios where series are hidden dynamically. For this scenario, the following code looks to be working well in my test page:
<script>
function
showLabel(e) {
var
chart = $(
"#Chart"
).data(
"kendoChart"
),
index = e.series.index,
stack = e.series.stack;
if
(index == 0 ||
(index != 0 && chart.options.series[index - 1].visible ==
false
) ||
(index != 0 && stack != chart.options.series[index - 1].stack)) {
return
true
;
}
return
false
;
}
</script>
Could you try it and let me know if you find cases where it fails?
Regards,
Tsvetina
Progress Telerik
Hi Tsvetina,
Thanks again for helping, but that also doesn't work (well it does by displaying the label when i hide a series but, it still displays a label for all series not just the bottom).
I've created a dojo for you maybe to make it easier? https://dojo.telerik.com/afOHUHub
Thanks,
Lee.
Thank you for the example. I see now what the difference is. In your scenario, the series from one and the same stack are not created one after the other, so the logic to check if the previous series belongs to another stack in order to display the label always returns true. With such order of the series, I do not think the suggested solution could be adjusted to work.
However, if it is possible to order the data by Stack before returning it to the view, the problem should be resolved. Could you try ordering the Model.Series collection by the Stack field in the controller?
Regards,
Tsvetina
Progress Telerik
Hi Tsvetina,
Great, that fixed it! Now i guess i just need to know how i can make the empty categoryAxis higher so i can fit the labels in at 90 degrees.
(See attached image)
Again thank you for you fantastic support!!
The problem with this is that the actual axis line does not have padding and margin properties available. What I can suggest as an alternative is to hide the second category axis line and move its labels down using padding:
.CategoryAxis(axis => axis
.Labels(lbl => lbl.Visible(
false
))
)
.CategoryAxis(axis => axis
.Categories(Model.Categories)
.Line(line=>line.Visible(
false
))
.Labels(lbl=>lbl.Padding(20, 0, 0, 0))
)
Regards,
Tsvetina
Progress Telerik