diff --git a/Examples/src/components/AppRouter/examplePaths.ts b/Examples/src/components/AppRouter/examplePaths.ts
index 52ef139ff..95f7aa0d1 100644
--- a/Examples/src/components/AppRouter/examplePaths.ts
+++ b/Examples/src/components/AppRouter/examplePaths.ts
@@ -14,7 +14,6 @@ export default [
"../Examples/Charts2D/AxisLabelCustomization/MultiLineLabels",
"../Examples/Charts2D/AxisLabelCustomization/RotatedLabels",
"../Examples/Charts2D/BasicChartTypes/BandSeriesChart",
- "../Examples/Charts2D/v4Charts/HeatmapOverMap",
"../Examples/Charts2D/BasicChartTypes/BubbleChart",
"../Examples/Charts2D/BasicChartTypes/CandlestickChart",
"../Examples/Charts2D/BasicChartTypes/ColumnChart",
@@ -60,13 +59,14 @@ export default [
"../Examples/Charts2D/Filters/PercentageChange",
"../Examples/Charts2D/Filters/TrendMARatio",
"../Examples/Charts2D/Legends/ChartLegendsAPI",
- "../Examples/Charts2D/ModifyAxisBehavior/DiscontinuousDateAxisComparison",
"../Examples/Charts2D/ModifyAxisBehavior/BaseValueAxes",
"../Examples/Charts2D/ModifyAxisBehavior/CentralAxes",
+ "../Examples/Charts2D/ModifyAxisBehavior/DiscontinuousDateAxisComparison",
"../Examples/Charts2D/ModifyAxisBehavior/DrawBehindAxes",
"../Examples/Charts2D/ModifyAxisBehavior/LogarithmicAxis",
"../Examples/Charts2D/ModifyAxisBehavior/MultipleXAxes",
"../Examples/Charts2D/ModifyAxisBehavior/SecondaryYAxes",
+ "../Examples/Charts2D/ModifyAxisBehavior/SmithChart",
"../Examples/Charts2D/ModifyAxisBehavior/StaticAxis",
"../Examples/Charts2D/ModifyAxisBehavior/VerticalCharts",
"../Examples/Charts2D/ModifyAxisBehavior/VerticallyStackedAxes",
@@ -128,6 +128,7 @@ export default [
"../Examples/Charts2D/v4Charts/AnimatedColumns",
"../Examples/Charts2D/v4Charts/BoxPlotChart",
"../Examples/Charts2D/v4Charts/GanttChart",
+ "../Examples/Charts2D/v4Charts/HeatmapOverMap",
"../Examples/Charts2D/v4Charts/HeatmapRectangle",
"../Examples/Charts2D/v4Charts/HistogramChart",
"../Examples/Charts2D/v4Charts/LinearGauges",
@@ -168,5 +169,5 @@ export default [
"../Examples/FeaturedApps/ShowCases/OilAndGasDashboard",
"../Examples/FeaturedApps/ShowCases/PopulationPyramid",
"../Examples/FeaturedApps/ShowCases/ServerTrafficDashboard",
- "../Examples/FeaturedApps/ShowCases/WebsocketBigData",
+ "../Examples/FeaturedApps/ShowCases/WebsocketBigData"
];
diff --git a/Examples/src/components/AppRouter/examples.ts b/Examples/src/components/AppRouter/examples.ts
index f4c6daa11..312a77e9a 100644
--- a/Examples/src/components/AppRouter/examples.ts
+++ b/Examples/src/components/AppRouter/examples.ts
@@ -193,6 +193,7 @@ export const MENU_ITEMS_2D: TMenuItem[] = [
EXAMPLES_PAGES.chart2D_modifyAxisBehavior_SecondaryYAxes,
EXAMPLES_PAGES.chart2D_modifyAxisBehavior_VerticalCharts,
EXAMPLES_PAGES.chart2D_modifyAxisBehavior_CentralAxes,
+ EXAMPLES_PAGES.chart2D_modifyAxisBehavior_SmithChart,
EXAMPLES_PAGES.chart2D_modifyAxisBehavior_StaticAxis,
EXAMPLES_PAGES.chart2D_modifyAxisBehavior_VerticallyStackedAxes,
EXAMPLES_PAGES.chart2D_modifyAxisBehavior_LogarithmicAxis,
diff --git a/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/README.md b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/README.md
new file mode 100644
index 000000000..c02b6aea5
--- /dev/null
+++ b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/README.md
@@ -0,0 +1,68 @@
+# Central Axes (Central Axes Layout Example)
+
+## Overview
+
+This example demonstrates how to customize the axes layout in SciChart.js by placing the axes in the center of the chart. The example creates a chart with central axes that cross at the data value (0,0) (oscilloscope style) and includes implementations for React, Vanilla JavaScript/TypeScript, and Angular.
+
+## Technologies Used
+
+- SciChart.js (core charting library)
+- SciChart Angular Component
+- SciChart React Component
+- TypeScript and JavaScript
+
+## Code Explanation
+
+The heart of the example is the `drawExample` function (provided in both JavaScript and TypeScript versions). This function creates a SciChart Surface and configures a custom layout manager (CentralAxesLayoutManager) to display the x- and y-axes centrally. Key points include:
+
+- **Chart Creation:** A SciChart Surface is created with a specified theme.
+- **Custom Axis Layout:** The `CentralAxesLayoutManager` is instantiated with options to position the horizontal and vertical axes at data value 0, ensuring that the axes pan with the chart.
+- **Axis Configuration:** The x-axis and y-axis are configured as inner axes by setting `isInnerAxis` to true. This positions them in the center of the chart. Additional styling (like label color and axis borders) is applied.
+- **Data Series and Annotation:** A fast line renderable series is added that draws a butterfly curve generated by a helper function. Furthermore, a text annotation is added to describe the chart’s functionality.
+- **Interaction Modifiers:** Standard chart interaction modifiers (zoom pan, mouse wheel zoom, and zoom extents) are included to allow users to interact with the chart.
+
+The example also includes framework-specific files:
+
+- **Angular:** The `angular.ts` file sets up a standalone Angular component that uses the SciChart Angular component and binds its `drawExample` function.
+- **React:** The `index.tsx` file presents a React component which uses the SciChart React wrapper to initialize the chart with the `drawExample` function.
+- **Vanilla:** The `vanilla.js` and `vanilla.ts` files demonstrate how to create and dispose of the chart in a plain JavaScript/TypeScript environment.
+
+## Customization
+
+Key configuration options in this example include:
+
+- **Axis Positioning:** You can modify the options passed to the `CentralAxesLayoutManager` to change the axis alignment. By default, the axes are set to cross at (0,0) using the data value coordinate mode, but commented code shows how to use relative coordinate modes as well.
+- **Animation:** The fast line renderable series uses a fade animation with a duration of 500ms, which can be adjusted as needed.
+- **Styling:** Colors for axis labels, axis borders, and the renderable series stroke are set based on a theme. These can be customized to match your desired appearance.
+
+## Running the Example
+
+To run any example from the SciChart.JS.Examples repository, follow these steps:
+
+1. **Clone the Repository**: Download the entire repository to your local machine using Git:
+
+ ```bash
+ git clone https://github.com/ABTSoftware/SciChart.JS.Examples.git
+ ```
+
+2. **Navigate to the Examples Directory**: Change into the `Examples` folder:
+
+ ```bash
+ cd SciChart.JS.Examples/Examples
+ ```
+
+3. **Install Dependencies**: Install the necessary packages using npm:
+
+ ```bash
+ npm install
+ ```
+
+4. **Run the Development Server**: Start the development server to view and interact with the examples:
+
+ ```bash
+ npm run dev
+ ```
+
+ This will launch the demo application, allowing you to explore various examples, including the one in question.
+
+For more detailed instructions, refer to the [SciChart.JS.Examples README](https://github.com/ABTSoftware/SciChart.JS.Examples/blob/master/README.md).
diff --git a/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/angular.ts b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/angular.ts
new file mode 100644
index 000000000..1e5fa5e21
--- /dev/null
+++ b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/angular.ts
@@ -0,0 +1,15 @@
+import { Component } from "@angular/core";
+import { ScichartAngularComponent } from "scichart-angular";
+import { drawExample } from "./drawExample";
+
+@Component({
+ standalone: true,
+ selector: "app-root",
+ imports: [ScichartAngularComponent],
+ template: ``,
+})
+export class AppComponent {
+ title = "scichart-angular-app";
+
+ drawExample = drawExample;
+}
diff --git a/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/drawExample.ts b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/drawExample.ts
new file mode 100644
index 000000000..cd5c22779
--- /dev/null
+++ b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/drawExample.ts
@@ -0,0 +1,634 @@
+import { appTheme } from "../../../theme";
+import {
+ ChartModifierBase2D,
+ EAxisAlignment,
+ ECoordinateMode,
+ EHorizontalAnchorPoint,
+ EllipsePointMarker,
+ EVerticalAnchorPoint,
+ FastLineRenderableSeries,
+ ModifierMouseArgs,
+ MouseWheelZoomModifier,
+ NumericAxis,
+ NumberRange,
+ PinchZoomModifier,
+ SciChartSurface,
+ TextAnnotation,
+ TSciChart,
+ XyDataSeries,
+ XyScatterRenderableSeries,
+ ZoomExtentsModifier,
+} from "scichart";
+
+export const drawExample = async (rootElement: string | HTMLDivElement) => {
+ const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
+ theme: appTheme.SciChartJsTheme,
+ });
+
+ // Configure axes for Smith Chart (-1.15 to 1.15 range to show the full chart with padding)
+ sciChartSurface.xAxes.add(
+ new NumericAxis(wasmContext, {
+ visibleRange: new NumberRange(-1.15, 1.15),
+ axisAlignment: EAxisAlignment.Bottom,
+ drawMajorGridLines: false,
+ drawMinorGridLines: false,
+ drawMajorBands: false,
+ drawLabels: false,
+ drawMajorTickLines: false,
+ drawMinorTickLines: false,
+ })
+ );
+
+ sciChartSurface.yAxes.add(
+ new NumericAxis(wasmContext, {
+ visibleRange: new NumberRange(-1.15, 1.15),
+ axisAlignment: EAxisAlignment.Left,
+ drawMajorGridLines: false,
+ drawMinorGridLines: false,
+ drawMajorBands: false,
+ drawLabels: false,
+ drawMajorTickLines: false,
+ drawMinorTickLines: false,
+ })
+ );
+
+ // Define colors for grid lines
+ const gridColor = appTheme.ForegroundColor + "30"; // Light gray with transparency
+ const outerCircleColor = appTheme.ForegroundColor + "80"; // Darker for outer circle
+
+ // Outer circle (unit circle)
+ sciChartSurface.renderableSeries.add(
+ new FastLineRenderableSeries(wasmContext, {
+ dataSeries: createCircle(wasmContext, 0, 0, 1, 360),
+ stroke: outerCircleColor,
+ strokeThickness: 2,
+ })
+ );
+
+ // Constant resistance circles (r values)
+ const resistanceValues = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 3.0, 4.0, 5.0, 10, 20, 50];
+ const majorResistanceValues = [0.2, 0.5, 1.0, 2.0, 5.0, 10, 20, 50];
+
+ resistanceValues.forEach((r) => {
+ const center = r / (1 + r);
+ const radius = 1 / (1 + r);
+ const isMajor = majorResistanceValues.includes(r);
+
+ sciChartSurface.renderableSeries.add(
+ new FastLineRenderableSeries(wasmContext, {
+ dataSeries: createCircle(wasmContext, center, 0, radius, 360),
+ stroke: gridColor,
+ strokeThickness: isMajor ? 1 : 0.5,
+ })
+ );
+
+ // Add resistance labels on the horizontal axis
+ if (isMajor) {
+ const labelX = center - radius;
+ sciChartSurface.annotations.add(
+ new TextAnnotation({
+ text: r >= 1 ? r.toString() : r.toFixed(1),
+ x1: labelX,
+ y1: 0,
+ xCoordShift: 0,
+ yCoordShift: -15,
+ fontSize: 10,
+ textColor: appTheme.ForegroundColor,
+ opacity: 0.7,
+ horizontalAnchorPoint: EHorizontalAnchorPoint.Center,
+ })
+ );
+ }
+ });
+
+ // Constant reactance arcs (x values)
+ const reactanceValues = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 3.0, 4.0, 5.0, 10, 20, 50];
+ const majorReactanceValues = [0.2, 0.5, 1.0, 2.0, 5.0, 10, 20, 50];
+
+ // Positive reactance (upper half)
+ reactanceValues.forEach((x) => {
+ const isMajor = majorReactanceValues.includes(x);
+
+ sciChartSurface.renderableSeries.add(
+ new FastLineRenderableSeries(wasmContext, {
+ dataSeries: createReactanceArc(wasmContext, x, true),
+ stroke: gridColor,
+ strokeThickness: isMajor ? 1 : 0.5,
+ })
+ );
+
+ // Add reactance labels on the outer circle where the arc meets it
+ if (isMajor) {
+ const xVal2 = x * x;
+ const labelX = (xVal2 - 1) / (1 + xVal2);
+ const labelY = 2 * x / (1 + xVal2);
+
+ sciChartSurface.annotations.add(
+ new TextAnnotation({
+ text: `+${x >= 1 ? x.toString() : x.toFixed(1)}`,
+ x1: labelX,
+ y1: labelY,
+ xCoordShift: 15,
+ yCoordShift: 0,
+ fontSize: 10,
+ textColor: appTheme.ForegroundColor,
+ opacity: 0.7,
+ horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
+ verticalAnchorPoint: EVerticalAnchorPoint.Center,
+ })
+ );
+ }
+ });
+
+ // Negative reactance (lower half)
+ reactanceValues.forEach((x) => {
+ const isMajor = majorReactanceValues.includes(x);
+
+ sciChartSurface.renderableSeries.add(
+ new FastLineRenderableSeries(wasmContext, {
+ dataSeries: createReactanceArc(wasmContext, x, false),
+ stroke: gridColor,
+ strokeThickness: isMajor ? 1 : 0.5,
+ })
+ );
+
+ // Add reactance labels on the outer circle where the arc meets it
+ if (isMajor) {
+ const xVal2 = x * x;
+ const labelX = (xVal2 - 1) / (1 + xVal2);
+ const labelY = -2 * x / (1 + xVal2);
+
+ sciChartSurface.annotations.add(
+ new TextAnnotation({
+ text: `-${x >= 1 ? x.toString() : x.toFixed(1)}`,
+ x1: labelX,
+ y1: labelY,
+ xCoordShift: 15,
+ yCoordShift: 0,
+ fontSize: 10,
+ textColor: appTheme.ForegroundColor,
+ opacity: 0.7,
+ horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
+ verticalAnchorPoint: EVerticalAnchorPoint.Center,
+ })
+ );
+ }
+ });
+
+ // Add horizontal axis line (real axis)
+ sciChartSurface.renderableSeries.add(
+ new FastLineRenderableSeries(wasmContext, {
+ dataSeries: createLine(wasmContext, -1, 0, 1, 0),
+ stroke: gridColor,
+ strokeThickness: 1,
+ })
+ );
+
+ // Add axis label at the left end
+ sciChartSurface.annotations.add(
+ new TextAnnotation({
+ text: "0.0",
+ x1: -1,
+ y1: 0,
+ xCoordShift: -20,
+ yCoordShift: 0,
+ fontSize: 10,
+ textColor: appTheme.ForegroundColor,
+ opacity: 0.7,
+ horizontalAnchorPoint: EHorizontalAnchorPoint.Right,
+ verticalAnchorPoint: EVerticalAnchorPoint.Center,
+ })
+ );
+
+ // ═══════════════════════════════════════════════════════
+ // INTERACTIVE ELEMENTS - Draggable point with highlights
+ // ═══════════════════════════════════════════════════════
+
+ const rHighlightColor = "#FF4444"; // Red for constant resistance
+ const xHighlightColor = "#4488FF"; // Blue for constant reactance
+ const gammaColor = "#44CC44"; // Green for |Γ| and point
+
+ // Highlighted constant-R circle (red)
+ const rCircleDS = new XyDataSeries(wasmContext);
+ sciChartSurface.renderableSeries.add(
+ new FastLineRenderableSeries(wasmContext, {
+ dataSeries: rCircleDS,
+ stroke: rHighlightColor,
+ strokeThickness: 2.5,
+ })
+ );
+
+ // Highlighted constant-X arc (blue)
+ const xArcDS = new XyDataSeries(wasmContext);
+ sciChartSurface.renderableSeries.add(
+ new FastLineRenderableSeries(wasmContext, {
+ dataSeries: xArcDS,
+ stroke: xHighlightColor,
+ strokeThickness: 2.5,
+ })
+ );
+
+ // |Γ| circle (green, dashed)
+ const gammaCircleDS = new XyDataSeries(wasmContext);
+ sciChartSurface.renderableSeries.add(
+ new FastLineRenderableSeries(wasmContext, {
+ dataSeries: gammaCircleDS,
+ stroke: gammaColor,
+ strokeThickness: 1.5,
+ strokeDashArray: [5, 5],
+ })
+ );
+
+ // Draggable point marker (green)
+ const pointDS = new XyDataSeries(wasmContext);
+ pointDS.append(0, 0);
+ sciChartSurface.renderableSeries.add(
+ new XyScatterRenderableSeries(wasmContext, {
+ dataSeries: pointDS,
+ pointMarker: new EllipsePointMarker(wasmContext, {
+ width: 14,
+ height: 14,
+ fill: gammaColor,
+ stroke: "#FFFFFF",
+ strokeThickness: 2,
+ }),
+ })
+ );
+
+ // ═══════════════════════════════════════════════════════
+ // TEXT READOUTS - Γ, |Γ|, Z displayed on chart
+ // ═══════════════════════════════════════════════════════
+
+ const gammaTextAnnotation = new TextAnnotation({
+ x1: 0.02,
+ y1: 0.02,
+ xCoordinateMode: ECoordinateMode.Relative,
+ yCoordinateMode: ECoordinateMode.Relative,
+ text: "Γ = 0.000 + j0.000",
+ fontSize: 14,
+ fontFamily: "monospace",
+ textColor: appTheme.ForegroundColor,
+ horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
+ verticalAnchorPoint: EVerticalAnchorPoint.Top,
+ });
+
+ const gammaMagTextAnnotation = new TextAnnotation({
+ x1: 0.02,
+ y1: 0.06,
+ xCoordinateMode: ECoordinateMode.Relative,
+ yCoordinateMode: ECoordinateMode.Relative,
+ text: "|Γ| = 0.000",
+ fontSize: 14,
+ fontFamily: "monospace",
+ textColor: gammaColor,
+ horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
+ verticalAnchorPoint: EVerticalAnchorPoint.Top,
+ });
+
+ const impedanceTextAnnotation = new TextAnnotation({
+ x1: 0.02,
+ y1: 0.10,
+ xCoordinateMode: ECoordinateMode.Relative,
+ yCoordinateMode: ECoordinateMode.Relative,
+ text: "Z = 1.000 + j0.000",
+ fontSize: 14,
+ fontFamily: "monospace",
+ textColor: appTheme.ForegroundColor,
+ horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
+ verticalAnchorPoint: EVerticalAnchorPoint.Top,
+ });
+
+ const resistanceLabel = new TextAnnotation({
+ x1: 0.02,
+ y1: 0.14,
+ xCoordinateMode: ECoordinateMode.Relative,
+ yCoordinateMode: ECoordinateMode.Relative,
+ text: "R = 1.000",
+ fontSize: 14,
+ fontFamily: "monospace",
+ textColor: rHighlightColor,
+ horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
+ verticalAnchorPoint: EVerticalAnchorPoint.Top,
+ });
+
+ const reactanceLabel = new TextAnnotation({
+ x1: 0.02,
+ y1: 0.18,
+ xCoordinateMode: ECoordinateMode.Relative,
+ yCoordinateMode: ECoordinateMode.Relative,
+ text: "X = 0.000",
+ fontSize: 14,
+ fontFamily: "monospace",
+ textColor: xHighlightColor,
+ horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
+ verticalAnchorPoint: EVerticalAnchorPoint.Top,
+ });
+
+ sciChartSurface.annotations.add(
+ gammaTextAnnotation,
+ gammaMagTextAnnotation,
+ impedanceTextAnnotation,
+ resistanceLabel,
+ reactanceLabel
+ );
+
+ // ═══════════════════════════════════════════════════════
+ // UPDATE LOGIC - Recalculates all visuals when point moves
+ // ═══════════════════════════════════════════════════════
+
+ function updateInteractiveElements(gammaR: number, gammaI: number) {
+ // Clamp to unit circle
+ const mag = Math.sqrt(gammaR * gammaR + gammaI * gammaI);
+ let gr = gammaR;
+ let gi = gammaI;
+ if (mag > 1) {
+ gr = gammaR / mag;
+ gi = gammaI / mag;
+ }
+
+ const gammaMag = Math.sqrt(gr * gr + gi * gi);
+
+ // Compute impedance: Z = (1 + Γ) / (1 - Γ) = R + jX
+ const denom = (1 - gr) * (1 - gr) + gi * gi;
+ const r = denom > 1e-10 ? (1 - gr * gr - gi * gi) / denom : Infinity;
+ const x = denom > 1e-10 ? (2 * gi) / denom : Infinity;
+
+ // Update draggable point position
+ pointDS.clear();
+ pointDS.append(gr, gi);
+
+ // Update highlighted R circle
+ populateRCircle(rCircleDS, r);
+
+ // Update highlighted X arc
+ populateXArc(xArcDS, x);
+
+ // Update |Γ| circle
+ populateCircle(gammaCircleDS, 0, 0, gammaMag);
+
+ // Update text readouts
+ const signG = gi >= 0 ? "+" : "−";
+ gammaTextAnnotation.text = `Γ = ${gr.toFixed(3)} ${signG} j${Math.abs(gi).toFixed(3)}`;
+ gammaMagTextAnnotation.text = `|Γ| = ${gammaMag.toFixed(3)}`;
+
+ if (!isFinite(r) || !isFinite(x)) {
+ impedanceTextAnnotation.text = "Z = ∞";
+ resistanceLabel.text = "R = ∞";
+ reactanceLabel.text = "X = ∞";
+ } else {
+ const signZ = x >= 0 ? "+" : "−";
+ impedanceTextAnnotation.text = `Z = ${r.toFixed(3)} ${signZ} j${Math.abs(x).toFixed(3)}`;
+ resistanceLabel.text = `R = ${r.toFixed(3)}`;
+ reactanceLabel.text = `X = ${x >= 0 ? "" : "−"}${Math.abs(x).toFixed(3)}`;
+ }
+ }
+
+ // Populate an XyDataSeries with a constant-R circle
+ function populateRCircle(ds: XyDataSeries, r: number) {
+ ds.clear();
+ if (!isFinite(r) || r < 0) return;
+ const cx = r / (1 + r);
+ const rad = 1 / (1 + r);
+ const n = 200;
+ for (let i = 0; i <= n; i++) {
+ const angle = (i / n) * 2 * Math.PI;
+ ds.append(cx + rad * Math.cos(angle), rad * Math.sin(angle));
+ }
+ }
+
+ // Populate an XyDataSeries with a constant-X reactance arc
+ function populateXArc(ds: XyDataSeries, xVal: number) {
+ ds.clear();
+ if (!isFinite(xVal)) return;
+
+ // Near zero: draw horizontal axis
+ if (Math.abs(xVal) < 0.001) {
+ ds.append(-1, 0);
+ ds.append(1, 0);
+ return;
+ }
+
+ const absX = Math.abs(xVal);
+ const isPos = xVal > 0;
+ const radius = 1 / absX;
+ const cx = 1;
+ const cy = isPos ? radius : -radius;
+
+ const xv2 = absX * absX;
+ const xInt = (xv2 - 1) / (1 + xv2);
+ const yInt = isPos ? (2 * absX) / (1 + xv2) : (-2 * absX) / (1 + xv2);
+
+ const thetaOther = Math.atan2(yInt - cy, xInt - cx);
+ const thetaOrigin = isPos ? -Math.PI / 2 : Math.PI / 2;
+
+ let startAngle: number;
+ let endAngle: number;
+
+ if (isPos) {
+ startAngle = thetaOther;
+ endAngle = thetaOrigin;
+ while (endAngle <= startAngle) endAngle += 2 * Math.PI;
+ } else {
+ startAngle = thetaOrigin;
+ endAngle = thetaOther;
+ while (endAngle <= startAngle) endAngle += 2 * Math.PI;
+ }
+
+ const n = 200;
+ for (let i = 0; i <= n; i++) {
+ const angle = startAngle + (i / n) * (endAngle - startAngle);
+ ds.append(cx + radius * Math.cos(angle), cy + radius * Math.sin(angle));
+ }
+ }
+
+ // Populate an XyDataSeries with a circle centered at (cx, cy) with given radius
+ function populateCircle(ds: XyDataSeries, cx: number, cy: number, radius: number) {
+ ds.clear();
+ if (radius < 0.001) return;
+ const n = 200;
+ for (let i = 0; i <= n; i++) {
+ const angle = (i / n) * 2 * Math.PI;
+ ds.append(cx + radius * Math.cos(angle), cy + radius * Math.sin(angle));
+ }
+ }
+
+ // Initialize interactive elements at the origin (Γ = 0 → Z = 1)
+ updateInteractiveElements(0, 0);
+
+ // ═══════════════════════════════════════════════════════
+ // CUSTOM CHART MODIFIER - Handles click & drag on chart
+ // ═══════════════════════════════════════════════════════
+
+ class SmithChartDragModifier extends ChartModifierBase2D {
+ readonly type = "SmithChartDragModifier";
+ private isDragging = false;
+
+ modifierMouseDown(args: ModifierMouseArgs) {
+ super.modifierMouseDown(args);
+ this.isDragging = true;
+ this.handleDrag(args);
+ args.handled = true;
+ }
+
+ modifierMouseMove(args: ModifierMouseArgs) {
+ super.modifierMouseMove(args);
+ if (this.isDragging) {
+ this.handleDrag(args);
+ args.handled = true;
+ }
+ }
+
+ modifierMouseUp(args: ModifierMouseArgs) {
+ super.modifierMouseUp(args);
+ this.isDragging = false;
+ }
+
+ private handleDrag(args: ModifierMouseArgs) {
+ const { mousePoint } = args;
+ const xCalc = this.parentSurface.xAxes.get(0).getCurrentCoordinateCalculator();
+ const yCalc = this.parentSurface.yAxes.get(0).getCurrentCoordinateCalculator();
+
+ const dataX = xCalc.getDataValue(mousePoint.x);
+ const dataY = yCalc.getDataValue(mousePoint.y);
+
+ updateInteractiveElements(dataX, dataY);
+ }
+ }
+
+ // Add interaction modifiers
+ sciChartSurface.chartModifiers.add(
+ new SmithChartDragModifier(),
+ new MouseWheelZoomModifier(),
+ new ZoomExtentsModifier(),
+ new PinchZoomModifier()
+ );
+
+ // Preserve aspect ratio to always show circle (1:1 aspect ratio)
+ const xAxis = sciChartSurface.xAxes.get(0);
+ const yAxis = sciChartSurface.yAxes.get(0);
+
+ sciChartSurface.preRender.subscribe(() => {
+ const result = preserveAspectRatio(
+ sciChartSurface.viewRect.width,
+ sciChartSurface.viewRect.height,
+ xAxis.visibleRange.min,
+ xAxis.visibleRange.max,
+ yAxis.visibleRange.min,
+ yAxis.visibleRange.max
+ );
+
+ xAxis.visibleRange = new NumberRange(result.minVisibleX, result.maxVisibleX);
+ yAxis.visibleRange = new NumberRange(result.minVisibleY, result.maxVisibleY);
+ });
+
+ return { sciChartSurface, wasmContext };
+};
+
+// ═══════════════════════════════════════════════════════
+// HELPER FUNCTIONS
+// ═══════════════════════════════════════════════════════
+
+// Preserve aspect ratio (ensures circles remain circular)
+function preserveAspectRatio(
+ width: number,
+ height: number,
+ minVisibleX: number,
+ maxVisibleX: number,
+ minVisibleY: number,
+ maxVisibleY: number
+) {
+ const visibleWidth = maxVisibleX - minVisibleX;
+ const visibleHeight = maxVisibleY - minVisibleY;
+ const containerAspectRatio = width / height;
+ const visibleAspectRatio = visibleWidth / visibleHeight;
+
+ let newMinX: number, newMaxX: number, newMinY: number, newMaxY: number;
+
+ if (containerAspectRatio > visibleAspectRatio) {
+ const newVisibleWidth = visibleHeight * containerAspectRatio;
+ const widthDiff = newVisibleWidth - visibleWidth;
+ newMinX = minVisibleX - widthDiff / 2;
+ newMaxX = maxVisibleX + widthDiff / 2;
+ newMinY = minVisibleY;
+ newMaxY = maxVisibleY;
+ } else {
+ const newVisibleHeight = visibleWidth / containerAspectRatio;
+ const heightDiff = newVisibleHeight - visibleHeight;
+ newMinX = minVisibleX;
+ newMaxX = maxVisibleX;
+ newMinY = minVisibleY - heightDiff / 2;
+ newMaxY = maxVisibleY + heightDiff / 2;
+ }
+
+ return { minVisibleX: newMinX, maxVisibleX: newMaxX, minVisibleY: newMinY, maxVisibleY: newMaxY };
+}
+
+// Create a circle as an XyDataSeries
+function createCircle(wasmContext: TSciChart, cx: number, cy: number, radius: number, points: number = 360): XyDataSeries {
+ const dataSeries = new XyDataSeries(wasmContext);
+ for (let i = 0; i <= points; i++) {
+ const angle = (i / points) * 2 * Math.PI;
+ dataSeries.append(cx + radius * Math.cos(angle), cy + radius * Math.sin(angle));
+ }
+ return dataSeries;
+}
+
+// Create a reactance arc as an XyDataSeries.
+// For reactance value xVal, the circle has center (1, 1/xVal) and radius 1/xVal (positive)
+// or center (1, -1/xVal) and radius 1/xVal (negative).
+// All arcs pass through (1, 0) and curve to the other intersection with the unit circle.
+function createReactanceArc(
+ wasmContext: TSciChart,
+ xVal: number,
+ isPositive: boolean,
+ numPoints: number = 200
+): XyDataSeries {
+ const dataSeries = new XyDataSeries(wasmContext);
+ const radius = 1 / xVal;
+ const cx = 1;
+ const cy = isPositive ? radius : -radius;
+
+ // The reactance circle intersects the unit circle at two points:
+ // 1) Always at (1, 0)
+ // 2) At ((xVal²-1)/(1+xVal²), ±2·xVal/(1+xVal²))
+ const xVal2 = xVal * xVal;
+ const xInt = (xVal2 - 1) / (1 + xVal2);
+ const yInt = isPositive ? (2 * xVal) / (1 + xVal2) : (-2 * xVal) / (1 + xVal2);
+
+ // Angle from circle center to the second intersection point
+ const thetaOther = Math.atan2(yInt - cy, xInt - cx);
+
+ // Angle from circle center to (1, 0):
+ // Positive: atan2(0 - 1/xVal, 0) = -π/2
+ // Negative: atan2(0 + 1/xVal, 0) = π/2
+ const thetaOrigin = isPositive ? -Math.PI / 2 : Math.PI / 2;
+
+ let startAngle: number, endAngle: number;
+
+ if (isPositive) {
+ // Sweep counterclockwise from thetaOther to thetaOrigin
+ startAngle = thetaOther;
+ endAngle = thetaOrigin;
+ while (endAngle <= startAngle) endAngle += 2 * Math.PI;
+ } else {
+ // Sweep counterclockwise from thetaOrigin to thetaOther
+ startAngle = thetaOrigin;
+ endAngle = thetaOther;
+ while (endAngle <= startAngle) endAngle += 2 * Math.PI;
+ }
+
+ for (let i = 0; i <= numPoints; i++) {
+ const angle = startAngle + (i / numPoints) * (endAngle - startAngle);
+ dataSeries.append(cx + radius * Math.cos(angle), cy + radius * Math.sin(angle));
+ }
+
+ return dataSeries;
+}
+
+// Create a straight line as an XyDataSeries
+function createLine(wasmContext: TSciChart, x1: number, y1: number, x2: number, y2: number): XyDataSeries {
+ const dataSeries = new XyDataSeries(wasmContext);
+ dataSeries.append(x1, y1);
+ dataSeries.append(x2, y2);
+ return dataSeries;
+}
diff --git a/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/exampleInfo.tsx b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/exampleInfo.tsx
new file mode 100644
index 000000000..0b9b36245
--- /dev/null
+++ b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/exampleInfo.tsx
@@ -0,0 +1,66 @@
+import { createExampleInfo } from "../../../exampleInfoUtils";
+import { IExampleMetadata } from "../../../IExampleMetadata";
+
+const metaData: IExampleMetadata =
+ //// This metadata is computer generated - do not edit!
+ {
+ reactComponent: "SmithChart",
+ id: "chart2D_modifyAxisBehavior_SmithChart",
+ imagePath: "smith-chart.jpg",
+ description:
+ "Demonstrates how to create a **JavaScript Chart with Smith Chart** using SciChart.js, High Performance JavaScript Charts",
+ tips: [],
+ frameworks: {
+ javascript: {
+ subtitle:
+ "Demonstrates how to create a **JavaScript Chart with Smith Chart** using SciChart.js, High Performance JavaScript Charts",
+ title: "JavaScript Chart with Smith Chart",
+ pageTitle: "JavaScript Chart with Smith Chart",
+ metaDescription:
+ "Demonstrates Smith Chart on a JavaScript Chart using SciChart.js. SciChart supports unlimited left, right, top, bottom X, Y axis with configurable layout",
+ markdownContent:
+ "## Smith Chart JavaScript Chart\n\n### Overview\nThis example demonstrates how to create a high-performance chart with **Smith Chart** using SciChart.js in a JavaScript framework. The chart positions the x and y axes to cross at the data value (0,0), producing an oscilloscope-like layout. It leverages the advanced customization available in SciChart.js for axis placement, as detailed in the [Central Axis Layout documentation](https://www.scichart.com/documentation/js/v5/2d-charts/axis-api/multi-axis-and-layout/central-axis-layout/).\n\n### Technical Implementation\nThe implementation begins by initializing a `SciChartSurface` with an integrated WebAssembly context, following guidelines from the [Tutorial 01 - Including SciChart.js in an HTML Page using CDN](https://www.scichart.com/documentation/js/v5/get-started/tutorials-cdn/tutorial-01-using-cdn/) documentation. Both the x and y axes are configured as inner axes by enabling the `axis.isInnerAxis` property and aligned to the center by setting the `sciChartSurface.layoutManager` property equal to a `SmithChartLayoutManager` instance with data value based positioning. A dynamically generated butterfly curve is rendered using the `FastLineRenderableSeries` and utilizes a fade animation as provided by the [Animations API](https://www.scichart.com/documentation/js/v5/2d-charts/animations-api/animations-api-overview/) for performance and visual enhancement. Interaction is further enriched with modifiers such as `ZoomPanModifier`, `MouseWheelZoomModifier`, and `ZoomExtentsModifier`, which support smooth zooming and panning.\n\n### Features and Capabilities\nThis example showcases advanced chart capabilities such as real-time data rendering for complex curves and dynamic interactivity. The efficient use of WebAssembly ensures high performance even when visualizing large data sets. Additionally, the chart demonstrates clear separation of concerns by isolating initialization, axis configuration, data rendering, and user interaction, which allows for robust customization based on the application’s needs.\n\n### Integration and Best Practices\nIntegrating SciChart.js into a JavaScript application is streamlined by employing a modular approach where the chart initialization function is directly invoked with a designated root element. Resource cleanup is handled by returning a destructor function that calls the `delete()` method on the `SciChartSurface`, in line with best practices suggested in the [Memory Best Practices](https://www.scichart.com/documentation/js/v5/2d-charts/performance-tips/memory-best-practices/) documentation. Developers looking to extend or optimize their chart applications can also refer to the [Getting Started with SciChart JS](https://www.scichart.com/getting-started/scichart-javascript/) guide for additional insights on integration and performance optimization.",
+ },
+ react: {
+ subtitle:
+ "Demonstrates how to create a **React Chart with Smith Chart** using SciChart.js, High Performance JavaScript Charts",
+ title: "React Chart with Smith Chart",
+ pageTitle: "React Chart with Smith Chart",
+ metaDescription:
+ "Demonstrates Smith Chart on a React Chart using SciChart.js. SciChart supports unlimited left, right, top, bottom X, Y axis with configurable layout",
+ markdownContent:
+ "## React Chart with Smith Chart\n\n### Overview\nThis example demonstrates how to create a high performance React chart with Smith Chart using SciChart.js. The chart leverages a custom Smith Chart layout, showcasing how axes can be positioned in the center of the chart by setting the `axis.isInnerAxis` property and using the `SmithChartLayoutManager`.\n\n### Technical Implementation\nThe chart is initialized through the `` component by passing the drawExample function as a prop, a pattern that follows [best practices for React integration](https://www.scichart.com/blog/react-charts-with-scichart-js/). The drawExample function sets up the `SciChartSurface` and configures the Smith Chart by using the `SmithChartLayoutManager` with options that specify data value based positioning. `NumericAxis` instances are added with the `isInnerAxis` flag enabled to ensure that the axes are rendered inside the chart. For more detailed information on central axis customization, please refer to the [Central Axis Layout documentation](https://www.scichart.com/documentation/js/v5/2d-charts/axis-api/multi-axis-and-layout/central-axis-layout/).\n\n### Features and Capabilities\nThe example features an efficient data series generation that calculates a butterfly curve and displays it using `FastLineRenderableSeries` with a fade animation, as described in [The Animations API](https://www.scichart.com/documentation/js/v5/2d-charts/animations-api/animations-api-overview/). Interaction is enhanced by including several chart modifiers such as `ZoomPanModifier`, `MouseWheelZoomModifier`, and `ZoomExtentsModifier`, providing dynamic zoom and pan capabilities which can be explored further in the [ZoomPanModifier documentation](https://www.scichart.com/documentation/js/v5/2d-charts/chart-modifier-api/zooming-and-panning/zoom-pan-modifier/). Additionally, a `TextAnnotation` is added to explain the chart's functionality.\n\n### Integration and Best Practices\nThis React implementation follows a modular approach by using the `` component to encapsulate chart initialization, making it easier to integrate SciChart.js into larger React applications. The example illustrates proper use of inner axis configurations with `NumericAxis`, supporting efficient performance and clear visual presentation. Developers looking to extend the feature set or optimize performance can find further guidance in the [Numeric Axis documentation](https://www.scichart.com/documentation/js/v5/2d-charts/axis-api/axis-types/numeric-axis/) as well as the [React Charts with SciChart.js article](https://www.scichart.com/blog/react-charts-with-scichart-js/).",
+ },
+ angular: {
+ subtitle:
+ "Demonstrates how to create a **Angular Chart with Smith Chart** using SciChart.js, High Performance JavaScript Charts",
+ title: "Angular Chart with Smith Chart",
+ pageTitle: "Angular Chart with Smith Chart",
+ metaDescription:
+ "Demonstrates Smith Chart on a Angular Chart using SciChart.js. SciChart supports unlimited left, right, top, bottom X, Y axis with configurable layout",
+ markdownContent:
+ "## Angular Chart with Smith Chart Example\n\n### Overview\nThis Angular example demonstrates how to create a high-performance chart with **Smith Chart** using SciChart.js. The chart positions both axes in the center by using a custom central axis layout and inner axis configuration. It leverages the [scichart-angular](https://www.npmjs.com/package/scichart-angular) package, which simplifies integration with Angular projects using the `ScichartAngularComponent`.\n\n### Technical Implementation\nThe implementation initializes a `SciChartSurface` using the Angular standalone component, which passes the chart setup function through the `[initChart]` property. The chart employs the `SmithChartLayoutManager` with options set to position the axes based on data values, ensuring that the axes cross at (0,0). Both the x and y axes are defined as inner axes by setting the `axis.isInnerAxis` property, as detailed in the [Central Axis Layout documentation](https://www.scichart.com/documentation/js/v5/2d-charts/axis-api/multi-axis-and-layout/central-axis-layout/). A `FastLineRenderableSeries` is used to render a dynamically generated butterfly curve, with a fade animation enhancing performance. Additional interactivity is provided through the `ZoomPanModifier`, `MouseWheelZoomModifier`, and `ZoomExtentsModifier`, which offer smooth zooming and panning as described in the [Tutorial 03 - Adding Zooming, Panning Behavior](https://www.scichart.com/documentation/js/v5/get-started/tutorials-js-npm-webpack/tutorial-03-adding-zooming-panning-behavior/).\n\n### Features and Capabilities\nThis example highlights advanced chart capabilities such as real-time updates, dynamic data rendering, and a unique oscilloscope style layout. The efficient rendering of complex data series, such as the butterfly curve, is optimized by the use of `FastLineRenderableSeries` and `FadeAnimation`, supporting high performance even with large data sets. For insights into performance optimization, developers can refer to the techniques discussed in [Performance Optimisation of JavaScript Applications & Charts](https://www.scichart.com/blog/performance-optimisation-of-javascript-applications-charts/).\n\n### Integration and Best Practices\nFollowing Angular best practices, the example uses a standalone component to encapsulate chart initialization, which promotes modularity and ease of management within larger Angular applications. Developers are encouraged to consult the [Getting Started with SciChart JS](https://www.scichart.com/getting-started/scichart-javascript/) guide for further details on Angular application integration techniques. This example provides a robust reference for implementing complex axis layouts, interactive modifiers, and performance optimizations in Angular environments.",
+ },
+ },
+ documentationLinks: [
+ {
+ href: "https://www.scichart.com/documentation/js/v5/2d-charts/axis-api/multi-axis-and-layout/central-axis-layout/",
+ title: "SciChart.js Central Axis Documentation page",
+ linkTitle: "Central Axis documentation",
+ },
+ ],
+ path: "smith-chart",
+ metaKeywords: "multiple, axis, chart, javascript, webgl, canvas",
+ onWebsite: true,
+ filepath: "Charts2D/ModifyAxisBehavior/SmithChart",
+ thumbnailImage: "smith-chart.jpg",
+ sandboxConfig: {},
+ markdownContent: null,
+ pageLayout: "default",
+ extraDependencies: {},
+ isNew: false,
+ };
+//// End of computer generated metadata
+
+export const SmithChartExampleInfo = createExampleInfo(metaData);
+export default SmithChartExampleInfo;
diff --git a/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/index.tsx b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/index.tsx
new file mode 100644
index 000000000..aa8d648b1
--- /dev/null
+++ b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/index.tsx
@@ -0,0 +1,11 @@
+import * as React from "react";
+import { appTheme } from "../../../theme";
+import { SciChartReact } from "scichart-react";
+import commonClasses from "../../../styles/Examples.module.scss";
+import { drawExample } from "./drawExample";
+
+// React component needed as our examples app is react.
+// SciChart can be used in Angular, Vue, Blazor and vanilla JS! See our Github repo for more info
+export default function ChartComponent() {
+ return ;
+}
diff --git a/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/smith-chart.jpg b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/smith-chart.jpg
new file mode 100644
index 000000000..351db0f9e
Binary files /dev/null and b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/smith-chart.jpg differ
diff --git a/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/vanilla.ts b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/vanilla.ts
new file mode 100644
index 000000000..4f87ed08b
--- /dev/null
+++ b/Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SmithChart/vanilla.ts
@@ -0,0 +1,19 @@
+import { drawExample } from "./drawExample";
+
+/**
+ * Creates charts on the provided root elements
+ * @returns cleanup function
+ */
+const create = async () => {
+ const { sciChartSurface } = await drawExample("chart");
+
+ const destructor = () => {
+ sciChartSurface.delete();
+ };
+
+ return destructor;
+};
+
+create();
+
+// call the `destructor` returned by the `create` promise to dispose the charts when necessary