-
-
Notifications
You must be signed in to change notification settings - Fork 368
Description
Is there an existing issue for this?
- I have searched the existing issues
Is your feature request related to a problem? Please describe the problem.
Currently, we can only call chart1.Update(ChartAction.AddDataset); and chart1.Update(ChartAction.RemoveDataset); to add or remove datasets on a chart once it has been created. But, those do not allow you to specify which dataset to add, nor at which index to add it, so the added dataset always appears at the end of the chart's legend. Also, those do not allow you to specify which dataset to remove - it always removes the last item from its legend, even if we wanted to remove a dataset from the middle of the legend.
Describe the solution you'd like
Change chart1.Update(ChartAction.AddDataset); and chart1.Update(ChartAction.RemoveDataset); to something like this, which gives us full control over what is being changed:
chart1.AddDataset(myChartDatasetToAdd, indexToInsertIntoLegend);
chart1.RemoveDataset(datasetLegendLabelToRemoveFromChart);
These actions should update the chart's internal ChartDataSource directly, and should not call OnInitAsync again. "Init" sounds like it should only be called once so it seems wrong that RemoveDataset calls OnInitAsync every time.
Additional context
Here is an example Blazor page to demonstrate the problem with adding/removing datasets in a desired order. It also demonstrates an issue where datasets after number 8 are always colored gray.
@page "/reports/ChartTest"
<Chart ChartType="ChartType.Line" OnInitAsync="OnChartInit" @ref="Chart1" />
<div class="border rounded p-3">
<div class="fw-semibold mb-2">Commodities</div>
@foreach (string commodityName in CommodityPrices.Select(x => x.CommodityName).Distinct())
{
<div class="form-check">
<input class="form-check-input"
type="checkbox"
id="chk_@commodityName)"
checked
@onchange="(ChangeEventArgs e) => OnCommoditySelectionChangedAsync(commodityName, e)" />
<label class="form-check-label"
for="chk_@commodityName)"
title="@commodityName">
@commodityName
</label>
</div>
}
</div>
@code
{
private readonly List<CommodityPricesDto> CommodityPrices = new List<CommodityPricesDto>
{
new CommodityPricesDto { Year = 2021, CommodityName = "Corn", Price = 5.20m },
new CommodityPricesDto { Year = 2022, CommodityName = "Corn", Price = 6.60m },
new CommodityPricesDto { Year = 2023, CommodityName = "Corn", Price = 4.90m },
new CommodityPricesDto { Year = 2024, CommodityName = "Corn", Price = 4.40m },
new CommodityPricesDto { Year = 2021, CommodityName = "Soy", Price = 13.40m },
new CommodityPricesDto { Year = 2022, CommodityName = "Soy", Price = 14.20m },
new CommodityPricesDto { Year = 2023, CommodityName = "Soy", Price = 12.10m },
new CommodityPricesDto { Year = 2024, CommodityName = "Soy", Price = 11.30m },
new CommodityPricesDto { Year = 2021, CommodityName = "Wheat", Price = 7.20m },
new CommodityPricesDto { Year = 2022, CommodityName = "Wheat", Price = 8.50m },
new CommodityPricesDto { Year = 2023, CommodityName = "Wheat", Price = 6.40m },
new CommodityPricesDto { Year = 2024, CommodityName = "Wheat", Price = 6.00m },
new CommodityPricesDto { Year = 2021, CommodityName = "Cotton", Price = 0.92m },
new CommodityPricesDto { Year = 2022, CommodityName = "Cotton", Price = 1.19m },
new CommodityPricesDto { Year = 2023, CommodityName = "Cotton", Price = 0.84m },
new CommodityPricesDto { Year = 2024, CommodityName = "Cotton", Price = 0.79m },
new CommodityPricesDto { Year = 2021, CommodityName = "Rice", Price = 13.80m },
new CommodityPricesDto { Year = 2022, CommodityName = "Rice", Price = 16.10m },
new CommodityPricesDto { Year = 2023, CommodityName = "Rice", Price = 17.30m },
new CommodityPricesDto { Year = 2024, CommodityName = "Rice", Price = 15.90m },
new CommodityPricesDto { Year = 2021, CommodityName = "Sorghum", Price = 4.85m },
new CommodityPricesDto { Year = 2022, CommodityName = "Sorghum", Price = 6.05m },
new CommodityPricesDto { Year = 2023, CommodityName = "Sorghum", Price = 5.10m },
new CommodityPricesDto { Year = 2024, CommodityName = "Sorghum", Price = 4.60m },
new CommodityPricesDto { Year = 2021, CommodityName = "Barley", Price = 5.60m },
new CommodityPricesDto { Year = 2022, CommodityName = "Barley", Price = 7.10m },
new CommodityPricesDto { Year = 2023, CommodityName = "Barley", Price = 6.30m },
new CommodityPricesDto { Year = 2024, CommodityName = "Barley", Price = 5.95m },
new CommodityPricesDto { Year = 2021, CommodityName = "Oats", Price = 3.55m },
new CommodityPricesDto { Year = 2022, CommodityName = "Oats", Price = 4.10m },
new CommodityPricesDto { Year = 2023, CommodityName = "Oats", Price = 3.75m },
new CommodityPricesDto { Year = 2024, CommodityName = "Oats", Price = 3.40m },
new CommodityPricesDto { Year = 2021, CommodityName = "Peanuts", Price = 0.23m },
new CommodityPricesDto { Year = 2022, CommodityName = "Peanuts", Price = 0.25m },
new CommodityPricesDto { Year = 2023, CommodityName = "Peanuts", Price = 0.24m },
new CommodityPricesDto { Year = 2024, CommodityName = "Peanuts", Price = 0.26m },
new CommodityPricesDto { Year = 2021, CommodityName = "Sunflowers", Price = 0.22m },
new CommodityPricesDto { Year = 2022, CommodityName = "Sunflowers", Price = 0.25m },
new CommodityPricesDto { Year = 2023, CommodityName = "Sunflowers", Price = 0.24m },
new CommodityPricesDto { Year = 2024, CommodityName = "Sunflowers", Price = 0.23m },
new CommodityPricesDto { Year = 2021, CommodityName = "Canola", Price = 0.55m },
new CommodityPricesDto { Year = 2022, CommodityName = "Canola", Price = 0.63m },
new CommodityPricesDto { Year = 2023, CommodityName = "Canola", Price = 0.58m },
new CommodityPricesDto { Year = 2024, CommodityName = "Canola", Price = 0.56m },
new CommodityPricesDto { Year = 2021, CommodityName = "Sugarbeets", Price = 43.00m },
new CommodityPricesDto { Year = 2022, CommodityName = "Sugarbeets", Price = 47.50m },
new CommodityPricesDto { Year = 2023, CommodityName = "Sugarbeets", Price = 45.25m },
new CommodityPricesDto { Year = 2024, CommodityName = "Sugarbeets", Price = 44.10m }
};
private Chart Chart1;
private class CommodityPricesDto
{
public int Year;
public string CommodityName;
public decimal Price;
}
private Task<ChartDataSource> OnChartInit()
{
ChartDataSource dataSource = new ChartDataSource();
dataSource.Options.Title = "Commodity Prices";
dataSource.Options.X.Title = "Year";
dataSource.Options.Y.Title = "Price";
List<int> distinctYears = CommodityPrices
.Select(x => x.Year)
.Distinct()
.OrderBy(x => x)
.ToList();
List<string> distinctCommodities = CommodityPrices
.Select(x => x.CommodityName)
.Distinct()
.OrderBy(x => x)
.ToList();
dataSource.Labels = distinctYears
.Select(x => x.ToString())
.ToList();
foreach (string commodityName in distinctCommodities)
{
List<object> values = CommodityPrices
.Where(x => x.CommodityName == commodityName)
.Select(x => (object)x.Price)
.ToList();
ChartDataset dataset = new ChartDataset
{
Label = commodityName,
Data = values
};
dataSource.Data.Add(dataset);
}
return Task.FromResult(dataSource);
}
private Task OnCommoditySelectionChangedAsync(String commodityName, ChangeEventArgs e)
{
List<decimal> datasetToAddOrRemove = CommodityPrices
.Where(x => String.Equals(x.CommodityName, commodityName, StringComparison.OrdinalIgnoreCase))
.Select(x => x.Price)
.ToList();
Boolean isChecked = (bool)(e.Value);
// here, how can I control exactly which commodity gets added or removed from the chart?
// I can append the correct commodity to the end of the dataset in OnChartInit, which is unintuitive, but that forces it to be added at the end of the chart's legend, even though I might want it added to the middle.
// But, I can't find any way to remove a specific commodity from the middle of the chart's legend without removing every commodity, one at a time, and re-adding them again, one at a time, which causes every line to replay its animation.
// A workaround is to update the chart's dataset and then call ChartAction.Refresh, but that causes every line on the chart to replay its animation, which makes it hard to see which new line just got added.
if (isChecked)
{
Chart1.Update(ChartAction.AddDataset);
}
else
{
Chart1.Update(ChartAction.RemoveDataset);
}
return Task.CompletedTask;
}
}