Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 28 additions & 12 deletions src/namespaces/box/BoxHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,27 @@ export class BoxHelper {
public syncToPlot() {
this._ensurePlotsEntry();
const time = this.context.marketData[0]?.openTime || 0;
const allPlotData = this._boxes.map(bx => bx.toPlotData());

// Split force_overlay objects into a separate overlay plot (renders on main chart pane)
const regular = allPlotData.filter((b: any) => !b.force_overlay);
const overlay = allPlotData.filter((b: any) => b.force_overlay);

this.context.plots['__boxes__'].data = [{
time,
value: this._boxes.map(bx => bx.toPlotData()),
value: regular,
options: { style: 'drawing_box' },
}];

if (overlay.length > 0) {
this.context.plots['__boxes_overlay__'] = {
title: '__boxes_overlay__',
data: [{ time, value: overlay, options: { style: 'drawing_box' } }],
options: { style: 'drawing_box', overlay: true },
};
} else {
delete this.context.plots['__boxes_overlay__'];
}
}

private _resolvePoint(point: ChartPointObject): { x: number; xloc: string } {
Expand Down Expand Up @@ -172,32 +188,32 @@ export class BoxHelper {
// --- Coordinate setters ---

set_left(id: BoxObject, left: number): void {
if (id && !id._deleted) id.left = left;
if (id && !id._deleted) id.left = this._resolve(left);
}

set_right(id: BoxObject, right: number): void {
if (id && !id._deleted) id.right = right;
if (id && !id._deleted) id.right = this._resolve(right);
}

set_top(id: BoxObject, top: number): void {
if (id && !id._deleted) id.top = top;
if (id && !id._deleted) id.top = this._resolve(top);
}

set_bottom(id: BoxObject, bottom: number): void {
if (id && !id._deleted) id.bottom = bottom;
if (id && !id._deleted) id.bottom = this._resolve(bottom);
}

set_lefttop(id: BoxObject, left: number, top: number): void {
if (id && !id._deleted) {
id.left = left;
id.top = top;
id.left = this._resolve(left);
id.top = this._resolve(top);
}
}

set_rightbottom(id: BoxObject, right: number, bottom: number): void {
if (id && !id._deleted) {
id.right = right;
id.bottom = bottom;
id.right = this._resolve(right);
id.bottom = this._resolve(bottom);
}
}

Expand All @@ -221,9 +237,9 @@ export class BoxHelper {

set_xloc(id: BoxObject, left: number, right: number, xloc: string): void {
if (id && !id._deleted) {
id.left = left;
id.right = right;
id.xloc = xloc;
id.left = this._resolve(left);
id.right = this._resolve(right);
id.xloc = this._resolve(xloc);
}
}

Expand Down
23 changes: 17 additions & 6 deletions src/namespaces/label/LabelHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,28 @@ export class LabelHelper {

public syncToPlot() {
this._ensurePlotsEntry();
// Store ALL labels as a single array value at the first bar's time.
// Using a live reference so setter mutations are reflected automatically.
// Multiple label objects at the same bar would overwrite each other
// in QFChart's sparse data array, so we aggregate them into one entry
// (same approach as LineHelper._syncToPlot).
const time = this.context.marketData[0]?.openTime || 0;
const allPlotData = this._labels.map(lbl => lbl.toPlotData());

// Split force_overlay objects into a separate overlay plot (renders on main chart pane)
const regular = allPlotData.filter((l: any) => !l.force_overlay);
const overlay = allPlotData.filter((l: any) => l.force_overlay);

this.context.plots['__labels__'].data = [{
time,
value: this._labels.map(lbl => lbl.toPlotData()),
value: regular,
options: { style: 'label' },
}];

if (overlay.length > 0) {
this.context.plots['__labels_overlay__'] = {
title: '__labels_overlay__',
data: [{ time, value: overlay, options: { style: 'label' } }],
options: { style: 'label', overlay: true },
};
} else {
delete this.context.plots['__labels_overlay__'];
}
}

/**
Expand Down
38 changes: 25 additions & 13 deletions src/namespaces/line/LineHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,28 @@ export class LineHelper {

public syncToPlot() {
this._ensurePlotsEntry();
// Store ALL lines as a single array value at the first bar's time.
// Using a live reference so setter mutations are reflected automatically.
// Multiple drawing objects at the same bar would overwrite each other
// in QFChart's sparse data array, so we aggregate them into one entry.
const time = this.context.marketData[0]?.openTime || 0;
const allPlotData = this._lines.map(ln => ln.toPlotData());

// Split force_overlay objects into a separate overlay plot (renders on main chart pane)
const regular = allPlotData.filter((l: any) => !l.force_overlay);
const overlay = allPlotData.filter((l: any) => l.force_overlay);

this.context.plots['__lines__'].data = [{
time,
value: this._lines.map(ln => ln.toPlotData()),
value: regular,
options: { style: 'drawing_line' },
}];

if (overlay.length > 0) {
this.context.plots['__lines_overlay__'] = {
title: '__lines_overlay__',
data: [{ time, value: overlay, options: { style: 'drawing_line' } }],
options: { style: 'drawing_line', overlay: true },
};
} else {
delete this.context.plots['__lines_overlay__'];
}
}

private _resolvePoint(point: ChartPointObject): { x: number; xloc: string } {
Expand Down Expand Up @@ -161,32 +173,32 @@ export class LineHelper {
// --- Setter methods ---

set_x1(id: LineObject, x: number): void {
if (id && !id._deleted) id.x1 = x;
if (id && !id._deleted) id.x1 = this._resolve(x);
}

set_y1(id: LineObject, y: number): void {
if (id && !id._deleted) id.y1 = y;
if (id && !id._deleted) id.y1 = this._resolve(y);
}

set_x2(id: LineObject, x: number): void {
if (id && !id._deleted) id.x2 = x;
if (id && !id._deleted) id.x2 = this._resolve(x);
}

set_y2(id: LineObject, y: number): void {
if (id && !id._deleted) id.y2 = y;
if (id && !id._deleted) id.y2 = this._resolve(y);
}

set_xy1(id: LineObject, x: number, y: number): void {
if (id && !id._deleted) {
id.x1 = x;
id.y1 = y;
id.x1 = this._resolve(x);
id.y1 = this._resolve(y);
}
}

set_xy2(id: LineObject, x: number, y: number): void {
if (id && !id._deleted) {
id.x2 = x;
id.y2 = y;
id.x2 = this._resolve(x);
id.y2 = this._resolve(y);
}
}

Expand Down
17 changes: 17 additions & 0 deletions src/transpiler/transformers/ExpressionTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,23 @@ function transformOperand(node: any, scopeManager: ScopeManager, namespace: stri
NAMESPACES_LIKE.includes(node.object.name) &&
scopeManager.isContextBound(node.object.name);

// For computed access on NAMESPACES_LIKE identifiers (e.g. time[1], close[2]),
// produce $.get(identifier.__value, offset) instead of identifier.__value[offset].
const isNamespaceSubscript = node.computed &&
node.object.type === 'Identifier' &&
NAMESPACES_LIKE.includes(node.object.name) &&
scopeManager.isContextBound(node.object.name);

if (isNamespaceSubscript) {
const valueExpr = {
type: 'MemberExpression',
object: { type: 'Identifier', name: node.object.name },
property: { type: 'Identifier', name: '__value' },
computed: false,
};
return ASTFactory.createGetCall(valueExpr, node.property);
}

// Handle array access
const transformedObject = (node.object.type === 'Identifier' && !isNamespacePropAccess)
? transformIdentifierForParam(node.object, scopeManager)
Expand Down
Loading
Loading