This problem has several pieces to it.
StackingLine type, but two are of Scatter type.ValueType.Category, and one is ValueType.Double.ValueType.Category is a string, displayed as a time: 12:36. It starts out as a number (such as 12.6) that gets converted to a string for display purposes. The x values for these series will almost never be exactly on the hour, and the exact time (down to the minute) is important. However, we don't want to use ValueType.DateTime, as we do not want dates represented, as this is aggregate data. Thus, the range of values 00:00 through 23:59 will always be the range of x values.ValueType.Double is also representative of time. It shows just the hour of the relevant data, as it is summarized prior to display. The series using this axis will only have x values exactly on an hour, so the numbers 0-23 will always be the range of values.ValueType.Category seemed like a good idea.ValueType.Scatter datapoint that has an X value of 12:36, it should display a little bit further than the middle of the 12 and 13 X values in the other axis).ValueType.Scatter series.decimal? (AverageDemand, AverageBids, AverageBookings, BidRate, BookRate, AverageLors, AverageRevenue, RPD), and one properties of type int (Hour).AdHoc)ValueType.Double axis, but display them as the time string format in the tooltip, but was unable to, as the Format property doesn't seem to allow alterations to the data prior to display.int to string using methods I define, that would be the preferred way of handling all of this.<TabItem>
<ChildContent>
<TabHeader Text="Performance Grid"></TabHeader>
</ChildContent>
<ContentTemplate>
<div class="mt-lg-4">
<SfChart Width="100%" Height="100%">
<ChartEvents OnLegendClick="OnLegendClick"></ChartEvents>
<ChartPrimaryXAxis ValueType="Syncfusion.Blazor.Charts.ValueType.Double" Minimum="0" Maximum="23" Interval="1">
<ChartCrosshairSettings Enable="true" LineType="LineType.Vertical"></ChartCrosshairSettings>
</ChartPrimaryXAxis>
<ChartPrimaryYAxis ValueType="Syncfusion.Blazor.Charts.ValueType.Double" Interval="@GraphInterval">
</ChartPrimaryYAxis>
<ChartAxes>
@*<ChartAxis Name="XAxis" ValueType="Syncfusion.Blazor.Charts.ValueType.Double" Interval="@GraphInterval"></ChartAxis>*@
<ChartAxis Name="XAxis" ValueType="Syncfusion.Blazor.Charts.ValueType.Category" OpposedPosition="false"/>
</ChartAxes>
<ChartCrosshairSettings Enable="true" LineType="LineType.Vertical"></ChartCrosshairSettings>
<ChartTooltipSettings Enable="true" Shared="true"Format="${series.name} : ${point.x} : ${point.y}"></ChartTooltipSettings>
<ChartArea>
<ChartAreaBorder Width="0"></ChartAreaBorder>
</ChartArea>
<ChartSeriesCollection>
@*XName="Hour"*@
<ChartSeries XName="Hour" DataSource="@performanceGraphData" Visible="@GraphAverageDemandVisible"YName="AverageDemand" Type="ChartSeriesType.StackingLine" Name="Demand" Width="3">
<ChartMarker Visible="true"></ChartMarker>
</ChartSeries>
<ChartSeries XName="Hour" DataSource="@performanceGraphData" Visible="@GraphAverageBidsVisible"YName="AverageBids" Type="ChartSeriesType.StackingLine" Name="Bids" Width="3">
<ChartMarker Visible="true"></ChartMarker>
</ChartSeries>
<ChartSeries XName="Hour" DataSource="@performanceGraphData" Visible="@GraphAverageBookingsVisible" YName="AverageBookings" Type="ChartSeriesType.StackingLine" Name="Bookings" Width="3">
<ChartMarker Visible="true"></ChartMarker>
</ChartSeries>
<ChartSeries XName="Hour" DataSource="@performanceGraphData" Visible="@GraphBidRateVisible" YName="BidRate" Type="ChartSeriesType.StackingLine" Name="Bid Rate" Width="3">
<ChartMarker Visible="true"></ChartMarker>
</ChartSeries>
<ChartSeries XName="Hour" DataSource="@performanceGraphData" Visible="@GraphBookRateVisible" YName="BookRate" Type="ChartSeriesType.StackingLine" Name="Book Rate" Width="3">
<ChartMarker Visible="true"></ChartMarker>
</ChartSeries>
<ChartSeries XName="Hour" DataSource="@performanceGraphData" Visible="@GraphAverageRevenueVisible" YName="AverageRevenue" Type="ChartSeriesType.StackingLine" Name="Revenue" Width="3">
<ChartMarker Visible="true"></ChartMarker>
</ChartSeries>
<ChartSeries XName="Hour" DataSource="@performanceGraphData" Visible="@GraphRPDVisible" YName="RPD" Type="ChartSeriesType.StackingLine" Name="RPD" Width="3">
<ChartMarker Visible="true"></ChartMarker>
</ChartSeries>
@*XAxisName="XAxis"*@
<ChartSeries XName="Hour" DataSource="@scheduleStartTimes" Visible="@GraphScheduledVisible" YName="Height" Type="ChartSeriesType.Scatter" Name="Scheduled" XAxisName="XAxis">
<ChartMarker Visible="true" Shape="ChartShape.Circle" Height="15" Width="15"></ChartMarker>
</ChartSeries>
@*XAxisName="XAxis"*@
<ChartSeries XName="Hour" DataSource="@adHocStartTimes" Visible="@GraphAdHocVisible" YName="Height" Type="ChartSeriesType.Scatter" Name="AdHoc" XAxisName="XAxis">
<ChartMarker Visible="true" Shape="ChartShape.Diamond" Height="15" Width="15"></ChartMarker>
</ChartSeries>
</ChartSeriesCollection>
</SfChart>
</div>
</ContentTemplate>
</TabItem>
As you can see, this is all put inside of a tab element. I have also zipped the relevant code files for easier reading. The code I have added in the zip is not a solution, but it should serve as enough of a reference to facilitate understanding of how the code I have described works.
|
public void TooltipRender(SharedTooltipRenderEventArgs args)
{
List<String> tmpList = args.Text.ToList();
} |
|
<ChartAxes>
<ChartAxis Name="YAxis1" ValueType="Syncfusion.Blazor.Charts.ValueType.Double" OpposedPosition=true></ChartAxis>
<ChartAxis Name="YAxis2" ValueType="Syncfusion.Blazor.Charts.ValueType.Double"></ChartAxis>
</ChartAxes> |
Hello Durga,
This worked really well! I really appreciate the prompt response.
I ended up putting using only 1 X axis, and keeping all hour records as decimals.
This is the event handler I used:
public void TooltipRender(SharedTooltipRenderEventArgs args)
{
List
var adHoc = args.Data.Find(p => p.SeriesName == "AdHoc");
var innerText = decimal.Parse(args.HeaderText.Substring(3, args.HeaderText.Length - 7)).ToTimeString();
args.HeaderText = $"{innerText}";
if (adHoc != null)
{
var adHocIx = args.Text.FindIndex(s => s.Contains("AdHoc"));
var adHocText = $"AdHoc: {innerText}";
args.Text[adHocIx] = adHocText;
}
var sched = args.Data.Find(p => p.SeriesName == "Scheduled");
if (sched != null)
{
var schedIx = args.Text.FindIndex(s => s.Contains("Scheduled"));
var schedText = $"Scheduled: {innerText}";
args.Text[schedIx] = schedText;
}
}
This is a screenshot of how the sample looks afterwards (I also changed it from stacking line to just line):
EDIT: For anyone looking at this, I created a decimal-to-time-formatted-string converter:
public static class DecimalTimeToStringConverter
{
/// <summary>
/// Converts a decimal into the form hh:mm. Invalid values return an empty string.
/// </summary>
/// <param name="input">The decimal being converted</param>
/// <returns>A time string in the form hh:mm</returns>
public static string ToTimeString(this decimal input)
{
if (input >= 24)
return "";
return $"{((int)input < 10 ? $"0{(int)input}" : (int)input)}:{((int)(input % 1.0m * 60) < 10 ? $"0{(int)(input % 1.0m * 60)}" : (int)(input % 1.0m * 60))}";
}
/// <summary>
/// Converts a decimal into the form hh:mm. Invalid values return an empty string.
/// </summary>
/// <param name="input">The decimal being converted</param>
/// <returns>A time string in the form hh:mm</returns>
public static string ToTimeString(this decimal? input)
{
if (input is null)
return "";
if (input >= 24)
return "";
return $"{((int)input < 10 ? $"0{(int)input}" : (int)input)}:{((int)(input % 1.0m * 60) < 10 ? $"0{(int)(input % 1.0m * 60)}" : (int)(input % 1.0m * 60))}";
}
/// <summary>
/// Converts a time string in the form hh:mm to a decimal. Invalid values return null.
/// </summary>
/// <param name="input">The string being converted</param>
/// <returns>A decimal representative of the time that was converted</returns>
public static decimal? FromTimeString(this string input)
}
var regex = new Regex(@"^[0-9]{1,2}:[0-9]{2}$");
if (!regex.IsMatch(input))
return null;
return decimal.Parse(input.Substring(0, 2)) + (decimal.Parse(input.Substring(3, 2)) / 60m);
}
}