Another feature of the SubCharts API is an ability to add custom HTML content around a sub-chart.
When adding a Sub Chart to a SciChartSurface with the addSubChart() function, you can place extra optional HTML elements into the DOM. By specifying their IDs and classes to the SubChart, they can be positioned on top of, and around the SciChartSubSurface.
<!-- the Div where the SciChartSurface will reside --> <div id="scichart-root"></div> <!-- the div where a custom HTML elements could reside, its size and position will be managed by SciChartSurface --> <div id="sub-chart-container-id-1" class="sub-chart-container"> <div class="chart-html-section left-section"> A left section of the sub-chart </div> <div class="chart-html-section right-section">Right Section</div> <div class="chart-html-section top-section">Top Section</div> <div class="chart-html-section bottom-section">Bottom Section</div> </div>
body { margin: 0; } #scichart-root { width: 100%; height: 100vh; } .sub-chart-container { position: absolute; border: 1px solid red; } .chart-html-section { pointer-events: all; position: absolute; } .left-section { width: 100px; height: 100%; background-color: rgba(212, 245, 66, 0.5); } .right-section { top: 0; right: 0; width: 100px; height: 100%; background-color: rgba(226, 78, 14, 0.5); } .top-section { top: 0; width: calc(100% - 200px); height: 50px; position: absolute; left: 100px; background-color: rgba(236, 66, 245, 0.5); } .bottom-section { bottom: 0; width: calc(100% - 200px); height: 50px; position: absolute; left: 100px; background-color: rgba(66, 245, 224, 0.5); }
const xValues = []; const yValues = []; for (let i = 0; i < 100; i++) { xValues.push(i); yValues.push(0.2 * Math.sin(i * 0.1) - Math.cos(i * 0.01)); } async function simpleSubChart(divElementId) { // Demonstrates how to use the Sub-Charts API to create child charts in a parent chart const { SciChartSurface, NumericAxis, FastLineRenderableSeries, XyDataSeries, SciChartJsNavyTheme, Rect, ECoordinateMode, ZoomPanModifier, ZoomExtentsModifier, MouseWheelZoomModifier, BoxAnnotation, NumberRange, } = SciChart; // or, for npm, import { SciChartSurface, ... } from "scichart" // Create a parent (regular) SciChartSurface which will contain the sub-chart const { wasmContext, sciChartSurface } = await SciChartSurface.create( divElementId, { theme: new SciChartJsNavyTheme(), } ); // Create X,Y axis on the parent chart and programmatically zoom into part of the data sciChartSurface.xAxes.add(new NumericAxis(wasmContext)); sciChartSurface.yAxes.add(new NumericAxis(wasmContext)); // #region ExampleA // Add a Sub-Charts to the main surface. This will display a rectangle showing the current zoomed in area on the parent chart const subChart1 = sciChartSurface.addSubChart({ position: new Rect(0.1, 0.1, 0.6, 0.4), isTransparent: false, isVisible: true, coordinateMode: ECoordinateMode.Relative, title: "SubChart with HTML Elements", titleStyle: { fontSize: 16, color: "#eeeeee77" }, // Specify the subChartContainer for extra HTML elements // These will be positioned by SciChartSubSurface // This property accepts a string or an HTMLDivElement subChartContainerId: "sub-chart-container-id-1", }); // specify class names of section elements within the sub-chart container subChart1.topSectionClass = "top-section"; subChart1.leftSectionClass = "left-section"; subChart1.bottomSectionClass = "bottom-section"; subChart1.rightSectionClass = "right-section"; // #endregion // Add x,y axis to the subchart subChart1.xAxes.add(new NumericAxis(wasmContext)); subChart1.yAxes.add(new NumericAxis(wasmContext)); // Add a series to the subchart subChart1.renderableSeries.add( new FastLineRenderableSeries(wasmContext, { stroke: "#47bde6", strokeThickness: 5, dataSeries: new XyDataSeries(wasmContext, { xValues, yValues, }), }) ); } simpleSubChart("scichart-root"); async function builderExample(divElementId) { // Demonstrates how to create a line chart with SciChart.js using the Builder API const { chartBuilder, ESeriesType, EAxisType, EThemeProviderType, Rect, ECoordinateMode, } = SciChart; // or, for npm, import { chartBuilder, ... } from "scichart" // #region ExampleB const { wasmContext, sciChartSurface } = await chartBuilder.build2DChart( divElementId, { surface: { theme: { type: EThemeProviderType.Dark } }, // Main chart definition is here xAxes: { type: EAxisType.NumericAxis }, yAxes: { type: EAxisType.NumericAxis }, // Subchart definition is here subCharts: [ { surface: { position: new Rect(0.1, 0.1, 0.6, 0.4), isTransparent: false, isVisible: true, coordinateMode: ECoordinateMode.Relative, title: "SubChart with HTML Elements", titleStyle: { fontSize: 16, color: "#eeeeee77" }, // Specify the subChartContainer for extra HTML elements // These will be positioned by SciChartSubSurface // This property accepts a string or an HTMLDivElement subChartContainerId: "sub-chart-container-id-1", }, // Define the x,y axis on Subchart xAxes: { type: EAxisType.NumericAxis }, yAxes: { type: EAxisType.NumericAxis }, // Define the series on Subchart series: [ { type: ESeriesType.LineSeries, xyData: { xValues, yValues: yValues1, }, options: { stroke: "#0066FF", strokeThickness: 5, }, }, ], }, ], } ); // #endregion } // Uncomment this to use the builder example //builderExample("scichart-root");
This is achieved by composing following required HTML elements:
- scichart-root-element - the element used to create the main surface.
- sub-chart-container - the element which will be displayed at the sub-surface position. It will have the sub-surface and custom html inside; more sub-chart containers could be added if there are many sub-charts.
- chart-html-section - the element which will hold the actual custom HTML content; sections are placed to the sides of a sub-surface accordingly to their class names: left-section, right-section, top-section, bottom-section.
Here is the setup required for the example: We will start from adding HTML markup which corresponds to the descriptions above. CSS is also added to give the HTML elements size and note that each have position: absolute
.
In the JavaScript, we create a SubChart as normal by calling addSubChart(), however we also specify I2DSubSurfaceOptions.subChartContainerId. This property accepts both string (Id) or HtmlDivElement
. We also specify class names that will identify sections of the container.
As a result the container will be drawn with the position and sizes specified when creating the sub-surface, while the sub-surface itself will shrink accordingly to the space occupied by the custom content sections.
Creating a Draggable Header on SubCharts
Let's create a concrete example of using HTML Containers with SubCharts. In this updated example we will create some HTML elements and place them dynamically using JavaScript. This will give the effect of creating a draggable SubChart on a SciChartSurface.
First let's create a function to create a Sub-Chart with container HTML.
This function creates a container <div>
element with a unique Id and adds it to the DOM. It creates a topBar <div> and adds that to the container. CSS styles are applied to ensure position: absolute
and the className = "top-section"
is applied to the topBar, which helps SciChart position the element around the SubChart. We destructure the options so that the title can be set on the topBar and create the SubChart speciying the subChartContainerId
as an HTMLElement (also supports string Id).
Next, by subscribing to container.onpointerdown
, onpointermove
and onpointerup
we can reposition the SubChart by calling SciChartSubSurface.subPosition
. Note that this accepts a Rect
with relative coordinates, so we have to calculate that based on the parent sciChartSurface.domChartRoot
width & height.
position: absolute
and applying applying className = "top-section"
helps SciChart position the top section above the SubChart.
The SubChart can now be added to a parent SciChartSurface as follows:
This declares a SubChart with initial position, and adds some x,y axis and series.
Here's the result. You can now have a draggable SubChart window in a SciChartSurface!
<!-- the Div where the SciChartSurface will reside --> <div id="scichart-root"></div>
body { margin: 0; } #scichart-root { width: 100%; height: 100vh; }
const xValues = []; const yValues = []; for (let i = 0; i < 100; i++) { xValues.push(i); yValues.push(0.2 * Math.sin(i * 0.1) - Math.cos(i * 0.01)); } const { SciChartSurface, NumericAxis, FastLineRenderableSeries, XyDataSeries, SciChartJsNavyTheme, Rect, ECoordinateMode, ZoomPanModifier, ZoomExtentsModifier, MouseWheelZoomModifier, BoxAnnotation, NumberRange, generateGuid, } = SciChart; // or, for npm, import { SciChartSurface, ... } from "scichart" // #region createSubChartContainer function createSubChartContainer(sciChartSurface, subChartOptions) { // Create the subChartContainer HTML and add to the DOM const container = document.createElement("div"); container.id = generateGuid(); // generateGuid imported from SciChart container.style.position = "absolute"; container.style.border = "1px solid #4682b4"; document.body.appendChild(container); const { title, ...subChartOptionsNoTitle } = subChartOptions; // Create a top bar header HTML element for the subchart const topBar = document.createElement("div"); topBar.style.pointerEvents = "all"; topBar.style.position = "absolute"; topBar.style.top = "0"; topBar.style.width = "100%"; topBar.style.height = "30px"; topBar.style.backgroundColor = "#4682b4"; // className is required to specify that this is a top-section bar, to be positioned outside the chart // even if this class isn't used or specified in the DOM. // Default available options are "top-section", "bottom-section", "left-section", "right-section" topBar.className = "top-section"; container.appendChild(topBar); const containerTitle = document.createElement("span"); containerTitle.style.userSelect = "none"; containerTitle.style.color = "#eee"; containerTitle.style.fontFamily = "Arial"; containerTitle.style.fontWeight = "Bold"; containerTitle.style.left = "10px"; containerTitle.style.top = "5px"; containerTitle.style.position = "relative"; containerTitle.innerText = title; topBar.appendChild(containerTitle); // Add a Sub-Charts to the main surface. This will display a rectangle showing the current zoomed in area on the parent chart const subChart = sciChartSurface.addSubChart({ ...subChartOptionsNoTitle, theme: sciChartSurface.themeProvider, // Specify the subChartContainer subChartContainerId: container, }); // Track dragging state let isDragging = false; let startX = 0; let startY = 0; let startRect; // Handle pointer down to start drag container.onpointerdown = (e) => { isDragging = true; startX = e.clientX; startY = e.clientY; startRect = subChart.subPosition; // Capture pointer to receive events outside container container.setPointerCapture(e.pointerId); }; // Handle pointer move to update position container.onpointermove = (e) => { if (!isDragging) return; // Calculate delta movement in pixels const deltaX = e.clientX - startX; const deltaY = e.clientY - startY; // Convert pixel movement to relative coordinates (0..1) const parentWidth = sciChartSurface.domChartRoot.clientWidth; const parentHeight = sciChartSurface.domChartRoot.clientHeight; const relativeX = deltaX / parentWidth; const relativeY = deltaY / parentHeight; // Update subchart position subChart.subPosition = new Rect( startRect.x + relativeX, startRect.y + relativeY, startRect.width, startRect.height ); }; // Handle pointer up to end drag container.onpointerup = (e) => { isDragging = false; container.releasePointerCapture(e.pointerId); }; return subChart; } // #endregion async function simpleSubChart(divElementId) { // Create a parent (regular) SciChartSurface which will contain the sub-chart const { wasmContext, sciChartSurface } = await SciChartSurface.create( divElementId, { theme: new SciChartJsNavyTheme(), } ); // Create X,Y axis on the parent chart and programmatically zoom into part of the data sciChartSurface.xAxes.add(new NumericAxis(wasmContext)); sciChartSurface.yAxes.add(new NumericAxis(wasmContext)); // #region addSubChart const subChart = createSubChartContainer(sciChartSurface, { position: new Rect(0.1, 0.1, 0.4, 0.4), isTransparent: false, isVisible: true, coordinateMode: ECoordinateMode.Relative, title: "Draggable Sub-Chart Window", }); // Add x,y axis to the subchart subChart.xAxes.add(new NumericAxis(wasmContext)); subChart.yAxes.add(new NumericAxis(wasmContext)); // Add a series to the subchart subChart.renderableSeries.add( new FastLineRenderableSeries(wasmContext, { stroke: "#47bde6", strokeThickness: 5, dataSeries: new XyDataSeries(wasmContext, { xValues, yValues, }), }) ); // #endregion } simpleSubChart("scichart-root");