Skip to content

Commit 5a2954a

Browse files
committed
Update LCJS version
1 parent d15b783 commit 5a2954a

File tree

6 files changed

+379
-1
lines changed

6 files changed

+379
-1
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
dist
3+
package-lock.json

README.md

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,76 @@
1-
# lcjs-example-0805-spectrogramProjection
1+
# JavaScript Spectrogram XY-Projection Chart
2+
3+
![JavaScript Spectrogram XY-Projection Chart](spectrogramProjection.png)
4+
5+
This demo application belongs to the set of examples for LightningChart JS, data visualization library for JavaScript.
6+
7+
LightningChart JS is entirely GPU accelerated and performance optimized charting library for presenting massive amounts of data. It offers an easy way of creating sophisticated and interactive charts and adding them to your website or web application.
8+
9+
The demo can be used as an example or a seed project. Local execution requires the following steps:
10+
11+
- Make sure that relevant version of [Node.js](https://nodejs.org/en/download/) is installed
12+
- Open the project folder in a terminal:
13+
14+
npm install # fetches dependencies
15+
npm start # builds an application and starts the development server
16+
17+
- The application is available at *http://localhost:8080* in your browser, webpack-dev-server provides hot reload functionality.
18+
19+
20+
## Description
21+
22+
This example shows how to create a 2D spectrogram chart with X and Y line projections over last mouse coordinate (custom interaction).
23+
24+
Every time the user moves mouse over the spectrogram 1024 + 1024 data points are picked from the data set and pushed to X and Y projections line series - this is an expensive operation, but handled really fast with calls to `LineSeries.clear().add(data)`.
25+
26+
The spectrogram chart contains 1024 x 1024 = ~1 million data points.
27+
28+
29+
## API Links
30+
31+
* [Dashboard]
32+
* [XY cartesian chart]
33+
* [Heatmap Grid Series Intensity]
34+
* [Line Series]
35+
* [Axis scroll strategies]
36+
* [Paletted Fill]
37+
* [LUT]
38+
* [Empty line style]
39+
* [Legend Box]
40+
* [Legend Box builders]
41+
* [Translate point]
42+
43+
44+
## Support
45+
46+
If you notice an error in the example code, please open an issue on [GitHub][0] repository of the entire example.
47+
48+
Official [API documentation][1] can be found on [Arction][2] website.
49+
50+
If the docs and other materials do not solve your problem as well as implementation help is needed, ask on [StackOverflow][3] (tagged lightningchart).
51+
52+
If you think you found a bug in the LightningChart JavaScript library, please contact support@arction.com.
53+
54+
Direct developer email support can be purchased through a [Support Plan][4] or by contacting sales@arction.com.
55+
56+
[0]: https://github.com/Arction/
57+
[1]: https://www.arction.com/lightningchart-js-api-documentation/
58+
[2]: https://www.arction.com
59+
[3]: https://stackoverflow.com/questions/tagged/lightningchart
60+
[4]: https://www.arction.com/support-services/
61+
62+
© Arction Ltd 2009-2020. All rights reserved.
63+
64+
65+
[Dashboard]: https://www.arction.com/lightningchart-js-api-documentation/v3.1.0/classes/dashboard.html
66+
[XY cartesian chart]: https://www.arction.com/lightningchart-js-api-documentation/v3.1.0/classes/chartxy.html
67+
[Heatmap Grid Series Intensity]: https://www.arction.com/lightningchart-js-api-documentation/v3.1.0/
68+
[Line Series]: https://www.arction.com/lightningchart-js-api-documentation/v3.1.0/classes/lineseries.html
69+
[Axis scroll strategies]: https://www.arction.com/lightningchart-js-api-documentation/v3.1.0/globals.html#axisscrollstrategies
70+
[Paletted Fill]: https://www.arction.com/lightningchart-js-api-documentation/v3.1.0/classes/palettedfill.html
71+
[LUT]: https://www.arction.com/lightningchart-js-api-documentation/v3.1.0/classes/lut.html
72+
[Empty line style]: https://www.arction.com/lightningchart-js-api-documentation/v3.1.0/globals.html#emptyline
73+
[Legend Box]: https://www.arction.com/lightningchart-js-api-documentation/v3.1.0/classes/chartxy.html#addlegendbox
74+
[Legend Box builders]: https://www.arction.com/lightningchart-js-api-documentation/v3.1.0/globals.html#legendboxbuilders
75+
[Translate point]: https://www.arction.com/lightningchart-js-api-documentation/v3.1.0/globals.html#translatepoint
276

package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"version": "1.0.1",
3+
"scripts": {
4+
"build": "webpack --mode production",
5+
"start": "webpack-dev-server"
6+
},
7+
"license": "Custom",
8+
"private": true,
9+
"main": "./src/index.js",
10+
"devDependencies": {
11+
"copy-webpack-plugin": "^6.0.2",
12+
"html-webpack-plugin": "^3.2.0",
13+
"webpack-cli": "^3.3.10",
14+
"webpack-dev-server": "^3.9.0"
15+
},
16+
"dependencies": {
17+
"@arction/lcjs": "^3.1.0",
18+
"@arction/xydata": "^1.4.0",
19+
"clean-webpack-plugin": "^3.0.0",
20+
"webpack": "^4.41.2",
21+
"webpack-stream": "^5.2.1"
22+
}
23+
}

