diff --git a/Plotly.Blazor.Examples/Components/Selected.razor b/Plotly.Blazor.Examples/Components/Selected.razor new file mode 100644 index 00000000..c75f77bb --- /dev/null +++ b/Plotly.Blazor.Examples/Components/Selected.razor @@ -0,0 +1,82 @@ +@using Plotly.Blazor.Interop +@using Plotly.Blazor.LayoutLib +@using Plotly.Blazor.Traces.ScatterLib + + + +@if (SelectedInfos != null && SelectedInfos.Any()) +{ + @foreach (var selected in SelectedInfos) + { + (Trace: @(selected.TraceIndex), X: @(selected.X), Y: @(selected.Y)) + } +} + +@code +{ + [CascadingParameter] + private MudTheme Theme { get; set; } + + private PlotlyChart chart; + private Config config; + private Layout layout; + private IList data; + private IEnumerable SelectedInfos { get; set; } + + /// + protected override void OnInitialized() + { + config = new Config + { + Responsive = true + }; + + layout = new Layout + { + Title = new Title + { + Text = GetType().Name + }, + PaperBgColor = Theme.PaletteDark.Surface.ToString(), + PlotBgColor = Theme.PaletteDark.Surface.ToString(), + Font = new Font + { + Color = Theme.PaletteDark.TextPrimary.ToString() + }, + HoverMode = HoverModeEnum.XUnified + }; + + data = new List + { + new Scatter + { + Name = "ScatterTrace", + Mode = ModeFlag.Markers, + X = Enumerable.Range(0, 30).Cast().ToList(), + Y = Helper.GenerateData(0, 30).Y + }, + new Scatter + { + Name = "ScatterTrace 2", + Mode = ModeFlag.Markers, + X = Enumerable.Range(0, 30).Cast().ToList(), + Y = Helper.GenerateData(0, 30).Y + } + }; + + base.OnInitialized(); + } + + public void SelectedAction(IEnumerable eventData) + { + SelectedInfos = eventData; + StateHasChanged(); + } + + public async void SubscribeEvents() + { + await chart.SubscribeSelectedEvent(); + } +} \ No newline at end of file diff --git a/Plotly.Blazor.Examples/Pages/SelectedPage.razor b/Plotly.Blazor.Examples/Pages/SelectedPage.razor new file mode 100644 index 00000000..9016941b --- /dev/null +++ b/Plotly.Blazor.Examples/Pages/SelectedPage.razor @@ -0,0 +1,5 @@ +@page "/selected" + + + + \ No newline at end of file diff --git a/Plotly.Blazor.Examples/Shared/CodeSnippet.razor b/Plotly.Blazor.Examples/Shared/CodeSnippet.razor index c8327c84..afc9ec61 100644 --- a/Plotly.Blazor.Examples/Shared/CodeSnippet.razor +++ b/Plotly.Blazor.Examples/Shared/CodeSnippet.razor @@ -14,7 +14,14 @@ { if (firstRender) { - Code = await CodeHttpClient.GetStringAsync(Url); + try + { + Code = await CodeHttpClient.GetStringAsync(Url); + } + catch + { + // ignore + } StateHasChanged(); } await JsRunTime.InvokeVoidAsync("onBlazorReady"); diff --git a/Plotly.Blazor.Examples/Shared/NavMenu.razor b/Plotly.Blazor.Examples/Shared/NavMenu.razor index 6725b354..92d10d6e 100644 --- a/Plotly.Blazor.Examples/Shared/NavMenu.razor +++ b/Plotly.Blazor.Examples/Shared/NavMenu.razor @@ -8,11 +8,10 @@ @foreach (var pageInfo in pageInfos) { - var uri = new Uri(NavManager.Uri); - var color = uri.AbsolutePath.TrimStart('/').Equals(pageInfo.Page.TrimStart('/')) ? Color.Primary : Color.Default; - var href = $"{NavManager.BaseUri}{pageInfo.Page}"; + var uri = NavManager.BaseUri + pageInfo.Page; + var color = NavManager.Uri.Equals(uri, StringComparison.InvariantCultureIgnoreCase) ? Color.Primary : Color.Default; - @pageInfo.Title + @pageInfo.Title } diff --git a/Plotly.Blazor.Examples/Shared/NavMenu.razor.cs b/Plotly.Blazor.Examples/Shared/NavMenu.razor.cs index df64b4ca..98972387 100644 --- a/Plotly.Blazor.Examples/Shared/NavMenu.razor.cs +++ b/Plotly.Blazor.Examples/Shared/NavMenu.razor.cs @@ -56,7 +56,8 @@ private class PageInfo new() { Page = "hover", Title = "Hover Event" }, new() { Page = "click", Title = "Click Event" }, new() { Page = "legendclick", Title = "Legend Click Event" }, - new() { Page = "relayout", Title = "Relayout Event" } + new() { Page = "relayout", Title = "Relayout Event" }, + new() { Page = "selected", Title = "Selected Event" } }; private void OpenOrCloseDrawer() diff --git a/Plotly.Blazor.Generator/Plotly.Blazor.Generator.csproj b/Plotly.Blazor.Generator/Plotly.Blazor.Generator.csproj index 8bd37d82..db4f4238 100644 --- a/Plotly.Blazor.Generator/Plotly.Blazor.Generator.csproj +++ b/Plotly.Blazor.Generator/Plotly.Blazor.Generator.csproj @@ -33,7 +33,7 @@ true Always - + true PreserveNewest Always diff --git a/Plotly.Blazor.Generator/src/PlotlyJsInterop.cs b/Plotly.Blazor.Generator/src/PlotlyJsInterop.cs index f7952d94..971f2617 100644 --- a/Plotly.Blazor.Generator/src/PlotlyJsInterop.cs +++ b/Plotly.Blazor.Generator/src/PlotlyJsInterop.cs @@ -14,7 +14,7 @@ namespace Plotly.Blazor; /// public class PlotlyJsInterop { - private const string InteropPath = "./_content/Plotly.Blazor/plotly-interop-2.33.0.js"; + private const string InteropPath = "./_content/Plotly.Blazor/plotly-interop-5.1.0.js"; private const string PlotlyPath = "./_content/Plotly.Blazor/plotly-2.33.0.min.js"; private const string PlotlyBasicPath = "./_content/Plotly.Blazor/plotly-basic-1.58.5.min.js"; diff --git a/Plotly.Blazor/wwwroot/plotly-interop-2.33.0.js b/Plotly.Blazor.Generator/src/wwwroot/plotly-interop-5.1.0.js similarity index 84% rename from Plotly.Blazor/wwwroot/plotly-interop-2.33.0.js rename to Plotly.Blazor.Generator/src/wwwroot/plotly-interop-5.1.0.js index 430444cb..b4608c09 100644 --- a/Plotly.Blazor/wwwroot/plotly-interop-2.33.0.js +++ b/Plotly.Blazor.Generator/src/wwwroot/plotly-interop-5.1.0.js @@ -139,6 +139,42 @@ export function subscribeLegendClickEvent(dotNetObj, id) { }) }) } +export function subscribeSelectedEvent(dotNetObj, id) { + var plot = document.getElementById(id); + plot.on('plotly_selected', function (data) { + dotNetObj.invokeMethodAsync('SelectedEvent', + data.points.map(function (d) { + if (d.x != null) { + return ({ + TraceIndex: d.fullData.index, + PointIndex: d.pointIndex, + PointNumber: d.pointNumber, + CurveNumber: d.curveNumber, + Text: d.text, + X: d.x, + Y: d.y, + Z: d.z, + Lat: d.lat, + Lon: d.lon + }); + } + else { + return ({ + TraceIndex: d.fullData.index, + PointIndex: d.pointIndex, + PointNumber: d.pointNumber, + CurveNumber: d.curveNumber, + Text: d.text, + X: d.value, + Y: d.label, + Z: null, + Lat: d.lat, + Lon: d.lon + }); + } + })); + }) +} export function subscribeClickEvent(dotNetObj, id) { var plot = document.getElementById(id); plot.on('plotly_click', function (data) { diff --git a/Plotly.Blazor/Plotly.Blazor.xml b/Plotly.Blazor/Plotly.Blazor.xml index ecd36bf3..b4372dcc 100644 --- a/Plotly.Blazor/Plotly.Blazor.xml +++ b/Plotly.Blazor/Plotly.Blazor.xml @@ -23166,6 +23166,12 @@ Objects are currently required for accommodating different plot value types + + + Defines the action that should happen when the SelectedEvent is triggered. + Objects are currently required for accommodating different plot value types + + Defines the action that should happen when the RelayoutEvent is triggered. @@ -23190,6 +23196,13 @@ + + + Method which is called by JSRuntime once a you selected plot points, to invoke the passed in SelectedAction. + Objects are currently required for accommodating different plot value types. + + + Method which is called by JSRuntime when the chart's layout has changed. @@ -23216,6 +23229,13 @@ CancellationToken Task + + + Subscribes to the selected event of the chart. + + CancellationToken + Task + Subscribes to the relayout event of the chart. @@ -23382,6 +23402,12 @@ CancellationToken + + + Can be used to subscribe selected events for points. + + CancellationToken + Can be used to subscribe to relayout events. diff --git a/Plotly.Blazor/PlotlyChart.razor.cs b/Plotly.Blazor/PlotlyChart.razor.cs index a7137875..39b335c9 100644 --- a/Plotly.Blazor/PlotlyChart.razor.cs +++ b/Plotly.Blazor/PlotlyChart.razor.cs @@ -947,6 +947,13 @@ public async Task PrependTraces3D(IEnumerable> x, IEnumerabl [Parameter] public Action> HoverAction { get; set; } + /// + /// Defines the action that should happen when the SelectedEvent is triggered. + /// Objects are currently required for accommodating different plot value types + /// + [Parameter] + public Action> SelectedAction { get; set; } + /// /// Defines the action that should happen when the RelayoutEvent is triggered. /// @@ -986,6 +993,17 @@ public void HoverEvent(IEnumerable eventData) HoverAction?.Invoke(eventData); } + /// + /// Method which is called by JSRuntime once a you selected plot points, to invoke the passed in SelectedAction. + /// Objects are currently required for accommodating different plot value types. + /// + /// + [JSInvokable("SelectedEvent")] + public void SelectedEvent(IEnumerable eventData) + { + SelectedAction?.Invoke(eventData); + } + /// /// Method which is called by JSRuntime when the chart's layout has changed. /// @@ -1025,6 +1043,16 @@ public async Task SubscribeHoverEvent(CancellationToken cancellationToken = defa await Interop.SubscribeHoverEvent(cancellationToken); } + /// + /// Subscribes to the selected event of the chart. + /// + /// CancellationToken + /// Task + public async Task SubscribeSelectedEvent(CancellationToken cancellationToken = default) + { + await Interop.SubscribeSelectedEvent(cancellationToken); + } + /// /// Subscribes to the relayout event of the chart. /// diff --git a/Plotly.Blazor/PlotlyJsInterop.cs b/Plotly.Blazor/PlotlyJsInterop.cs index f7952d94..d861fa4b 100644 --- a/Plotly.Blazor/PlotlyJsInterop.cs +++ b/Plotly.Blazor/PlotlyJsInterop.cs @@ -14,7 +14,7 @@ namespace Plotly.Blazor; /// public class PlotlyJsInterop { - private const string InteropPath = "./_content/Plotly.Blazor/plotly-interop-2.33.0.js"; + private const string InteropPath = "./_content/Plotly.Blazor/plotly-interop-5.1.0.js"; private const string PlotlyPath = "./_content/Plotly.Blazor/plotly-2.33.0.min.js"; private const string PlotlyBasicPath = "./_content/Plotly.Blazor/plotly-basic-1.58.5.min.js"; @@ -298,6 +298,17 @@ public async Task SubscribeHoverEvent(CancellationToken cancellationToken) await jsRuntime.InvokeVoidAsync("subscribeHoverEvent", cancellationToken, dotNetObj, dotNetObj.Value.Id); } + /// + /// Can be used to subscribe selected events for points. + /// + /// CancellationToken + public async Task SubscribeSelectedEvent(CancellationToken cancellationToken) + { + var jsRuntime = await moduleTask.Value; + + await jsRuntime.InvokeVoidAsync("subscribeSelectedEvent", cancellationToken, dotNetObj, dotNetObj.Value.Id); + } + /// /// Can be used to subscribe to relayout events. /// diff --git a/Plotly.Blazor.Generator/src/wwwroot/plotly-interop-2.33.0.js b/Plotly.Blazor/wwwroot/plotly-interop-5.1.0.js similarity index 83% rename from Plotly.Blazor.Generator/src/wwwroot/plotly-interop-2.33.0.js rename to Plotly.Blazor/wwwroot/plotly-interop-5.1.0.js index 88202feb..b4608c09 100644 --- a/Plotly.Blazor.Generator/src/wwwroot/plotly-interop-2.33.0.js +++ b/Plotly.Blazor/wwwroot/plotly-interop-5.1.0.js @@ -139,6 +139,42 @@ export function subscribeLegendClickEvent(dotNetObj, id) { }) }) } +export function subscribeSelectedEvent(dotNetObj, id) { + var plot = document.getElementById(id); + plot.on('plotly_selected', function (data) { + dotNetObj.invokeMethodAsync('SelectedEvent', + data.points.map(function (d) { + if (d.x != null) { + return ({ + TraceIndex: d.fullData.index, + PointIndex: d.pointIndex, + PointNumber: d.pointNumber, + CurveNumber: d.curveNumber, + Text: d.text, + X: d.x, + Y: d.y, + Z: d.z, + Lat: d.lat, + Lon: d.lon + }); + } + else { + return ({ + TraceIndex: d.fullData.index, + PointIndex: d.pointIndex, + PointNumber: d.pointNumber, + CurveNumber: d.curveNumber, + Text: d.text, + X: d.value, + Y: d.label, + Z: null, + Lat: d.lat, + Lon: d.lon + }); + } + })); + }) +} export function subscribeClickEvent(dotNetObj, id) { var plot = document.getElementById(id); plot.on('plotly_click', function (data) { @@ -221,6 +257,9 @@ export function subscribeRelayoutEvent(dotNetObj, id) { var y1 = data["yaxis.range[0]"] var y2 = data["yaxis.range[1]"] + var z1 = data["zaxis.range[0]"] + var z2 = data["zaxis.range[1]"] + var result = {}; if (x1 && x2) { @@ -230,6 +269,11 @@ export function subscribeRelayoutEvent(dotNetObj, id) { if (y1 && y2) { result.YRange = [y1, y2]; } + + if (z1 && z2) { + result.ZRange = [z1, z2]; + } + dotNetObj.invokeMethodAsync('RelayoutEvent', result); }); } \ No newline at end of file