Open vishnuc opened 1 month ago
use an id for price scale :
const volumeSeries = chart.addHistogramSeries({
color: '#26a69a',
priceFormat: {
type: 'volume',
},
priceScaleId: 'rightVolume',
}, 1);
chart.priceScale('rightVolume').applyOptions({
autoScale: false,
scaleMargins: {
top: 0.9,
bottom: 0,
},
});
If i set priceScaleId: 'rightVolume', , I am not able to scale by dragging its pricescale.. also when i hover the volume its not displaying price label on right side.
If i set priceScaleId: 'rightVolume', , I am not able to scale by dragging its pricescale.. also when i hover the volume its not displaying price label on right side.
As I understand it, if you want to have full control over the volume, the best approach is to build a plugin, or you can use a secondary overlay canvas or a second price scale at the left
sorry , I am not a professional to build plugin..Also i want both price and volume scale on the right, thats why using the pane.
so can you tell me about secondary overlay canvas ?
sorry , I am not a professional to build plugin..Also i want both price and volume scale on the right, thats why using the pane.
so can you tell me about secondary overlay canvas ?
as i am a fan of pure js i created a plugin for lightweight chart. you can see the concept and use it : https://github.com/safaritrader/lightweight-chart-plugin
wow , thanks i was thinking to create volume profile for my project , but did u extend version 4 or 5 ..i need multi pane support.
wow , thanks i was thinking to create volume profile for my project , but did u extend version 4 or 5 ..i need multi pane support.
your welcome. i am expanding that plugin frequently. it's based on v 4.2.0
ok , then I want to build plugin for my v5 , can you guide me with any basic tutorials ? there is no documentation in TV how to create a plugin from scratch.
I am coding vanilla js for past 8 years.. since there was no use for constructor , canvas I did not learn , but I am willing to learn now .. can you tell me what should I learn ? because I am new to constructor , canvas etc ..
is there a skeleton or template that i must follow to create plugin from scratch and how it works.
ok , then I want to build plugin for my v5 , can you guide me with any basic tutorials ? there is no documentation in TV how to create a plugin from scratch.
I am coding vanilla js for past 8 years.. since there was no use for constructor , canvas I did not learn , but I am willing to learn now .. can you tell me what should I learn ? because I am new to constructor , canvas etc ..
is there a skeleton or template that i must follow to create plugin from scratch and how it works.
As i know the last version for lightweight charts is 4.2
ok there is another branch named 5 , you can use that to checkout multi pane feature - https://github.com/tradingview/lightweight-charts/tree/v5-candidate
btw please tell me what should I learn , or any tutorials from scratch to create one simple plugin
ok there is another branch named 5 , you can use that to checkout multi pane feature - https://github.com/tradingview/lightweight-charts/tree/v5-candidate
btw please tell me what should I learn , or any tutorials from scratch to create one simple plugin
Official Library suggest to do that : https://github.com/tradingview/lightweight-charts/tree/master/packages/create-lwc-plugin which i am working with pure js and its not fitting my requirements and im using overlay canvas which i described in my Lightwight charts plugin. its very simple when you read you will learn!. the main approach of mine is to use another canvas over the lwc canvas and do every thing you want
Ok I am reading your code now. along with chatgpt help
On Wed, 16 Oct, 2024, 4:17 pm Hassan Safari, @.***> wrote:
ok there is another branch named 5 , you can use that to checkout multi pane feature - https://github.com/tradingview/lightweight-charts/tree/v5-candidate
btw please tell me what should I learn , or any tutorials from scratch to create one simple plugin
Official Library suggest to do that :
https://github.com/tradingview/lightweight-charts/tree/master/packages/create-lwc-plugin which i am working with pure js and its not fitting my requirements and im using overlay canvas which i described in my Lightwight charts plugin. its very simple when you read you will learn!. the main approach of mine is to use another canvas over the lwc canvas and do every thing you want
— Reply to this email directly, view it on GitHub https://github.com/tradingview/lightweight-charts/issues/1709#issuecomment-2416441546, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQ5HCSFGTVALQBKU4NOK3TZ3Y75TAVCNFSM6AAAAABP4OUWBWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIMJWGQ2DCNJUGY . You are receiving this because you authored the thread.Message ID: @.***>
Hey @safaritrader I saw plugin use fancy-canvas etc , how did u overcome all those things using vanilla js.
Hey @safaritrader I saw plugin use fancy-canvas etc , how did u overcome all those things using vanilla js.
Hi Dear @vishnuc Sometimes a simple solution is faster for achieving the desired outcome, plus I tested that plugin on 3 million data points for volume profile, and it worked perfectly. I try not to get too caught up in complexities and aim to reach my goal with the simplest approach. However, there are still some small bugs that I'll fix in the next update. Since I work with large datasets, I need to make sure the code can handle at least 10 million data points. One of the good features of this plugin is that it doesn’t require extensive expertise to modify or rewrite.
hi , but I compiled and run your example.. its not fluid when i scale price axis .. native plugins are way smoother...also when time axis is scaled I think you redraw after certain interval.
hi , but I compiled and run your example.. its not fluid when i scale price axis .. native plugins are way smoother...also when time axis is scaled I think you redraw after certain interval.
its depend on your data scale. for now its loop through all data but im replacing a simple algorithm to not loop through all data in next version and its depend on your browser also it take 5 sec to build a volume profile from 3m data (tested in firefox). other plugins are using lightweight chart built-in feature's which is great but not fit my requirements
hi , i succeeded creating primitive with pure js , its smooth . now working on series , will update you.
<script >
class AnchoredTextRenderer {
constructor(options) {
this._data = options;
}
draw(target) {
target.useMediaCoordinateSpace((scope) => {
const ctx = scope.context;
ctx.font = this._data.font;
const textWidth = ctx.measureText(this._data.text).width;
const horzMargin = 20;
let x = horzMargin;
const width = scope.mediaSize.width;
const height = scope.mediaSize.height;
switch (this._data.horzAlign) {
case 'right':
x = width - horzMargin - textWidth;
break;
case 'middle':
x = width / 2 - textWidth / 2;
break;
}
const vertMargin = 10;
const lineHeight = this._data.lineHeight;
let y = vertMargin + lineHeight;
switch (this._data.vertAlign) {
case 'middle':
y = height / 2 + lineHeight / 2;
break;
case 'bottom':
y = height - vertMargin;
break;
}
ctx.fillStyle = this._data.color;
ctx.fillText(this._data.text, x, y);
});
}
}
class AnchoredTextPaneView {
constructor(source) {
this._source = source;
}
update() {}
renderer() {
return new AnchoredTextRenderer(this._source._data);
}
}
class AnchoredText {
constructor(options) {
this._data = options;
this._paneViews = [new AnchoredTextPaneView(this)];
}
updateAllViews() {
this._paneViews.forEach(pw => pw.update());
}
paneViews() {
return this._paneViews;
}
attached({ requestUpdate }) {
this.requestUpdate = requestUpdate;
}
detached() {
this.requestUpdate = undefined;
}
applyOptions(options) {
this._data = { ...this._data, ...options };
if (this.requestUpdate) this.requestUpdate();
}
}
// Create the chart
const chart = LightweightCharts.createChart(document.getElementById('chart'), {
width: window.innerWidth,
height: 500,
});
// Add a line series
const lineSeries1 = chart.addLineSeries({},0);
const data1 = [
{ time: '2024-01-01', value: 120 },
{ time: '2024-01-02', value: 130 },
{ time: '2024-01-03', value: 125 },
{ time: '2024-01-04', value: 135 },
{ time: '2024-01-05', value: 140 },
];
lineSeries1.setData(data1);
// Add a line series
const lineSeries = chart.addLineSeries({},1);
const data = [
{ time: '2024-01-01', value: 120 },
{ time: '2024-01-02', value: 130 },
{ time: '2024-01-03', value: 125 },
{ time: '2024-01-04', value: 135 },
{ time: '2024-01-05', value: 140 },
];
lineSeries.setData(data);
// Add Anchored Text
const anchoredText = new AnchoredText({
vertAlign: 'middle',
horzAlign: 'middle',
text: 'Anchored Text',
lineHeight: 54,
font: 'italic bold 54px Arial',
color: 'green',
});
lineSeries.attachPrimitive(anchoredText);
// Change the text after 2 seconds
setTimeout(() => {
anchoredText.applyOptions({
text: 'New Text',
});
}, 2000);
// Update chart size on window resize
window.addEventListener('resize', () => {
chart.applyOptions({ width: window.innerWidth });
});
</script>
ok series too works fine with pure js , why dont u use like this in ur plugin,.. so even when u scale it will look good.
<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>
ok series too works fine with pure js , why dont u use like this in ur plugin,.. so even when u scale it will look good.
<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>
that using for loop for redraw too which cant make a different for my current plugin. its executing redraw on resize and changing scales too it just using less code to attach custom shapes or series which is good
No yours is not giving native feel , I am checking in my macbook retina..Its easy I think u can create lots of plugin with native way with vanilla js.
also if i scale my pricescale up and down urs is hiding the volume profile etc
hi , I am testing out v5-candidate with multpane , I added volume series to new pane via
now if i want to scale this volumeseries , it is also scaling the pane 0 price series.
Its expected to fit / scale only pane 1 as the series is in pane1