mdas-jsview-sdk 1.0.10-uat.0 → 1.0.12-uat.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mdas-sdk.esm.js +328 -82
- package/dist/mdas-sdk.esm.js.map +1 -1
- package/dist/mdas-sdk.js +328 -82
- package/dist/mdas-sdk.js.map +1 -1
- package/dist/mdas-sdk.min.js +9 -9
- package/dist/mdas-sdk.min.js.map +1 -1
- package/package.json +1 -1
package/dist/mdas-sdk.esm.js
CHANGED
|
@@ -1199,13 +1199,12 @@ const NightSessionTemplate = `
|
|
|
1199
1199
|
<div class="company-market-info">
|
|
1200
1200
|
<span class="night-company-name"></span>
|
|
1201
1201
|
<span class="market-name"></span>
|
|
1202
|
-
<span class="market-mic"></span>
|
|
1203
1202
|
</div>
|
|
1204
1203
|
<h1 class="symbol editable-symbol"
|
|
1205
1204
|
title="Double-click to edit symbol"
|
|
1206
1205
|
data-original-symbol="">
|
|
1207
1206
|
</h1>
|
|
1208
|
-
|
|
1207
|
+
|
|
1209
1208
|
</div>
|
|
1210
1209
|
<div class="price-section">
|
|
1211
1210
|
<div class="current-price"></div>
|
|
@@ -4415,13 +4414,6 @@ class NightSessionWidget extends BaseWidget {
|
|
|
4415
4414
|
marketNameElement.textContent = this.exchangeName || data.exchangeName || '';
|
|
4416
4415
|
}
|
|
4417
4416
|
|
|
4418
|
-
// Update MIC (Market Identifier Code)
|
|
4419
|
-
const marketMicElement = this.container.querySelector('.market-mic');
|
|
4420
|
-
if (marketMicElement) {
|
|
4421
|
-
const micValue = this.mic || data.mic || '';
|
|
4422
|
-
marketMicElement.textContent = micValue;
|
|
4423
|
-
}
|
|
4424
|
-
|
|
4425
4417
|
// Update price
|
|
4426
4418
|
const currentPriceElement = this.container.querySelector('.current-price');
|
|
4427
4419
|
if (currentPriceElement) {
|
|
@@ -37500,6 +37492,10 @@ class IntradayChartWidget extends BaseWidget {
|
|
|
37500
37492
|
|
|
37501
37493
|
// Symbol editor
|
|
37502
37494
|
this.symbolEditor = null;
|
|
37495
|
+
|
|
37496
|
+
// Lazy loading cache for 5D data
|
|
37497
|
+
this.cached5DData = null;
|
|
37498
|
+
this.is5DDataLoading = false;
|
|
37503
37499
|
this.createWidgetStructure();
|
|
37504
37500
|
this.setupSymbolEditor();
|
|
37505
37501
|
this.initialize();
|
|
@@ -37601,6 +37597,10 @@ class IntradayChartWidget extends BaseWidget {
|
|
|
37601
37597
|
this.chartData = null;
|
|
37602
37598
|
this.livePrice = null;
|
|
37603
37599
|
|
|
37600
|
+
// Clear cached 5D data for old symbol
|
|
37601
|
+
this.cached5DData = null;
|
|
37602
|
+
this.is5DDataLoading = false;
|
|
37603
|
+
|
|
37604
37604
|
// Update internal symbol
|
|
37605
37605
|
this.symbol = upperSymbol;
|
|
37606
37606
|
|
|
@@ -37751,7 +37751,13 @@ class IntradayChartWidget extends BaseWidget {
|
|
|
37751
37751
|
throw new Error('API service not available');
|
|
37752
37752
|
}
|
|
37753
37753
|
|
|
37754
|
-
//
|
|
37754
|
+
// For 5D chart: Load data from multiple days (rangeback 0-5)
|
|
37755
|
+
if (this.rangeBack === 5) {
|
|
37756
|
+
await this.load5DayChartData(apiService);
|
|
37757
|
+
return;
|
|
37758
|
+
}
|
|
37759
|
+
|
|
37760
|
+
// FALLBACK LOGIC: Try to find most recent available data (for 1D)
|
|
37755
37761
|
const MAX_LOOKBACK_DAYS = 7;
|
|
37756
37762
|
let attemptRangeBack = this.rangeBack;
|
|
37757
37763
|
let dataFound = false;
|
|
@@ -37840,6 +37846,9 @@ class IntradayChartWidget extends BaseWidget {
|
|
|
37840
37846
|
await this.startAutoRefresh();
|
|
37841
37847
|
// Subscribe to live price updates
|
|
37842
37848
|
this.subscribeToLivePrice();
|
|
37849
|
+
|
|
37850
|
+
// LAZY LOADING: Preload 5D data in the background after 1D loads
|
|
37851
|
+
this.preload5DDataInBackground();
|
|
37843
37852
|
} else {
|
|
37844
37853
|
// Historical data or fallback - don't refresh
|
|
37845
37854
|
this.stopAutoRefresh();
|
|
@@ -37867,6 +37876,159 @@ class IntradayChartWidget extends BaseWidget {
|
|
|
37867
37876
|
this.showError(errorMessage);
|
|
37868
37877
|
}
|
|
37869
37878
|
}
|
|
37879
|
+
async load5DayChartData(apiService) {
|
|
37880
|
+
try {
|
|
37881
|
+
// Check if we have cached 5D data
|
|
37882
|
+
if (this.cached5DData) {
|
|
37883
|
+
if (this.debug) {
|
|
37884
|
+
console.log('[IntradayChartWidget] Using cached 5D data');
|
|
37885
|
+
}
|
|
37886
|
+
|
|
37887
|
+
// Use cached data
|
|
37888
|
+
this.chartData = this.cached5DData;
|
|
37889
|
+
this.renderChart();
|
|
37890
|
+
this.updateStats();
|
|
37891
|
+
this.hideLoading();
|
|
37892
|
+
|
|
37893
|
+
// Don't auto-refresh for 5D chart
|
|
37894
|
+
this.stopAutoRefresh();
|
|
37895
|
+
return;
|
|
37896
|
+
}
|
|
37897
|
+
|
|
37898
|
+
// No cached data, load it now
|
|
37899
|
+
const combinedData = await this.fetch5DayData(apiService);
|
|
37900
|
+
|
|
37901
|
+
// Process the combined data
|
|
37902
|
+
this.chartData = new IntradayChartModel(combinedData);
|
|
37903
|
+
if (this.chartData.dataPoints.length === 0) {
|
|
37904
|
+
throw new Error(`No valid data points for ${this.symbol}`);
|
|
37905
|
+
}
|
|
37906
|
+
|
|
37907
|
+
// Cache the processed data
|
|
37908
|
+
this.cached5DData = this.chartData;
|
|
37909
|
+
this.renderChart();
|
|
37910
|
+
this.updateStats();
|
|
37911
|
+
this.hideLoading();
|
|
37912
|
+
if (this.debug) {
|
|
37913
|
+
console.log(`[IntradayChartWidget] 5D chart loaded with ${this.chartData.dataPoints.length} data points`);
|
|
37914
|
+
}
|
|
37915
|
+
|
|
37916
|
+
// Don't auto-refresh for 5D chart
|
|
37917
|
+
this.stopAutoRefresh();
|
|
37918
|
+
} catch (error) {
|
|
37919
|
+
console.error('[IntradayChartWidget] Error loading 5D chart data:', error);
|
|
37920
|
+
throw error; // Re-throw to be caught by parent loadChartData
|
|
37921
|
+
}
|
|
37922
|
+
}
|
|
37923
|
+
async fetch5DayData(apiService) {
|
|
37924
|
+
const DAYS_TO_COLLECT = 5;
|
|
37925
|
+
const MAX_RANGEBACK_ATTEMPTS = 7; // API limit: maximum 7 rangeback
|
|
37926
|
+
|
|
37927
|
+
if (this.debug) {
|
|
37928
|
+
console.log('[IntradayChartWidget] Fetching 5D chart data with parallel requests (API limit: rangeback 0-6)');
|
|
37929
|
+
}
|
|
37930
|
+
|
|
37931
|
+
// OPTIMIZATION: Query all rangeback values in parallel (0-6)
|
|
37932
|
+
const rangebackPromises = [];
|
|
37933
|
+
for (let rb = 0; rb < MAX_RANGEBACK_ATTEMPTS; rb++) {
|
|
37934
|
+
rangebackPromises.push(apiService.getIntradayChart(this.source, this.symbol, rb).then(response => {
|
|
37935
|
+
// Extract data array from response
|
|
37936
|
+
let dataArray = response;
|
|
37937
|
+
if (response && response.data && Array.isArray(response.data)) {
|
|
37938
|
+
dataArray = response.data;
|
|
37939
|
+
}
|
|
37940
|
+
return {
|
|
37941
|
+
rangeBack: rb,
|
|
37942
|
+
data: dataArray
|
|
37943
|
+
};
|
|
37944
|
+
}).catch(error => {
|
|
37945
|
+
// If a request fails, return null so we can filter it out
|
|
37946
|
+
if (this.debug) {
|
|
37947
|
+
console.warn(`[IntradayChartWidget] Request failed for rangeback ${rb}:`, error);
|
|
37948
|
+
}
|
|
37949
|
+
return {
|
|
37950
|
+
rangeBack: rb,
|
|
37951
|
+
data: null
|
|
37952
|
+
};
|
|
37953
|
+
}));
|
|
37954
|
+
}
|
|
37955
|
+
|
|
37956
|
+
// Wait for all parallel requests to complete
|
|
37957
|
+
const results = await Promise.all(rangebackPromises);
|
|
37958
|
+
if (this.debug) {
|
|
37959
|
+
console.log('[IntradayChartWidget] All parallel requests completed');
|
|
37960
|
+
}
|
|
37961
|
+
|
|
37962
|
+
// Filter out empty/null responses and collect valid days
|
|
37963
|
+
const collectedDays = results.filter(result => {
|
|
37964
|
+
const isValid = result.data && Array.isArray(result.data) && result.data.length > 0;
|
|
37965
|
+
if (this.debug) {
|
|
37966
|
+
if (isValid) {
|
|
37967
|
+
console.log(`[IntradayChartWidget] Rangeback ${result.rangeBack}: ${result.data.length} data points`);
|
|
37968
|
+
} else {
|
|
37969
|
+
console.log(`[IntradayChartWidget] Rangeback ${result.rangeBack}: No data (skipped)`);
|
|
37970
|
+
}
|
|
37971
|
+
}
|
|
37972
|
+
return isValid;
|
|
37973
|
+
}).slice(0, DAYS_TO_COLLECT); // Take only the first 5 days with data
|
|
37974
|
+
|
|
37975
|
+
if (collectedDays.length === 0) {
|
|
37976
|
+
throw new Error(`No intraday data available for ${this.symbol} in the past ${MAX_RANGEBACK_ATTEMPTS} days`);
|
|
37977
|
+
}
|
|
37978
|
+
if (this.debug) {
|
|
37979
|
+
console.log(`[IntradayChartWidget] Collected ${collectedDays.length}/${DAYS_TO_COLLECT} days of data`);
|
|
37980
|
+
if (collectedDays.length < DAYS_TO_COLLECT) {
|
|
37981
|
+
console.log(`[IntradayChartWidget] Note: Only ${collectedDays.length} days available within API limit (rangeback 0-6)`);
|
|
37982
|
+
}
|
|
37983
|
+
}
|
|
37984
|
+
|
|
37985
|
+
// Combine all collected days into a single array (oldest to newest)
|
|
37986
|
+
const combinedData = [];
|
|
37987
|
+
for (let i = collectedDays.length - 1; i >= 0; i--) {
|
|
37988
|
+
combinedData.push(...collectedDays[i].data);
|
|
37989
|
+
}
|
|
37990
|
+
if (this.debug) {
|
|
37991
|
+
console.log(`[IntradayChartWidget] Combined ${combinedData.length} total data points from ${collectedDays.length} days`);
|
|
37992
|
+
}
|
|
37993
|
+
return combinedData;
|
|
37994
|
+
}
|
|
37995
|
+
preload5DDataInBackground() {
|
|
37996
|
+
// Prevent multiple simultaneous preloads
|
|
37997
|
+
if (this.is5DDataLoading || this.cached5DData) {
|
|
37998
|
+
return;
|
|
37999
|
+
}
|
|
38000
|
+
this.is5DDataLoading = true;
|
|
38001
|
+
if (this.debug) {
|
|
38002
|
+
console.log('[IntradayChartWidget] Starting background preload of 5D data...');
|
|
38003
|
+
}
|
|
38004
|
+
|
|
38005
|
+
// Run in background without blocking
|
|
38006
|
+
setTimeout(async () => {
|
|
38007
|
+
try {
|
|
38008
|
+
const apiService = this.wsManager.getApiService();
|
|
38009
|
+
if (!apiService) {
|
|
38010
|
+
if (this.debug) {
|
|
38011
|
+
console.log('[IntradayChartWidget] API service not available for preload');
|
|
38012
|
+
}
|
|
38013
|
+
return;
|
|
38014
|
+
}
|
|
38015
|
+
const combinedData = await this.fetch5DayData(apiService);
|
|
38016
|
+
|
|
38017
|
+
// Create and cache the model
|
|
38018
|
+
const chartData = new IntradayChartModel(combinedData);
|
|
38019
|
+
this.cached5DData = chartData;
|
|
38020
|
+
if (this.debug) {
|
|
38021
|
+
console.log(`[IntradayChartWidget] ✓ Background preload complete: ${chartData.dataPoints.length} data points cached`);
|
|
38022
|
+
}
|
|
38023
|
+
} catch (error) {
|
|
38024
|
+
if (this.debug) {
|
|
38025
|
+
console.warn('[IntradayChartWidget] Background preload failed:', error);
|
|
38026
|
+
}
|
|
38027
|
+
} finally {
|
|
38028
|
+
this.is5DDataLoading = false;
|
|
38029
|
+
}
|
|
38030
|
+
}, 1000); // Wait 1 second after 1D loads before starting preload
|
|
38031
|
+
}
|
|
37870
38032
|
subscribeToLivePrice() {
|
|
37871
38033
|
// Unsubscribe from previous subscription if any
|
|
37872
38034
|
if (this.unsubscribe) {
|
|
@@ -38189,16 +38351,28 @@ class IntradayChartWidget extends BaseWidget {
|
|
|
38189
38351
|
|
|
38190
38352
|
if (this.chartType === 'candlestick') {
|
|
38191
38353
|
// Prepare OHLC data for candlestick chart
|
|
38192
|
-
|
|
38193
|
-
x
|
|
38194
|
-
|
|
38195
|
-
|
|
38196
|
-
|
|
38197
|
-
|
|
38198
|
-
|
|
38199
|
-
|
|
38200
|
-
|
|
38201
|
-
}
|
|
38354
|
+
if (this.rangeBack > 0) {
|
|
38355
|
+
// For multi-day charts, use index as x-value (linear scale)
|
|
38356
|
+
chartDataPoints = validDataPoints.map((point, index) => ({
|
|
38357
|
+
x: index,
|
|
38358
|
+
o: point.open,
|
|
38359
|
+
h: point.high,
|
|
38360
|
+
l: point.low,
|
|
38361
|
+
c: point.close
|
|
38362
|
+
}));
|
|
38363
|
+
} else {
|
|
38364
|
+
// For single-day charts, use timestamps (time scale)
|
|
38365
|
+
chartDataPoints = validDataPoints.map(point => ({
|
|
38366
|
+
x: this.parseTimestamp(point.time).getTime(),
|
|
38367
|
+
o: point.open,
|
|
38368
|
+
h: point.high,
|
|
38369
|
+
l: point.low,
|
|
38370
|
+
c: point.close
|
|
38371
|
+
})).filter(point => {
|
|
38372
|
+
// Filter out invalid timestamps
|
|
38373
|
+
return !isNaN(point.x) && point.x > 0;
|
|
38374
|
+
});
|
|
38375
|
+
}
|
|
38202
38376
|
if (chartDataPoints.length === 0) {
|
|
38203
38377
|
console.error('[IntradayChartWidget] No valid candlestick data points after date parsing');
|
|
38204
38378
|
this.showError('Unable to parse chart data timestamps');
|
|
@@ -38220,14 +38394,23 @@ class IntradayChartWidget extends BaseWidget {
|
|
|
38220
38394
|
};
|
|
38221
38395
|
} else {
|
|
38222
38396
|
// Prepare data with timestamps for line/area chart
|
|
38223
|
-
|
|
38224
|
-
x
|
|
38225
|
-
|
|
38226
|
-
|
|
38227
|
-
|
|
38228
|
-
|
|
38229
|
-
|
|
38230
|
-
|
|
38397
|
+
if (this.rangeBack > 0) {
|
|
38398
|
+
// For multi-day charts, use index as x-value (linear scale)
|
|
38399
|
+
chartDataPoints = validDataPoints.map((point, index) => ({
|
|
38400
|
+
x: index,
|
|
38401
|
+
y: point.close
|
|
38402
|
+
}));
|
|
38403
|
+
} else {
|
|
38404
|
+
// For single-day charts, use timestamps (time scale)
|
|
38405
|
+
chartDataPoints = validDataPoints.map(point => ({
|
|
38406
|
+
x: this.parseTimestamp(point.time),
|
|
38407
|
+
y: point.close
|
|
38408
|
+
})).filter(point => {
|
|
38409
|
+
// Filter out invalid dates
|
|
38410
|
+
const timestamp = point.x.getTime();
|
|
38411
|
+
return !isNaN(timestamp) && timestamp > 0;
|
|
38412
|
+
});
|
|
38413
|
+
}
|
|
38231
38414
|
if (chartDataPoints.length === 0) {
|
|
38232
38415
|
console.error('[IntradayChartWidget] No valid chart data points after date parsing');
|
|
38233
38416
|
this.showError('Unable to parse chart data timestamps');
|
|
@@ -38262,16 +38445,23 @@ class IntradayChartWidget extends BaseWidget {
|
|
|
38262
38445
|
console.log('[IntradayChartWidget] Last data point - Source time:', validDataPoints[validDataPoints.length - 1].time);
|
|
38263
38446
|
console.log('[IntradayChartWidget] Last chart point:', chartDataPoints[chartDataPoints.length - 1]);
|
|
38264
38447
|
|
|
38265
|
-
// Calculate explicit min/max for x-axis
|
|
38266
|
-
|
|
38267
|
-
|
|
38268
|
-
|
|
38269
|
-
|
|
38270
|
-
min
|
|
38271
|
-
max
|
|
38272
|
-
|
|
38273
|
-
|
|
38274
|
-
|
|
38448
|
+
// Calculate explicit min/max for x-axis (only for time scale, not linear)
|
|
38449
|
+
let minTimestamp, maxTimestamp;
|
|
38450
|
+
if (this.rangeBack === 0) {
|
|
38451
|
+
// For time scale, calculate timestamp bounds
|
|
38452
|
+
const timestamps = chartDataPoints.map(p => this.chartType === 'candlestick' ? p.x : p.x.getTime());
|
|
38453
|
+
minTimestamp = Math.min(...timestamps);
|
|
38454
|
+
maxTimestamp = Math.max(...timestamps);
|
|
38455
|
+
console.log('[IntradayChartWidget] X-axis bounds:', {
|
|
38456
|
+
min: minTimestamp,
|
|
38457
|
+
max: maxTimestamp,
|
|
38458
|
+
minDate: new Date(minTimestamp),
|
|
38459
|
+
maxDate: new Date(maxTimestamp)
|
|
38460
|
+
});
|
|
38461
|
+
} else {
|
|
38462
|
+
// For linear scale, bounds are just indices
|
|
38463
|
+
console.log('[IntradayChartWidget] Using linear scale with', chartDataPoints.length, 'data points');
|
|
38464
|
+
}
|
|
38275
38465
|
const config = {
|
|
38276
38466
|
type: this.chartType === 'candlestick' ? 'candlestick' : 'line',
|
|
38277
38467
|
data: {
|
|
@@ -38309,10 +38499,9 @@ class IntradayChartWidget extends BaseWidget {
|
|
|
38309
38499
|
const index = context[0].dataIndex;
|
|
38310
38500
|
const point = validDataPoints[index];
|
|
38311
38501
|
if (point) {
|
|
38312
|
-
//
|
|
38502
|
+
// Display timestamp as-is from the data, without timezone conversion
|
|
38313
38503
|
const date = new Date(point.time);
|
|
38314
38504
|
return date.toLocaleString('en-US', {
|
|
38315
|
-
timeZone: 'America/New_York',
|
|
38316
38505
|
month: '2-digit',
|
|
38317
38506
|
day: '2-digit',
|
|
38318
38507
|
year: 'numeric',
|
|
@@ -38363,62 +38552,62 @@ class IntradayChartWidget extends BaseWidget {
|
|
|
38363
38552
|
}
|
|
38364
38553
|
},
|
|
38365
38554
|
annotation: {
|
|
38366
|
-
annotations:
|
|
38367
|
-
livePriceLine: {
|
|
38368
|
-
type: 'line',
|
|
38369
|
-
scaleID: 'y',
|
|
38370
|
-
value: this.livePrice || stats.close,
|
|
38371
|
-
borderColor: '#667eea',
|
|
38372
|
-
borderWidth: 2,
|
|
38373
|
-
borderDash: [5, 5],
|
|
38374
|
-
label: {
|
|
38375
|
-
display: true,
|
|
38376
|
-
content: this.livePrice ? `$${this.livePrice.toFixed(2)}` : `$${stats.close.toFixed(2)}`,
|
|
38377
|
-
enabled: true,
|
|
38378
|
-
position: 'end',
|
|
38379
|
-
backgroundColor: 'rgb(102, 126, 234)',
|
|
38380
|
-
color: '#ffffff',
|
|
38381
|
-
font: {
|
|
38382
|
-
size: 12,
|
|
38383
|
-
weight: 'bold',
|
|
38384
|
-
family: 'system-ui, -apple-system, sans-serif'
|
|
38385
|
-
},
|
|
38386
|
-
padding: {
|
|
38387
|
-
top: 4,
|
|
38388
|
-
bottom: 4,
|
|
38389
|
-
left: 8,
|
|
38390
|
-
right: 8
|
|
38391
|
-
},
|
|
38392
|
-
borderRadius: 4,
|
|
38393
|
-
xAdjust: -10,
|
|
38394
|
-
yAdjust: 0
|
|
38395
|
-
}
|
|
38396
|
-
}
|
|
38397
|
-
}
|
|
38555
|
+
annotations: this.createAnnotations(validDataPoints, stats)
|
|
38398
38556
|
}
|
|
38399
38557
|
},
|
|
38400
38558
|
scales: {
|
|
38401
38559
|
x: {
|
|
38402
|
-
type: 'time',
|
|
38403
|
-
min: minTimestamp,
|
|
38404
|
-
max: maxTimestamp,
|
|
38405
|
-
time: {
|
|
38406
|
-
unit:
|
|
38560
|
+
type: this.rangeBack === 0 ? 'time' : 'linear',
|
|
38561
|
+
min: this.rangeBack === 0 ? minTimestamp : undefined,
|
|
38562
|
+
max: this.rangeBack === 0 ? maxTimestamp : undefined,
|
|
38563
|
+
time: this.rangeBack === 0 ? {
|
|
38564
|
+
unit: 'hour',
|
|
38565
|
+
stepSize: 1,
|
|
38407
38566
|
displayFormats: {
|
|
38408
|
-
|
|
38409
|
-
hour: 'MMM d, ha'
|
|
38567
|
+
hour: 'h:mm a'
|
|
38410
38568
|
},
|
|
38411
38569
|
tooltipFormat: 'MMM d, h:mm a'
|
|
38412
|
-
},
|
|
38570
|
+
} : undefined,
|
|
38413
38571
|
grid: {
|
|
38414
38572
|
display: false
|
|
38415
38573
|
},
|
|
38416
38574
|
ticks: {
|
|
38417
|
-
maxTicksLimit: 10,
|
|
38575
|
+
maxTicksLimit: this.rangeBack === 0 ? 10 : 8,
|
|
38418
38576
|
color: '#6b7280',
|
|
38419
38577
|
autoSkip: true,
|
|
38420
38578
|
maxRotation: 0,
|
|
38421
|
-
minRotation: 0
|
|
38579
|
+
minRotation: 0,
|
|
38580
|
+
callback: (value, index, ticks) => {
|
|
38581
|
+
if (this.rangeBack > 0) {
|
|
38582
|
+
// For multi-day charts with linear scale
|
|
38583
|
+
// value is the x-value (index in data array), not the tick index
|
|
38584
|
+
const dataIndex = Math.round(value);
|
|
38585
|
+
const point = validDataPoints[dataIndex];
|
|
38586
|
+
if (point) {
|
|
38587
|
+
const date = new Date(point.time);
|
|
38588
|
+
return date.toLocaleString('en-US', {
|
|
38589
|
+
month: 'short',
|
|
38590
|
+
day: 'numeric',
|
|
38591
|
+
hour: 'numeric',
|
|
38592
|
+
minute: '2-digit',
|
|
38593
|
+
hour12: true
|
|
38594
|
+
});
|
|
38595
|
+
}
|
|
38596
|
+
return '';
|
|
38597
|
+
}
|
|
38598
|
+
// For single-day time scale, provide fallback formatting
|
|
38599
|
+
// If value is a number (timestamp), format it
|
|
38600
|
+
if (typeof value === 'number') {
|
|
38601
|
+
const date = new Date(value);
|
|
38602
|
+
return date.toLocaleString('en-US', {
|
|
38603
|
+
hour: 'numeric',
|
|
38604
|
+
minute: '2-digit',
|
|
38605
|
+
hour12: true
|
|
38606
|
+
});
|
|
38607
|
+
}
|
|
38608
|
+
// Otherwise let Chart.js handle it (if date adapter is working)
|
|
38609
|
+
return value;
|
|
38610
|
+
}
|
|
38422
38611
|
}
|
|
38423
38612
|
},
|
|
38424
38613
|
y: {
|
|
@@ -38464,6 +38653,63 @@ class IntradayChartWidget extends BaseWidget {
|
|
|
38464
38653
|
// Add reset zoom button listener
|
|
38465
38654
|
this.setupZoomReset();
|
|
38466
38655
|
}
|
|
38656
|
+
createAnnotations(dataPoints, stats) {
|
|
38657
|
+
const annotations = {
|
|
38658
|
+
livePriceLine: {
|
|
38659
|
+
type: 'line',
|
|
38660
|
+
scaleID: 'y',
|
|
38661
|
+
value: this.livePrice || stats.close,
|
|
38662
|
+
borderColor: '#667eea',
|
|
38663
|
+
borderWidth: 2,
|
|
38664
|
+
borderDash: [5, 5],
|
|
38665
|
+
label: {
|
|
38666
|
+
display: true,
|
|
38667
|
+
content: this.livePrice ? `$${this.livePrice.toFixed(2)}` : `$${stats.close.toFixed(2)}`,
|
|
38668
|
+
enabled: true,
|
|
38669
|
+
position: 'end',
|
|
38670
|
+
backgroundColor: 'rgb(102, 126, 234)',
|
|
38671
|
+
color: '#ffffff',
|
|
38672
|
+
font: {
|
|
38673
|
+
size: 12,
|
|
38674
|
+
weight: 'bold',
|
|
38675
|
+
family: 'system-ui, -apple-system, sans-serif'
|
|
38676
|
+
},
|
|
38677
|
+
padding: {
|
|
38678
|
+
top: 4,
|
|
38679
|
+
bottom: 4,
|
|
38680
|
+
left: 8,
|
|
38681
|
+
right: 8
|
|
38682
|
+
},
|
|
38683
|
+
borderRadius: 4,
|
|
38684
|
+
xAdjust: -10,
|
|
38685
|
+
yAdjust: 0
|
|
38686
|
+
}
|
|
38687
|
+
}
|
|
38688
|
+
};
|
|
38689
|
+
|
|
38690
|
+
// Add day separators for multi-day charts (5D, etc.)
|
|
38691
|
+
if (this.rangeBack > 0 && dataPoints.length > 0) {
|
|
38692
|
+
let currentDay = null;
|
|
38693
|
+
dataPoints.forEach((point, index) => {
|
|
38694
|
+
const pointDate = new Date(point.time);
|
|
38695
|
+
const day = pointDate.toDateString();
|
|
38696
|
+
|
|
38697
|
+
// Add vertical line at the start of each new day
|
|
38698
|
+
if (currentDay !== day && currentDay !== null) {
|
|
38699
|
+
annotations[`daySeparator${index}`] = {
|
|
38700
|
+
type: 'line',
|
|
38701
|
+
scaleID: 'x',
|
|
38702
|
+
value: index,
|
|
38703
|
+
borderColor: 'rgba(0, 0, 0, 0.1)',
|
|
38704
|
+
borderWidth: 1,
|
|
38705
|
+
borderDash: [3, 3]
|
|
38706
|
+
};
|
|
38707
|
+
}
|
|
38708
|
+
currentDay = day;
|
|
38709
|
+
});
|
|
38710
|
+
}
|
|
38711
|
+
return annotations;
|
|
38712
|
+
}
|
|
38467
38713
|
setupZoomReset() {
|
|
38468
38714
|
const resetBtn = this.container.querySelector('.zoom-reset-btn');
|
|
38469
38715
|
if (resetBtn) {
|