Pre loader

Double labels for line annotations

Welcome to the SciChart Forums!

  • Please read our Question Asking Guidelines for how to format a good question
  • Some reputation is required to post answers. Get up-voted to avoid the spam filter!
  • We welcome community answers and upvotes. Every Q&A improves SciChart for everyone

WPF Forums | JavaScript Forums | Android Forums | iOS Forums

0
0

Hello,
I have a question regarding line labels. We have a stock chart and we need to have the value/date of the line on the Y or X axis and a label. Currently (for example for HorizontalLineAnnotation), if I set:
labelPlacement to ‘Axis’ and do not set labelValue, then there is a value on the Y axis:
https://ibb.co/jrKtPzS

In the case of assigning the labelValue to ‘I would like to have text here’ and labelPlacement to Top, I get the text in the middle of the line:
https://ibb.co/N3Fq4Kk

I need a combination of these options, displaying both and, of course, changing the position as the user moves the line. We don’t have static lines, so moving a TextAnnotation assigned to a line would be troublesome (there could be a dozen of them on the chart).
https://ibb.co/Nn7cNWS

We will need this for every type of line. It would be a good solution to have, for example, 2 separate props: for the label, showLabel, labelValue, labelPlacement, and for the axis label: showAxisLabel, labelAxisValue.

Unless there is currently a way to achieve this effect?

Version
3.5.687
  • You must to post comments
0
0

Hello Kamil,
I think the straightforward solution would be to use 2 LineAnnotations (or maybe AxisMarkerAnnotation) for this and adjust their styles accordingly.
Then when one of them is being dragged you can update the position of the other respectively.

Another solution potentially would be to customize the rendering logic by extending the LineAnnotation class and overriding some methods to draw both labels. This, however, requires some understanding of how internals work.

Try the first solution if that works for you and let us know whether you have managed to achieve the desired behaviour.

  • You must to post comments
0
0

Hello,
I create labels as follows. Only problem is with fontFamily, because despite setting Ubuntu Mono for the 2 labels on the left, they have the default font. In addition, setting axisFontFamily only changes the font family of only one label, and the ones I added remain the default, which is Ariel. Also zoom does not change the font size. Is it possible to set a different font family using drawLineAnnotation and fix font size problem?

  drawWithContext(renderContext, xCalc, yCalc, viewRect) {
        const priceTextStyle = {color: this.parentSurface.themeProvider.crosshairAxisLabelFont, fontSize: this.axisFontSize * DpiHelper.PIXEL_RATIO, fontFamily: this.axisFontFamily};
        const priceDifferenceTextStyle = {color: this.axisLabelStroke, fontSize: 12 * DpiHelper.PIXEL_RATIO, fontFamily: "Ubuntu Mono, monospace"};

        const borderY1 = this.getY1Coordinate(xCalc, yCalc);
        const borderY2 = borderY1;

        const price = this.parentSurface.annotations.items.find(({id}) => id === 'priceAnnotation')?.y1;

        // Price annotation
        drawLineAnnotation(this.parentSurface.yAxes.get(0), renderContext, ELabelPlacement.Axis, this.y1.toFixed(2), 0, 0, borderY1, borderY2, priceTextStyle, this.parentSurface.themeProvider.crosshairAxisLabelFill, undefined, viewRect, true, 1, EHorizontalAnchorPoint.Right);

        // % price difference
        drawLineAnnotation(this.parentSurface.yAxes.get(0), renderContext, ELabelPlacement.TopLeft, getPriceDifference(price, this.y1, "UP"), 0, 0, borderY1, borderY2, priceDifferenceTextStyle, this.axisLabelFill, undefined, viewRect, true, 1, EHorizontalAnchorPoint.Left);
        drawLineAnnotation(this.parentSurface.yAxes.get(0), renderContext, ELabelPlacement.BottomLeft, getPriceDifference(price, this.y1, "DOWN"), 0, 0, borderY1, borderY2, priceDifferenceTextStyle, this.axisLabelFill, undefined, viewRect, true, 1, EHorizontalAnchorPoint.Left);

        super.drawWithContext(renderContext, xCalc, yCalc, viewRect);
    }
  • Jim Risen
    Hello, looks like you got a great progress on that! We need a bit more context to understand the issue here. Please clarify what kind of zoom you are refering to: via visible range update or browser zoom? What are your axes definitions? How do you define an annotation? Also, it might be not obvious from a code snippet, so it would be much better if you provide a minimal reproducible example.
  • You must to post comments
0
0

I have created a custom class for creating horizontalLineAnnotation. Each line must have labels on the left side above and below at the same distances, showing percentage changes that are recalculated with every line movement. They should have a fixed font, monospace Ubuntu Mono.

The label above the line (centered, with user-editable text) remains unchanged.

On the right side, on the Y-axis, there should be a label showing the current price value, which is the y1 value (for vertical lines, the date will be provided along with the label on the X-axis).

The assumption is to draw the labels immediately when creating the line.

Regarding zoom, I meant browser zoom. I have attached a picture at 125% zoom. I would like these additional labels to be scalable as well.
https://ibb.co/2qGvQM5

Currently, there remains a problem with the zoom and the font family of the labels on the left side.
Below I attach the code for CustomizedHorizontalLineAnnotation.

    import {
    HorizontalLineAnnotation,
    EventHandler,
    drawLineAnnotation,
    EHorizontalAnchorPoint,
    ELabelPlacement,
} from "scichart";
import {DpiHelper} from "scichart/Charting/Visuals/TextureManager/DpiHelper";
import {dividedBy, multiplyValues, subtractValues} from "@/utils/calculationUtils";
import {colorListForDarkFont} from "@/constans/chart";