spectrogramProjection.png

956 KB
Loading

src/index.js

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/*
2+
* LightningChartJS example for Chart with 2D spectrogram + dynamic projections on mouse interaction.
3+
*/
4+
// Import LightningChartJS
5+
const lcjs = require("@arction/lcjs");
6+
7+
// Extract required parts from LightningChartJS.
8+
const {
9+
lightningChart,
10+
PalettedFill,
11+
LUT,
12+
emptyFill,
13+
emptyLine,
14+
AxisScrollStrategies,
15+
LegendBoxBuilders,
16+
ColorHSV,
17+
translatePoint,
18+
Themes,
19+
} = lcjs;
20+
21+
const { createSpectrumDataGenerator } = require("@arction/xydata");
22+
23+
const spectrogramColumns = 1024;
24+
const spectrogramRows = 1024;
25+
26+
// Create charts and series.
27+
28+
const dashboard = lightningChart()
29+
.Dashboard({
30+
// theme: Themes.darkGold,
31+
numberOfColumns: 2,
32+
numberOfRows: 2,
33+
disableAnimations: true,
34+
})
35+
.setColumnWidth(0, 1)
36+
.setColumnWidth(1, 0.2)
37+
.setRowHeight(0, 1)
38+
.setRowHeight(1, 0.3);
39+
40+
const chartSpectrogram = dashboard
41+
.createChartXY({
42+
columnIndex: 0,
43+
rowIndex: 0,
44+
})
45+
.setTitle("2D Spectrogram with X & Y projection on mouse hover");
46+
47+
const seriesSpectrogram = chartSpectrogram
48+
.addHeatmapGridSeries({
49+
columns: spectrogramColumns,
50+
rows: spectrogramRows,
51+
})
52+
.setMouseInteractions(false)
53+
.setWireframeStyle(emptyLine)
54+
.setFillStyle(
55+
new PalettedFill({
56+
lookUpProperty: "value",
57+
lut: new LUT({
58+
interpolate: true,
59+
steps: [
60+
{ value: 0, label: "0.0", color: ColorHSV(0, 1, 0) },
61+
{ value: 0.2, label: "0.2", color: ColorHSV(270, 0.84, 0.2) },
62+
{ value: 0.4, label: "0.4", color: ColorHSV(289, 0.86, 0.35) },
63+
{ value: 0.6, label: "0.6", color: ColorHSV(324, 0.97, 0.56) },
64+
{ value: 0.8, label: "0.8", color: ColorHSV(1, 1, 1) },
65+
{ value: 1.0, label: "1.0", color: ColorHSV(44, 0.64, 1) },
66+
],
67+
}),
68+
})
69+
);
70+
71+
const legend = chartSpectrogram
72+
.addLegendBox(LegendBoxBuilders.HorizontalLegendBox)
73+
// Dispose example UI elements automatically if they take too much space. This is to avoid bad UI on mobile / etc. devices.
74+
.setAutoDispose({
75+
type: 'max-width',
76+
maxWidth: 0.80,
77+
})
78+
.add(chartSpectrogram);
79+
80+
const chartProjectionY = dashboard
81+
.createChartXY({
82+
columnIndex: 1,
83+
rowIndex: 0,
84+
})
85+
.setTitleFillStyle(emptyFill)
86+
// NOTE: Hardcoded alignment with Spectrogram chart.
87+
.setPadding({ top: 44 })
88+
.setMouseInteractions(false);
89+
90+
chartProjectionY
91+
.getDefaultAxisY()
92+
.setScrollStrategy(undefined)
93+
.setMouseInteractions(false);
94+
// Sync projection Axis with spectogram chart projected axis.
95+
chartSpectrogram
96+
.getDefaultAxisY()
97+
.onScaleChange((start, end) =>
98+
chartProjectionY.getDefaultAxisY().setInterval(start, end, false, true)
99+
);
100+
chartProjectionY
101+
.getDefaultAxisX()
102+
.setScrollStrategy(AxisScrollStrategies.expansion)
103+
.setInterval(0, 1)
104+
.setMouseInteractions(false);
105+
106+
const seriesProjectionY = chartProjectionY
107+
.addLineSeries({
108+
dataPattern: {
109+
pattern: "ProgressiveY",
110+
regularProgressiveStep: true,
111+
},
112+
})
113+
.setName("Projection (Y)")
114+
.setCursorSolveBasis("nearest-y");
115+
116+
const chartProjectionX = dashboard
117+
.createChartXY({
118+
columnIndex: 0,
119+
rowIndex: 1,
120+
})
121+
.setTitleFillStyle(emptyFill)
122+
.setMouseInteractions(false);
123+
chartProjectionX
124+
.getDefaultAxisX()
125+
.setScrollStrategy(undefined)
126+
.setMouseInteractions(false);
127+
// Sync projection Axis with spectogram chart projected axis.
128+
chartSpectrogram
129+
.getDefaultAxisX()
130+
.onScaleChange((start, end) =>
131+
chartProjectionX.getDefaultAxisX().setInterval(start, end, false, true)
132+
);
133+
chartProjectionX
134+
.getDefaultAxisY()
135+
.setScrollStrategy(AxisScrollStrategies.expansion)
136+
.setInterval(0, 1)
137+
.setMouseInteractions(false);
138+
const seriesProjectionX = chartProjectionX
139+
.addLineSeries({
140+
dataPattern: {
141+
pattern: "ProgressiveX",
142+
regularProgressiveStep: true,
143+
},
144+
})
145+
.setName("Projection (X)");
146+
147+
// Generate data.
148+
createSpectrumDataGenerator()
149+
.setNumberOfSamples(spectrogramColumns)
150+
.setSampleSize(spectrogramRows)
151+
.generate()
152+
.toPromise()
153+
.then((data) => {
154+
seriesSpectrogram.invalidateIntensityValues(data);
155+
156+
console.log(seriesSpectrogram);
157+
// Add custom interaction when mouse is hovered over spectrogram chart.
158+
chartSpectrogram.onSeriesBackgroundMouseMove((_, event) => {
159+
// Solve mouse location on Axis.
160+
const locationAxis = translatePoint(
161+
chartSpectrogram.engine.clientLocation2Engine(
162+
event.clientX,
163+
event.clientY
164+
),
165+
chartSpectrogram.engine.scale,
166+
seriesSpectrogram.scale
167+
);
168+
169+
// Calculate spectrogram 1D projections at axis location for both X and Y planes.
170+
let projectionY;
171+
try {
172+
projectionY = data[Math.round(locationAxis.x)].map((value, i) => ({
173+
x: value,
174+
y: i,
175+
}));
176+
} catch (e) {}
177+
178+
let projectionX;
179+
try {
180+
projectionX = [];
181+
const row = Math.round(locationAxis.y);
182+
for (let x = 0; x < spectrogramColumns; x += 1) {
183+
projectionX[x] = {
184+
x,
185+
y: data[x][row],
186+
};
187+
}
188+
} catch (e) {}
189+
190+
// Update projection series data.
191+
seriesProjectionY.clear();
192+
if (projectionY) {
193+
seriesProjectionY.add(projectionY);
194+
}
195+
196+
seriesProjectionX.clear();
197+
if (projectionX) {
198+
seriesProjectionX.add(projectionX);
199+
}
200+
});
201+
});

