Introducing a new command to push data to the js kernel
using Microsoft.DotNet.Interactive;
using Microsoft.DotNet.Interactive.Commands;
public class WidgetData : KernelCommand {
public int[] Data {get;set;}
public WidgetData(string targetKernelName = null) : base(targetKernelName?? "javascript") {
}
}
register the command for serialization
var jsKernel = Kernel.Root.FindKernelByName("javascript");
jsKernel.RegisterCommandType<WidgetData>();
load 3djs using import
d3 = await import("https://cdn.jsdelivr.net/npm/d3@7/+esm");
adding the handler to the javascript
kernel, this will use d3js
to refresh the display
let jskernel = kernel.root.findKernelByName('javascript');
jskernel.registerCommandHandler({commandType: 'WidgetData', handle: c => {
const svg = d3.select("#d3_target");
const data = c.commandEnvelope.command.data;
const scaleFactor = 0.9;
const container = svg.select(".container");
const colorMap = (d) => d3.interpolateWarm(d / 80);
const p = container.selectAll(".points")
.data(data, (d, i) => i);
p.transition()
.duration(2000)
.style("fill", d => colorMap(d))
.attr("r", d => Math.max(0, d * scaleFactor));
p.enter()
.append("circle")
.attr("class", "points")
.attr("cy", 80)
.attr("cx", (d,i) => ((i) + 1) * 60)
.transition()
.duration(2000)
.style("fill", d => colorMap(d))
.ease(d3.easeElasticOut.period(1.00))
.attr("r", d => Math.max(0, d * scaleFactor)),
p.exit()
.transition()
.duration(1000)
.attr("r", 0)
.remove();
}});
add the html placeholder
<svg id="d3_target" style="width:100%;"></svg>
setup the svg container with some svg effects
const svg = d3.select("#d3_target");
let defs = svg.append("defs");
let filter = defs.append("filter").attr("id", "gooeyCodeFilter");
filter.append("feGaussianBlur")
.attr("in", "SourceGraphic")
.attr("stdDeviation", "10")
.attr("color-interpolation-filters", "sRGB")
.attr("result", "blur");
filter.append("feColorMatrix")
.attr("in", "blur")
.attr("mode", "matrix")
.attr("values", "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9")
.attr("result", "gooey");
d3.select("#d3_target")
.append("g")
.style("filter", "url(#gooeyCodeFilter)")
.classed("container", true);
generate data and send it to javscript using the new command
var rnd = new Random();
for(var i = 0; i < 10; i++){
await Task.Delay(1000);
var limit = rnd.Next(4,12);
var data = Enumerable.Range(1,limit).Select( t => rnd.Next(30, 80)).ToArray();
await Kernel.Root.SendAsync(new WidgetData("javascript"){
Data = data
});
}