function getPriceDifference(price, lineValue, direction) {
    const baseValue = direction === "UP" ? lineValue : price;
    const compareValue = direction === "UP" ? price : lineValue;
    const percent = subtractValues(dividedBy(multiplyValues(baseValue, 100), compareValue), 100);

    return percent > 0 ? `+${percent.toFixed(2)}%` : `${percent.toFixed(2)}%`;
}

class CustomizedHorizontalLineAnnotation extends HorizontalLineAnnotation {
    constructor({
                    x1,
                    y1,
                    stroke,
                    strokeThickness,
                    isEditable,
                    isSelected,
                    id,
                    strokeDashArray,
                    onClick,
                    onDragEnded,
                    onDragStarted,
                    labelPlacement,
                    labelValue,
                    showLabel,
                    axisLabelFill,
                    isHidden,
                    onHover,
                    lineType,
                }) {
        super();
        this.customDragEventHandler = new EventHandler();
        this.id = id;
        this.isSelected = isSelected;
        this.isHidden = isHidden;
        this.onClick = onClick;
        this.onHover = onHover;
        this.onDragEndedFunction = onDragEnded;
        this.onDragStartedFunction = onDragStarted;
        this.strokeDashArray = strokeDashArray;
        this.stroke = stroke;
        this.strokeThickness = strokeThickness;
        this.isEditable = isEditable;
        this.selectionBoxStroke = "rgba(255,255,255,0)";
        this.selectionBoxThickness = 0;
        this.annotationsGripsRadius = 8;
        this.annotationsGripsFill = "#f4730b33";
        this.annotationsGripsStroke = "#f4730b";
        this.x1 = x1;
        this.y1 = y1;
        this.labelPlacement = labelPlacement;
        this.labelValue = labelValue;
        this.showLabel = showLabel;
        this.axisLabelFill = axisLabelFill;
        this.lineType = lineType;
    }

    hover(args) {
        super.hover(args)
        this.onHover(args);
    }

    click(args, selectOnClick) {
        const isSelected = super.click(args, selectOnClick);
        if (isSelected) {
            this.onClick({mouseArgs: args, sender: {id: this.id}});
        }
        return isSelected;
    }

    onDragEnded() {
        super.onDragEnded();
        this.onDragEndedFunction();
    }

    onDragStarted(args) {
        if (this.onDragStartedFunction) {
            this.onDragStartedFunction();
        }
        return super.onDragStarted(args);
    }

    onDragAdorner(args) {
        super.onDragAdorner(args);
        this.customDragEventHandler.raiseEvent({args, sender: this});
    }

    delete() {
        this.customDragEventHandler.unsubscribeAll();
        super.delete();
    }

    drawWithContext(renderContext, xCalc, yCalc, viewRect) {
        const priceTextStyle = {
            color: colorListForDarkFont.includes(this.axisLabelFill) ? "#282828" : "#ffffff",
            fontSize: this.axisFontSize * DpiHelper.PIXEL_RATIO,
            fontFamily: this.axisFontFamily
        };
        const priceDifferenceTextStyle = {
            color: this.axisLabelStroke,
            fontSize: 12 * DpiHelper.PIXEL_RATIO,
            fontFamily: "Ubuntu Mono, monospace"
        };

        const borderY1 = this.getY1Coordinate(xCalc, yCalc);
        const borderY2 = borderY1;

        const price = this.parentSurface.annotations.items.find(({id}) => id === 'priceAnnotation')?.y1;

        // Price annotation
        drawLineAnnotation(this.parentSurface.yAxes.get(0), renderContext, ELabelPlacement.Axis, this.y1.toFixed(2), 0, 0, borderY1, borderY2, priceTextStyle, this.axisLabelFill, undefined, viewRect, true, 1, EHorizontalAnchorPoint.Right);

        // % price difference
        drawLineAnnotation(this.parentSurface.yAxes.get(0), renderContext, ELabelPlacement.TopLeft, getPriceDifference(price, this.y1, "UP"), 0, 0, borderY1, borderY2, priceDifferenceTextStyle, this.axisLabelFill, undefined, viewRect, true, 1, EHorizontalAnchorPoint.Left);
        drawLineAnnotation(this.parentSurface.yAxes.get(0), renderContext, ELabelPlacement.BottomLeft, getPriceDifference(price, this.y1, "DOWN"), 0, 0, borderY1, borderY2, priceDifferenceTextStyle, this.axisLabelFill, undefined, viewRect, true, 1, EHorizontalAnchorPoint.Left);

        super.drawWithContext(renderContext, xCalc, yCalc, viewRect);
    }
}

export {
    CustomizedHorizontalLineAnnotation
};
Attachments
  • Kamil Macura
    I delved a little deeper into the code and it seems to me that drawLineAnnotation with the given styles const priceDifferenceTextStyle = { color: this.axisLabelStroke, fontSize: 12 * DpiHelper.PIXEL_RATIO, fontFamily: “Ubuntu Mono, monospace” }; should create a label with the specified font, fontSize, and not replace it with the default one, because: (var drawLineAnnotation) var labelTextStyle = isLabelOnAxis ? textStyle : __assign(__assign({}, textStyle), { color: fill }); if (showLabel) { var _b = currentAxis.axisRenderer.createAnnotationLabelTexture(text, labelTextStyle, labelBackgroundColor, displayVertically, displayMirrored, opacity), bitmapTexture = _b.bitmapTexture, textureHeight = _b.textureHeight, textureWidth = _b.textureWidth; at no point is the style overwritten, but this does not work
  • You must to post comments
Showing 3 results
Your Answer

Please first to submit.