webpack.config.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
const HtmlWebpackPlugin = require('html-webpack-plugin')
2+
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
3+
const CopyWebpackPlugin = require('copy-webpack-plugin')
4+
const path = require('path')
5+
6+
const targetFolderName = 'dist'
7+
const outputPath = path.resolve(__dirname, targetFolderName)
8+
const packageJSON = require('./package.json')
9+
10+
11+
module.exports = {
12+
mode: 'development',
13+
entry: {
14+
app: packageJSON.main
15+
},
16+
node: {
17+
buffer: false,
18+
setImmediate: false
19+
},
20+
devServer: {
21+
contentBase: outputPath,
22+
compress: true,
23+
// handle asset renaming
24+
before: function(app, server, compiler){
25+
app.get('/examples/assets/*', (req, res, next)=>{
26+
if(req.originalUrl.match(/lcjs_example_\d*_\w*-/g)){
27+
res.redirect(req.originalUrl.replace(/lcjs_example_\d*_\w*-/g,''))
28+
}
29+
else{
30+
next()
31+
}
32+
})
33+
}
34+
},
35+
resolve: {
36+
modules: [
37+
path.resolve('./src'),
38+
path.resolve('./node_modules')
39+
],
40+
extensions: ['.js']
41+
},
42+
output: {
43+
filename: 'js/[name].[contenthash].bundle.js',
44+
chunkFilename: 'js/[name].[contenthash].bundle.js',
45+
path: outputPath
46+
},
47+
optimization: {
48+
splitChunks: {
49+
chunks: 'all',
50+
cacheGroups: {
51+
// make separate 'vendor' chunk that contains any depenedencies
52+
// allows for smaller file sizes and faster builds
53+
vendor: {
54+
test: /node_modules/,
55+
chunks: 'initial',
56+
name: 'vendor',
57+
priority: 10,
58+
enforce: true
59+
}
60+
}
61+
},
62+
runtimeChunk: 'single'
63+
},
64+
plugins: [
65+
new CleanWebpackPlugin(),
66+
new HtmlWebpackPlugin({
67+
title: "app",
68+
filename: path.resolve(__dirname, 'dist', 'index.html')
69+
}),
70+
new CopyWebpackPlugin({
71+
patterns: [
72+
{ from: './assets/**/*', to: './examples/assets', flatten: true, noErrorOnMissing: true },
73+
{ from: './node_modules/@arction/lcjs/dist/resources', to: 'resources', noErrorOnMissing: true },
74+
]
75+
})
76+
]
77+
}

0 commit comments

Comments
 (0)