Making a little chart app lazarus / 39-Graphics ---------------------------------------------------------------------- phoenix27 · 2023-06-01 13:28 I'm making a little chart app(candle chart to be precise and no , i don't wanty to use TAchart, i like to make things myself, well if it's not too complicated of course...). This is the relevant code Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure Chart.drawChartToBmp;var  i:integer;  d:array of double;  x:double;  offset:double;  drawOnlylowhigh:boolean=false;  cw:single;begin     cw:=fxmax / (fend-fstart);     if cw < 2 then         drawOnlylowhigh:=true;     offset:= cw * 0.40;   chartBmp.Canvas2D.clearRect(0,0,w,h);   chartBmp.Canvas2D.lineWidth:=1;   for i:=fstart to fend do begin      chartBmp.Canvas2D.beginPath();      d:= fdata[i];      if d[4] > d[1] then begin //close > open        chartBmp.Canvas2D.strokeStyle (green);        chartBmp.Canvas2D.fillStyle (green);      end      else if d[4] < d[1] then begin        chartBmp.Canvas2D.strokeStyle (red);        chartBmp.Canvas2D.fillStyle (red);      end      else  begin        chartBmp.Canvas2D.strokeStyle (white);        chartBmp.Canvas2D.fillStyle (white);      end;      x:=q2x(d[5]);    chartBmp.Canvas2D.moveTo(x, q2y(d[3])); //low      chartBmp.Canvas2D.lineTo(x, q2y(d[2])); //high      if not drawOnlylowhigh then begin        chartBmp.Canvas2D.moveTo(x-offset, q2y(d[1]));//open        chartBmp.Canvas2D.lineTo(x + offset, q2y(d[1]));         chartBmp.Canvas2D.lineTo(x + offset, q2y(d[4]));//close        chartBmp.Canvas2D.lineTo(x - offset, q2y(d[4]));      end;      chartBmp.Canvas2D.closePath();      chartBmp.Canvas2D.stroke();      chartBmp.Canvas2D.fill();   end;end; Then i call invalidate and paint chartBmp on the screen.  Now, let's say i want add another feature(and i will!!) such as real time,so that everytime a new price comes in a draw another candle,  based on some timeframe. Of course there is the procedure Canvas2D.clearRect() with which i can erase just the last candle and repaint it. Right? But what if i want to add an horizontal line going through all the chart, plus a price tag to show where the new  price is. Should i erase the whole chart and repaint it just to draw a line a nd a price tag? Isnt that unefficient? I dont understand well this canvas thing. To change a detail(such as a line) i should repaint the whole chart? ---------------------------------------------------------------------- phoenix27 · 2023-06-01 14:31 Also, imagine i want to add the ability for the user(me ahaha) to draw trendlines. I have to draw them on the chartBmp bitmap right? Together with the code needed to draw all the candles, which means everytime everything has to be redrawn. Is it possible? Am i missing something here? Or is it supposed to be this way?  In javascript, if i remember well, canvas seems to be persistent. I dont have to draw in a special method called by the OS or whatever. So if i want to add a trendline on the chart or something else i dont have to redraw everything. How can i do it in pascal efficiently? Anybody knows? ---------------------------------------------------------------------- wp · 2023-06-01 20:59 Quote from: phoenix27 on June 01, 2023, 03:28:04 pmCanvas2D.clearRect() with which i can erase just the last candle and repaint it. Right? But what if i want to add an horizontal line going through all the chart, plus a price tag to show where the new  price is. Should i erase the whole chart and repaint it just to draw a line a nd a price tag? Isnt that unefficient? It depends... Of course you can erase an individual candle by Canvas2D.ClearRect. This works fine when there is nothing else in the cleared rectangle. If there is, such as another line or the axis grid, it is easier to erase the entire chart and redraw everything. Unless you have millions of data points you will not notice any delay. Quote from: phoenix27 on June 01, 2023, 03:28:04 pmI dont understand well this canvas thing. Imagine you are a painter and have a canvas in front of you and paint on this canvas - it's the same here: the Canvas is surface on which you are painting using pens and brushes. BUT: There are several kinds of canvases. A Paintbox, for example, is a control which is designed for user painting. It provides you with a canvas but this canvas is not necessarily persistent. Imagine that it only "exists" during the painting cycle, i.e. in the OnPaint event of the Paintbox (similar with TForm or TPanel). So rather than painting in the OnClick event of a button Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TCanvas);begin  Paintbox1.Canvas.Line(0, 0, Paintbox1.Width, paintbox1.Height);end;you should always paint in the OnPaint event handler: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Paintbox1Paint(Sender: TCanvas);begin  Paintbox1.Canvas.Line(0, 0, Paintbox1.Width, paintbox1.Height);end; Why? Because the canvas always must be able to redraw itself at any time requested. When you paint in the OnClick event the drawing probably does appear, but when the user temporarily drags another window over your drawing the Paintbox is forced to redraw itself - but the code of the OnClick event is no longer available, and your drawing will be erased. In your special case, however, things are different since you seem to be painting on the canvas of a bitmap. This kind of canvas is not linked to a control and is always existent. You can draw on it at any time, and the pixels that you change this way will remain changed. But you must not forget to copy the bitmap onto the canvas of the control on which you want to see your drawing. And, of course, you do this on the OnPaint event of the control: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.PaintboxPaint(Sender: TObject);begin  Paintbox1.Canvas.Draw(0, 0, Your_Bitmap);end;And to trigger the OnPaint event you call the control's Invalidate method: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);begin  YourBitmap.Canvas.Line(0, 0, YourBitmap.Width, YourBitmap.Height);  Paintbox1.Invalidate;end; ---------------------------------------------------------------------- phoenix27 · 2023-06-05 07:50 Thank you for your answer. I thnk i understand it better now. ---------------------------------------------------------------------- circular · 2023-06-08 11:23 A little detail, the line chartBmp.Canvas2D.closePath(); would make more sense to be moved up one line, inside the begin/end. Indeed, closePath closes the current polygon. Note that you don't always need to call closePath for each beginPath. In fact, it would be better to call it closeSubPath but I've used the same name as in HTML5 canvas. ---------------------------------------------------------------------- phoenix27 · 2023-08-24 03:03 Right circular. Sorry i didn't read your reply before because i don't get notified so after a while i even forget my own posts. Anyway i can't get past the problem i talked about. If in the mousemove event i add, when the control key is down, an horizontal and vertical line which then follow the mouse pointer around, the drawing becomes slow because every time it has to make the chart again. But the only thing changing is the 2 lines, whereas the chart candles don't change. Imagine hundreds of little candles being created again and again while the mouse is moving, of course it will slow down the whole thing(see the image). So is there a way to separate the chart itself from the lines and other graphic annotations i could add later? ---------------------------------------------------------------------- phoenix27 · 2023-08-24 12:35 I solved by putting the code regarding the lines in the paint event, ahahha, so simple, why before i put it in the chartBmp... mahh: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TChart.chartAreaPaint(Sender: TObject);var  cnvs: TCanvas;begin  cnvs := chartArea.Canvas;  chartBmp.Draw(cnvs,0,0,True);  volBmp.Draw(volArea.Canvas, 0, 0, true);  cnvs.Pen.Color:=clwhite;  cnvs.Line(0, cy, cnvs.Width, cy);  cnvs.Line(cx, 0, cx, cnvs.Height);end; ---------------------------------------------------------------------- circular · 2023-08-24 19:03 That's indeed a way to do it efficiently. Congrats