⚡ Sangsakala Proxy 🏠 Home
Skip to content

Allow inverting series highlight behavior: change only color/alpha of the hovered series #990

Open

Description

@juliusv

When focusing a series by hovering, the focus.alpha setting allows you to de-emphasize all other series by adding transparency to them. I find that effect a bit too visually jarring and would like to achieve the opposite, where only the series that is currently focused gets emphasized somehow, while all others keep their style. Ideally the emphasis wouldn't be alpha-based (since alpha is already 1), but would allow me to change the color or width of the series.

Activity

  1. juliusv commented on Aug 21, 2024

    @juliusv
    Author

    The one way I got this working with the current uPlot is by remembering the selected series index with a setSeries hook like this:

      let selectedSeriesIdx: number | null = null;
    
      // ...
    
          setSeries: [
            (u: uPlot, seriesIdx: number | null, _opts: Series) => {
              if (seriesIdx === selectedSeriesIdx) {
                return;
              }
    
              if (selectedSeriesIdx !== null) {
                u.series[selectedSeriesIdx].width = 1.5;
              }
              if (seriesIdx !== null) {
                u.series[seriesIdx].width = 2.2;
              }
              selectedSeriesIdx = seriesIdx;
              u.redraw();
            },
          ],

    However, the required full redraw makes hovering sluggish when there are many series, so I probably won't be able to use this solution.

  2. leeoniya commented on Mar 8, 2025

    @leeoniya
    Owner

    yeah, this is the way that https://leeoniya.github.io/uPlot/demos/focus-cursor.html is implemented.

    there's no getting away from full redraw (nvm, i missed that you manually triggered redraw). but the paths are not re-generated, so it shouldnt be horribly expensive just to clear the canvas and re-paint the cached Path2Ds.

    do you have a demo or jsFiddle that shows the slowness?

    related: #787

    that being said, it probably makes sense to have an api for cursor.focus that does not require the user externally remembering the original line width / style / stroke / fill.

  3. leeoniya commented on Mar 9, 2025

    @leeoniya
    Owner

    that being said, it probably makes sense to have an api for cursor.focus that does not require the user externally remembering the original line width / style / stroke / fill.

    so, i started down this path in https://github.com/leeoniya/uPlot/tree/focus-styles, and it ends up being more complex than i think is worth it.

    mutating the series widths works well, and you don't have to call redraw again. see how it's done below. you can set focus.alpha: 1 as well.

    hooks: {
    setSeries: [
    (u, seriesIdx, opts) => {
    if (opts.focus != null) {
    console.log("focus!", seriesIdx, opts);
    u.series.forEach((s, i) => {
    s.width = i == seriesIdx ? 2 : 1;
    });
    }
    }
    ]
    },

    this mutation strategy will also work for series.dash and series.cap, since these have no callback signature and are used directly by the renderers.

    if you want to do have focus-dependent series.stroke or series.fill, you will have to provide callbacks for these options that return the color you want. you can use the u.series[seriesIdx]._focus boolean for the condition.

  4. leeoniya commented on Mar 9, 2025

    @leeoniya
    Owner

    ok, i tried it out and yeah, if the focus.alpha: 1 it will bail out of redraw. so you do need the manual u.redraw(false) call. the false argument will prevent it from regenerating the series paths, so is very fast. i added a demo in d1f7abb.

    hooks: {
    setSeries: [
    (u, seriesIdx, opts) => {
    if (opts.focus != null) {
    u.series.forEach((s, i) => {
    s.width = i == seriesIdx ? 2 : 1;
    });
    u.redraw(false);
    }
    }
    ]
    },

    you'll notice that the mutation strategy leaves the series points and hover points (in the dom) not changing size. also the hover point does not change color until you move to another x index. mutating series.points.width also isnt so straightforward.

    maybe in the future we can make use of Canvas shadow properties:

    ctx.shadowColor = "red";
    ctx.shadowOffsetX = 5;
    ctx.shadowOffsetY = 5;
    ctx.shadowBlur = 1;
    

    i'm afraid there's no straightforward solution here. as much as i want to help, this is the first time in 5 years this request has come up, and the juice just isn't worth the squeeze.

  5. leeoniya commented on Mar 9, 2025

    @leeoniya
    Owner

    thinking about it even more, it's not enough to change style/width/color. you would also have to change its rendering order, otherwise it would be occluded by 100 other line series.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions