Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin creation from scratch #1713

Open
vishnuc opened this issue Oct 19, 2024 · 7 comments
Open

Plugin creation from scratch #1713

vishnuc opened this issue Oct 19, 2024 · 7 comments

Comments

@vishnuc
Copy link

vishnuc commented Oct 19, 2024

Hi , I can see various example of different plugins created on tradingview , It is mind blowing.

now I want to create my own plugin , but there is nowhere how to create a plugin from scratch , step by step tutorial.It will be great if there is mini how to on how to create our own plugins in two types: custom series and drawing primitives.

like one example of what should be there inside

class MyCustomSeries {
/* Class implementing the ICustomSeriesPaneView interface */
}

I was running npm create lwc-plugin@latest and created plugin and it uses vite , typescript , fancy canvas etc

is it possible to create this plugin via vanilla js ? I dont want to use nodejs or typescript

@Skiv1989
Copy link

You can find examples in the repo, for example start with sinple one https://github.com/tradingview/lightweight-charts/tree/master/plugin-examples/src/plugins/anchored-text and then you will get how it works

@vishnuc
Copy link
Author

vishnuc commented Oct 21, 2024

Hi , yea was working on it in weekend and was able to replicate it via vanilla js using below code , my question is in some example in library it uses/importing fancy-canvas , but here my code in vanilla working fine without it , Am I missing something ? or tv library has built in fancy canvas ?

  <script type="module">
        import { createChart } from '/tv1.mjs';

        // Renderer for the Lollipop series
        class LollipopSeriesRenderer {
            constructor() {
                this._data = null;
                this._options = null;
            }

            draw(target, priceConverter) {
                target.useBitmapCoordinateSpace(scope => this._drawImpl(scope, priceConverter));
            }

            update(data, options) {
                this._data = data;
                this._options = options;
            }

            _drawImpl(scope, priceToCoordinate) {
                if (!this._data || !this._options || this._data.bars.length === 0 || !this._data.visibleRange) {
                    return;
                }

                const bars = this._data.bars.map(bar => ({
                    x: bar.x,
                    y: priceToCoordinate(bar.originalData.value) ?? 0,
                }));

                const lineWidth = Math.min(this._options.lineWidth, this._data.barSpacing)*3;
                const radius = Math.min(Math.floor(this._data.barSpacing / 2), 5);  // Max radius for the circles
                const zeroY = priceToCoordinate(0);

                for (let i = this._data.visibleRange.from; i < this._data.visibleRange.to; i++) {
                    const bar = bars[i];
                    const xPosition = bar.x * scope.horizontalPixelRatio;
                    const yPosition = bar.y * scope.verticalPixelRatio;

                    scope.context.beginPath();
                    scope.context.fillStyle = this._options.color;
                    
                    // Draw the line from zero to the value
                    scope.context.fillRect(xPosition - lineWidth / 2, zeroY * scope.verticalPixelRatio, lineWidth, yPosition - zeroY * scope.verticalPixelRatio);
                    
                    // Draw the circle on top
                    scope.context.arc(xPosition, yPosition, radius * scope.horizontalPixelRatio, 0, Math.PI * 2);
                    scope.context.fill();
                }
            }
        }

        // Lollipop Series class
        class LollipopSeries {
            constructor() {
                this._renderer = new LollipopSeriesRenderer();
            }

            priceValueBuilder(plotRow) {
                return [0, plotRow.value];
            }

            isWhitespace(data) {
                return data.value === undefined;
            }

            renderer() {
                return this._renderer;
            }

            update(data, options) {
                this._renderer.update(data, options);
            }

            defaultOptions() {
                return {
                    lineWidth: 2,
                    color: 'rgb(0, 100, 255)',
                };
            }
        }

        // Create the chart
        const chart = createChart(document.getElementById('chart'), {
            width: window.innerWidth,
            height: 500,
        });

        // Add Lollipop series to chart
        const customSeriesView = new LollipopSeries();
        const myCustomSeries = chart.addCustomSeries(customSeriesView, {
            lineWidth: 1,   // Make lines thinner
            color: 'rgb(0, 200, 255)',  // Lollipop color
        });

        // Generate random data for the Lollipop series
        function generateLollipopData() {
            const data = [];
            let baseTime = new Date('2021-01-01').getTime() / 1000; // Unix timestamp in seconds

            for (let i = 0; i < 50; i++) {
                const value = Math.random() * 300;  // Use a wider value range
                data.push({
                    time: baseTime + i * 60 * 60 * 24, // Increment by 1 day
                    value: value,
                });
            }
            return data;
        }

        // Set Lollipop data
        const lollipopData = generateLollipopData();
        myCustomSeries.setData(lollipopData);

        // Update chart size on window resize
        window.addEventListener('resize', () => {
            chart.applyOptions({ width: window.innerWidth });
        });
    </script>

@vishnuc
Copy link
Author

vishnuc commented Oct 23, 2024

@SlicedSilver : hi can you please tell is this right way to do in vanilla js ? how does it works without fancy-canvas ? does lightweight library i build contains fancy-canvas already ?

@SlicedSilver
Copy link
Contributor

There are a few different builds of the library. The 'standalone' version includes fancy-canvas bundled and you should use this if you aren't using a build or bundle tool.

Plugins themselves don't specifically require fancy-canvas. Some example might use imports from fancy canvas but this would be for the 'types' and these imports wouldn't be in the actual generated JS code.

@vishnuc
Copy link
Author

vishnuc commented Oct 23, 2024

Thanks I am using normal 160kb version and everything works fine..when can we expect next version .. any roadmaps ?

@SlicedSilver
Copy link
Contributor

SlicedSilver commented Oct 24, 2024

We don't share timelines but we are actively working on the next release. There is a 5.0 milestone.

@vishnuc
Copy link
Author

vishnuc commented Oct 24, 2024

so next release is 5 directly or something like 4.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants