Taylor
Taylor

Reputation: 39

How can we add text on bar of Bar chart?

Using LightningchartJS I want the bar graph which contains text on the bar of graph. How can I add text on bar?

const months = [
    'January', 'February', 'March', 'April', 'May', 'June', 'July',
    'August', 'September', 'October', 'November', 'December'
]


    const barText = chart.addUIElement(
                    UILayoutBuilders.Row,
                    { x: axisX.scale, y: axisY.scale }
                )
                    .setOrigin(UIOrigins.Center)
                    .setDraggingMode(UIDraggingModes.notDraggable)
                    .setPosition({
                        x:x - figureThickness,
                        y: 0 ,
                    })
                    .setBackground(background => background
                        .setStrokeStyle(emptyLine)
                    )
                spanText.addElement(
                    UIElementBuilders.TextBox
                        .addStyler(
                            textBox =>
                                textBox.setFont(fontSettings => fontSettings.setSize(10)).setText(months[index])
                                    .setTextFillStyle(new SolidFill().setColor(ColorRGBA(255, 255, 255)))
                        )

Original Graph Expected Graph

Upvotes: 0

Views: 1209

Answers (1)

Snekw
Snekw

Reputation: 2620

What you tried to do is bit more complex than what really is required.

You can use UIElementBuilders.TextBox to create textboxes for each chart. Make sure to use the axis scale for the series you want to position the textboxes to.

const uiElement = chart.addUIElement(
    UIElementBuilders.TextBox,
    { x:chart.getDefaultAxisX().scale, y:chart.getDefaultAxisY().scale }
)

Then you can position the textbox with same position information as the bar.

.setPosition({x: x - figureGap, y:0})

To get the positioning be offset from the y in the way you wanted to have them, you can change the origin point for the textbox.

.setOrigin(UIOrigins.CenterBottom) for the bars that are positive and .setOrigin(UIOrigins.CenterTop) for the bars that are negative.

See the code snippet below for full example.

/*
 * LightningChartJS example for rendering a 'vertical bar chart' using user-side logic as there is no dedicated Chart type for Bars, yet.
 */
// Extract required parts from LightningChartJS.
const {
    lightningChart,
    AxisScrollStrategies,
    SolidFill,
    ColorRGBA,
    emptyLine,
    emptyFill,
    AutoCursorModes,
    UIOrigins,
    emptyTick,
    UIElementBuilders
} = lcjs

const lc = lightningChart()

const months = [
    'January', 'February', 'March', 'April', 'May', 'June', 'July',
    'August', 'September', 'October', 'November', 'December'
]
// Define an interface for creating vertical bars.
let barChart
{
    barChart = (options) => {
        // flat red fill style for positive bars
        const flatRedStyle = new SolidFill().setColor(ColorRGBA(242, 67, 79))
        // flat blue fill style for negative bars
        const flatBlueStyle = new SolidFill().setColor(ColorRGBA(42, 171, 240))

        let x = 0
        const figureThickness = 10
        const figureGap = figureThickness * .5
        const bars = []

        // Create a XY-Chart and add a RectSeries to it for rendering rectangles.
        const chart = lc.ChartXY(options)
            .setTitle('Changes in electricity usage between 2017 and 2018')
            .setAutoCursorMode(AutoCursorModes.onHover)
            // Disable mouse interactions (e.g. zooming and panning) of plotting area
            .setMouseInteractions(false)

        // Bar series represented with rectangles.
        const rectangles = chart.addRectangleSeries()

        // cursor
        //#region
        // Show band using Rectangle series.
        const band = chart.addRectangleSeries()
            .setMouseInteractions(false)
            .setCursorEnabled(false).add({ x: 0, y: 0, width: 0, height: 0 })
            .setFillStyle(new SolidFill().setColor(ColorRGBA(255, 255, 255, 50)))
            .setStrokeStyle(emptyLine)
            .dispose()
        // Modify AutoCursor.
        chart.setAutoCursor(cursor => cursor
            .disposePointMarker()
            .disposeTickMarkerX()
            .disposeTickMarkerY()
            .setGridStrokeXStyle(emptyLine)
            .setGridStrokeYStyle(emptyLine)
            .setResultTable((table) => {
                table
                    .setOrigin(UIOrigins.CenterBottom)
            })
        )
        // Change how series parses its data-points using series method.
        rectangles.setResultTableFormatter((builder, series, figure) => {
            let counter = 0
            // Find cached entry for the figure.
            const entry = bars.find((bar, index) => {
                counter = index;
                return bar.rect == figure
            }).entry
            // Parse result table content from values of 'entry'.
            return builder
                .addRow(`Month: ${months[counter]}`)
                .addRow(`Value: ${entry.value}%`)
        })
        // Apply cursor logic using series.onHover method
        rectangles.onHover((_, point) => {
            if (point) {
                const figure = point.figure
                const dimensions = figure.getDimensionsPositionAndSize()
                // Show band.
                band
                    .setDimensions({
                        x: dimensions.x - figureGap * .5,
                        y: figure.scale.y.getInnerStart(),
                        width: dimensions.width + figureGap,
                        height: figure.scale.y.getInnerInterval()
                    })
                    .restore()
            } else
                band.dispose()
        })
        //#endregion

        // X-axis of the series
        const axisX = chart.getDefaultAxisX()
            .setTitle('Quarter')
            .setMouseInteractions(false)
            .setScrollStrategy(undefined)
            // Disable default ticks.
            .setTickStyle(emptyTick)

        // Y-axis of the series
        const axisY = chart.getDefaultAxisY()
            .setTitle('(%)')
            .setMouseInteractions(false)
            .setScrollStrategy(AxisScrollStrategies.fitting)

        /**
         * Add multiple bars.
         * @param entries Add multiple bars data.
         */
        const addValues = (entries) => {
            for (const entry of entries) {
                bars.push(add(entry))
            }
        }
        /**
         * Add single bar.
         * @param entry Add a single bar data.
         */
        const addValue = (entry) => {
            bars.push(add(entry))
        }
        /**
         * Construct bar to draw.
         * @param entry Single bar data.
         */
        const add = (entry) => {
            // Create rect dimensions.
            const rectDimensions = {
                x: x - figureThickness,
                y: 0,
                width: figureThickness,
                height: entry.value
            }
            // Add rect to the series.
            const rect = rectangles.add(rectDimensions)
            // Set individual color for the bar.
            rect.setFillStyle(entry.value > 0 ? flatRedStyle : flatBlueStyle)

            // Set view manually.
            axisX.setInterval(
                -(figureThickness + figureGap),
                x + figureGap
            )

            // Add custom tick, more like categorical axis.
            axisX.addCustomTick()
                .setValue(x - figureGap)
                .setGridStrokeLength(0)
                .setTextFormatter(_ => entry.category)
                .setMarker(marker => marker
                    .setPadding(4)
                    .setBackground((background) => background
                        .setFillStyle(emptyFill)
                        .setStrokeStyle(emptyLine)
                    )
                )

            const uiElement = chart.addUIElement(
                UIElementBuilders.TextBox,
                { x:chart.getDefaultAxisX().scale, y:chart.getDefaultAxisY().scale }
            )
                .setText(entry.label)
                .setTextFillStyle(new SolidFill({color:ColorRGBA(0,0,0)}))
                .setPosition({x: x - figureGap,y:0})
                .setOrigin(UIOrigins.CenterBottom)
            
            if(Math.sign(entry.value) === -1){
                uiElement.setOrigin(UIOrigins.CenterTop)
            }

            x += figureThickness + figureGap
            // Return data-structure with both original 'entry' and the rectangle figure that represents it.
            return {
                entry,
                rect
            }
        }

        // Return public methods of a bar chart interface.
        return {
            addValue,
            addValues
        }
    }
}

// Use bar chart interface to construct series.
const chart = barChart()
// Add multiple bars at once.
chart.addValues([
    { category: '', value: 20, label: 'JAN' },
    { category: 'Q1', value: 20, label: 'FEB'},
    { category: '', value: -25, label: 'MAR' },
    { category: '', value: 40, label: 'APR' },
    { category: 'Q2', value: 28, label: 'MAY' },
    { category: '', value: -23, label: 'JUN' },
    { category: '', value: -40, label: 'JUL' },
    { category: 'Q3', value: 35, label: 'AUG' },
    { category: '', value: 17, label: 'SEP' },
    { category: '', value: 24, label: 'OCT' },
    { category: 'Q4', value: -29, label: 'NOV' },
    { category: '', value: 15, label: 'DEC' }
])
<script src="https://unpkg.com/@arction/[email protected]/dist/lcjs.iife.js"></script>

Upvotes: 1

Related Questions