leeoniya / uPlot

📈 A small, fast chart for time series, lines, areas, ohlc & bars
MIT License
8.48k stars 370 forks source link

UI is overlapping and not sized correctly #899

Closed MengLinMaker closed 5 months ago

MengLinMaker commented 5 months ago

I'm experiencing strange UI overlapping issues. The y axis is not showing either. Do you have any insights into what could be happening?

I've tried to resize the canvas with CSS, but the y axis is still gone. Plus the graph will no longer fill up the element (obviously).

image

My uPlot setup is quite basic. The element provided to uPlot is an HTMLDivElement from Solid.js ref.

I'm using very minimal uPlot.Options + element resizing.

let opts: uPlot.Options = {
  width: 100,
  height: 100,
  series: [
    {},
    {
      label: 'Unit price',
      stroke: 'red',
      scale: "$",
    },
  ]
}
leeoniya commented 5 months ago

can you make a jsfiddle that reproduces the issue? like https://jsfiddle.net/0bvks7cw/1/

MengLinMaker commented 5 months ago

JS Fiddle with Solid.js: https://jsfiddle.net/MengLinMaker/e6hcog4u/355/

But actually, I don't think this is a framework issue: I replicated the issue with vanilla HTML, CSS and JS: https://jsfiddle.net/MengLinMaker/pfe7y34w/31

The uPlot chart overflows outside the element it's attached to:

image

Even if I made set element height to 100px, it still overflows.

Tested on:

leeoniya commented 5 months ago

ok, a bunch of things going on here.

first, you're missing the css file <link rel="stylesheet" href="https://leeoniya.github.io/uPlot/src/uPlot.css">

once you add this, it gets you here:

image

obviously a 100x100 plot cannot fit two axes with tick labels as well as a plot legend. i am not sure what result you are actually trying to achieve. if you want something like sparklines, you can disable a bunch of stuff to make it work: https://leeoniya.github.io/uPlot/demos/sparklines.html

image

next, uPlot's dimensions are only for the plotting area and exclude the legend, which is in HTML. you can detach and place this legend outside of the container using the legend.mount callback:

https://github.com/leeoniya/uPlot/blob/aea27cafd41acfb3ca77a97ec2092ebddf067de4/dist/uPlot.d.ts#L285-L286

uPlot has no ability to auto-size to its container (it knows nothing about its external environment). you should measure the container/available space before initializing and mounting uPlot with the defined size. you can then keep the size in sync by using the u.setSize() API, and an event listener or ResizeObserver.

https://github.com/leeoniya/uPlot/blob/aea27cafd41acfb3ca77a97ec2092ebddf067de4/demos/resize.html#L75-L77

finally, the y axis disappears because uPlot's Y auto-ranging logic does not take into account its tick-gen strategy. it currently adds 10% to the raw data range and then tries to place the best ticks on whatever that ends up being. at small panel heights this can result in 1 tick or even no ticks. i intend to fix this soon, but it requires changing quite a lot of internal plumbing.

you can define your own y auto ranging function or set a static y range using the scale.range option.

https://jsfiddle.net/ecm7qo1t/

image

MengLinMaker commented 5 months ago

Thank you, that's solves the UI problem. The setup is a little confusing

This library is exactly what I'm looking for:

I guess I'm my case, since I installed uPlot via npm, I'll need to; import 'uplot/dist/uPlot.min.css'

With legend.mount I just need to append the element to a HTMLDivElement