Creates a Custom Texture example with multiple renderableSeries, all allowing for customTextureOptions images.
drawExample.ts
index.html
vanilla.ts
theme.ts
1import {
2 NumberRange,
3 SciChartSurface,
4 NumericAxis,
5 ZoomPanModifier,
6 ZoomExtentsModifier,
7 MouseWheelZoomModifier,
8 FastTriangleRenderableSeries,
9 ETriangleSeriesDrawMode,
10 XyxyDataSeries,
11 ICustomTextureOptions,
12 FastRectangleRenderableSeries,
13 EColumnMode,
14 EColumnYMode,
15 createImageAsync,
16 FastBandRenderableSeries,
17 XyyDataSeries,
18 ELineDrawMode,
19 SplineMountainRenderableSeries,
20 XyDataSeries,
21} from "scichart";
22
23import { appTheme } from "../../../theme";
24
25import scichartImg from "./scichart.jpg";
26import mountain from "./mountain.jpg";
27import cloud from "./cloud.jpg";
28import buildings from "./buildings.jpg";
29import moon from "./moon.jpg";
30
31let textureRepeat = false;
32
33export class ImageTextureOptions implements ICustomTextureOptions {
34 isPerPrimitive?: boolean = false;
35 options: { image: HTMLImageElement; textureWidth?: number; textureHeight?: number; repeat?: boolean };
36 textureHeight: number = 800;
37 textureWidth: number = 600;
38 repeat = false;
39
40 public constructor(options: {
41 image: HTMLImageElement;
42 textureWidth?: number;
43 textureHeight?: number;
44 repeat?: boolean;
45 }) {
46 this.options = options;
47 this.textureHeight = options.textureHeight;
48 this.textureWidth = options.textureWidth;
49 this.repeat = options.repeat;
50 }
51
52 public createTexture(context: CanvasRenderingContext2D) {
53 context.drawImage(this.options.image, 0, 0);
54 }
55}
56
57export const drawExample = async (rootElement: string | HTMLDivElement) => {
58 // Create a SciChartSurface
59 const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
60 theme: appTheme.SciChartJsTheme,
61 });
62
63 const growBy = new NumberRange(0.01, 0.01);
64
65 sciChartSurface.xAxes.add(new NumericAxis(wasmContext, { growBy }));
66 sciChartSurface.yAxes.add(new NumericAxis(wasmContext, { growBy }));
67
68 const scichartBitmap = await createImageAsync(scichartImg);
69 const mountainBitmap = await createImageAsync(mountain);
70 const cloudBitmap = await createImageAsync(cloud);
71 const buildingsBitmap = await createImageAsync(buildings);
72 const moonBitmap = await createImageAsync(moon);
73
74 // triangles
75 const polygonSeries = new FastTriangleRenderableSeries(wasmContext, {
76 isDigitalLine: false,
77 fill: "cornflowerblue",
78 drawMode: ETriangleSeriesDrawMode.Strip,
79 polygonVertices: 6, // Sets the number of vertices per polygon. Applies only for drawMode ETriangleSeriesDrawMode.Polygon
80 customTextureOptions: new ImageTextureOptions({
81 image: scichartBitmap,
82 textureWidth: 600,
83 textureHeight: 324,
84 repeat: textureRepeat,
85 }),
86 opacity: 0.5,
87 });
88
89 const dataSeries = new XyxyDataSeries(wasmContext);
90
91 let myData: number[][] = [];
92
93 function generateRectangle(minX: number, maxX: number, minY: number, maxY: number) {
94 const midX = (minX + maxX) / 2;
95 const midY = (minY + maxY) / 2;
96
97 [
98 [midX, midY, 0.5, 0.5], // Center point
99 [minX, minY, 0, 1], // Bottom-left
100 [maxX, minY, 1, 1], // Bottom-right
101 [maxX, maxY, 1, 0], // Top-right
102 [minX, maxY, 0, 0], // Top-left
103 [minX, minY, 0, 1], // Bottom-left (duplicate)
104 ].forEach((d) => {
105 myData.push([d[0], d[1], d[2], d[3]]);
106 dataSeries.append(d[0], d[1], d[2], d[3]);
107 });
108 }
109
110 console.log(myData);
111
112 generateRectangle(500, 950, 150, 400);
113
114 polygonSeries.dataSeries = dataSeries;
115
116 // rectangless
117
118 const xValues = [0, 110, 220, 330];
119 const yValues = [20, 0, 20, 0];
120 const x1Values = [100, 210, 320, 430];
121 const y1Values = [320, 300, 320, 300];
122
123 const rectangleSeries = new FastRectangleRenderableSeries(wasmContext, {
124 dataSeries: new XyxyDataSeries(wasmContext, {
125 xValues,
126 yValues,
127 x1Values,
128 y1Values,
129 }),
130 columnXMode: EColumnMode.StartEnd, // x, x1
131 columnYMode: EColumnYMode.TopBottom, // y, y1
132 stroke: "black",
133 strokeThickness: 2,
134 customTextureOptions: new ImageTextureOptions({
135 image: buildingsBitmap,
136 textureWidth: 640,
137 textureHeight: 480,
138 repeat: textureRepeat,
139 }),
140 opacity: 1,
141 });
142
143 // band
144 const dataSeriesB = new XyyDataSeries(wasmContext);
145 const POINTSB = 1000;
146 const STEPB = (3 * Math.PI) / POINTSB;
147 for (let i = 0; i <= 1000; i++) {
148 const k = 1 - i / 2000;
149 let y = Math.sin(i * STEPB) * k * 0.7;
150 const y1 = Math.cos(i * STEPB) * k;
151 if (i >= 200 && i <= 300) {
152 y = NaN;
153 }
154 dataSeriesB.append(i, y * 100 + 500, y1 * 100 + 500);
155 }
156 const bandSeries = new FastBandRenderableSeries(wasmContext, {
157 dataSeries: dataSeriesB,
158 strokeThickness: 2,
159 drawNaNAs: ELineDrawMode.PolyLine,
160 customTextureOptions: new ImageTextureOptions({
161 image: cloudBitmap,
162 textureWidth: 640,
163 textureHeight: 480,
164 repeat: textureRepeat,
165 }),
166 });
167
168 // mountain
169
170 const mountainSeries = new SplineMountainRenderableSeries(wasmContext, {
171 stroke: "black",
172 strokeThickness: 2,
173 zeroLineY: 0.0,
174 fill: "rgba(176, 196, 222, 0.7)",
175 interpolationPoints: 5,
176 customTextureOptions: new ImageTextureOptions({
177 image: mountainBitmap,
178 textureWidth: 400,
179 textureHeight: 300,
180 repeat: textureRepeat,
181 }),
182 // pointMarker: new EllipsePointMarker(wasmContext),
183 });
184
185 const dataSeriesM = new XyDataSeries(wasmContext);
186 const POINTS = 10;
187 const STEP = (3 * Math.PI) / POINTS;
188 for (let i = 0; i <= POINTS; i++) {
189 const y = Math.abs(Math.sin(i * STEP)) * 100;
190 dataSeriesM.append(i * 100, y);
191 }
192 mountainSeries.dataSeries = dataSeriesM;
193
194 // triangle
195
196 const sXValues = [100, 100, 300, 300, 300, 100];
197 const sYValues = [500, 350, 350, 370, 520, 520];
198
199 const triangkeSeries = new FastTriangleRenderableSeries(wasmContext, {
200 dataSeries: new XyDataSeries(wasmContext, {
201 xValues: sXValues,
202 yValues: sYValues,
203 }),
204 drawMode: ETriangleSeriesDrawMode.List,
205 customTextureOptions: new ImageTextureOptions({
206 image: moonBitmap,
207 textureWidth: 800,
208 textureHeight: 600,
209 repeat: textureRepeat,
210 }),
211 });
212
213 sciChartSurface.renderableSeries.add(polygonSeries, triangkeSeries, rectangleSeries, bandSeries, mountainSeries);
214
215 sciChartSurface.chartModifiers.add(new ZoomPanModifier());
216 sciChartSurface.chartModifiers.add(new ZoomExtentsModifier());
217 sciChartSurface.chartModifiers.add(new MouseWheelZoomModifier());
218
219 return { sciChartSurface, wasmContext };
220};
221This example demonstrates how to apply custom textures to various series types in SciChart.js using JavaScript. It showcases texture mapping on FastTriangleRenderableSeries, FastRectangleRenderableSeries, FastBandRenderableSeries, and SplineMountainRenderableSeries with different image sources.
The implementation uses the ImageTextureOptions interface to define custom textures for each series. Images are loaded asynchronously using createImageAsync and applied via the customTextureOptions property. The example utilizes XyxyDataSeries for triangle series and XyyDataSeries for band series.
The example highlights texture mapping capabilities with different draw modes (ETriangleSeriesDrawMode) and series types. It demonstrates texture repetition control and opacity adjustments for layered visual effects.
The chart surface is initialized asynchronously with proper cleanup handling. Developers can extend this pattern for dynamic texture updates and performance optimization in data-intensive applications.