6pac / SlickGrid

A lightning fast JavaScript grid/spreadsheet
https://github.com/6pac/SlickGrid/wiki
MIT License
1.82k stars 422 forks source link

Rowspan #381

Closed MrMoronIV closed 5 years ago

MrMoronIV commented 5 years ago

I would really like to have rowspan to span the first cell of one row over multiple rows, it seems like this is not supported at the moment or am I missing something? If not, are there any plans to have this implemented?

MrMoronIV commented 5 years ago

In addition, I found this thread about it (from 2013): https://stackoverflow.com/questions/9880178/how-do-i-create-merged-cells-in-slickgrid

Where this fork is mentioned: https://github.com/GerHobbelt/SlickGrid/tree/k0stya-rowspan

However, I assume that code can't just be copy pasted without breaking existing functionality of this main branch.

6pac commented 5 years ago

I think this is too specialised to be on our list of plans for the grid. There is a DetailsView plugin (see the examples) which merges several whole rows, but I think that's all you'll get.

MrMoronIV commented 5 years ago

Thanks for the clarification. DetailsView only puts a div over several dynamically created empty rows below the clicked row, so no merging there either.

EfremBraun commented 2 years ago

Just want to let you know that this feature request would also be very helpful for my own application (I figure that maybe if you see a lot of users wanting this feature you might change your mind about implementing it; regardless, thanks for the great work you do!).

ghiscoding commented 2 years ago

to which I'll reply the same as this other comment shown below... This is an Open Source project, the best way to get it done is for you to contribute.

That was possible in another fork GerHobbelt/SlickGrid fork. I'm not sure if it's feasible with our fork since we now have the frozen feature, which I don't think GerHobbelt has, so it might or might not be doable, but it would be nice to have the following. I did not look at the code at all, I just clone his repo and looked at all the samples he has (a lot of them). That would be really great if you can make it working and contribute with a new Example. Thanks

GerHobbelt commented 2 years ago

to which I'll reply the same as this other comment shown below... This is an Open Source project, the best way to get it done is for you to contribute.

👍 I second that!

That was possible in another fork GerHobbelt/SlickGrid fork. I'm not sure if it's feasible with our fork since we now have the frozen feature, which I don't think GerHobbelt has, so it might or might not be doable, but it would be nice to have the following.

I had frozen columns, but I do not recall from memory if that feature was in the same branch. Might be it's only brought together in the specialized commercial work I did. My memory is fading...

Just couple of notes on all this:

  1. I'm not working on SlickGrid ATM and haven't for several years. I'm just following the development of one of my old loves 💘 from the corner of my eye, so to speak.

    There's plenty other stuff on my plate and I haven't been able to purchase a cloning machine that gets me a copy of myself without a mind of his own, so I can get him to do all the jobs I still haven't done. 😉 Ergo: don't wait for me or anyone else, if you want it, get crackin'. I did. I do. You can do too!

  2. @6pac and @ghiscoding have continued working on and maintaining SlickGrid, which is, if I am any judge, still at the top of the grid pageant contenders list in the whole of HTML/Web County -- and I've been looking at quite a few of them over the years. It's a quality product. And I applaud these gentlemen's stamina. Gentlemen, I salute you!

  3. Let's consider what it means to have these features, UI/UX and technology-wise (and we'll consider MS Excel alongside):

    • Suppose you have merged columns. Ok.
    • Next thing you'll want is symmetry, hence merged rows too. The referenced GH branch has those. Ok.
    • How does that impact 'frozen columns' (and/or 'frozen rows') from a UX/UI perspective? (We'll forget technological feasibility for now)
      • take the screenshot in the comment above: if you freeze up to Duration, you're golden. Ditto for all frozen up to (& including) Finish.
      • Things immediately get pretty hairy when you freeze up to (& including) column Start: the consequence of that is you having a frozen merged cell range (the green stuff) sticking out.
    • How does that impact 'frozen columns' (and/or 'frozen rows') re technological implications now? (Oh boy. 😵‍💫)

      • Technically, that would be doable in MS Excel, as MS Excel directly uses the Win API (GDI) and can, with effort, exert precise control. You don't have that level of control over your UI render as it's abstracted by the HTML+CSS layer. You can get close, but it won't be the same at all, performance-wise!

      • How about HTML+CSS? This wasn't really doable back in '12/'13 and it still isn't.

      Which will have you say:

      Yo! That's not true! I can create a sample HTML+CSS page where you can see it work like that!

      Right. Great job with the hand-coded sample page. 👍 Now, have you tried using your CSS tricks in conjunction with large and huge grids, i.e. any grids that are big enough to require the Virtual Table functionality (that underpins SlickGrid) as it is sorely needed for performance (UX: scroll speed, responsiveness, ...)?

      Back in '13 this was not doable, period. I know I've tried, and looked at others who I'ld expect to be smarter than me in this. This could not be done then, unless you accepted some very particular requirements, e.g. never accepting a freeze on a column or row which is crossed (intersected) by any merged cell block.

      Important: when I say "not doable" anywhere here, I specifically mean: not doable as a generic grid without peculiar restrictions: it has been done (with some effort!) and can be done when you stick with the aforementioned peculiar requirement. You will, however, land yourself in a world where no grid will ever be simple any more. Read: (severely) heightened maintenance costs.

      Why? Because only then do you still have a single frozen rectangle area across your entire grid (that's including all the rows and columns that are currently not visible on screen -- be reminded: all this is easy to do (sort of) for small grids; SlickGrid et al -- and my particular interest -- is all about large and bloody huge grids. In a web browser serving as your render engine and user feedback system.

      Today, we've got CSS3 enhancements, such as sticky (see https://elad.medium.com/css-position-sticky-how-it-really-works-54cd01dc2d46, for example), which I did not have in '13. All modern browsers support that CSS feature. fixed, position: absolute et al are nice, but did not pan out in a virtual table setting, not without some flickering and jumping around when the CPU load gets heavy, and I have not checked, but I guess that sticky might just be good enough to make this combo of merged cells and frozen columns work, theoretically.

      I hope you noted the above couple paragraphs are theoretical musings, because in practice, it's still quite similar to back in '13, due to other technical choices made: all grids I looked at, including SlickGrid, which offer a smooth & responsive 'frozen columns' feature, do this the same way: the frozen part is a a lot of cells in a separate rectangle that's fixed to the left side of the gird area and positioned on top of the rest of the grid so that the scrolling area moves underneath, producing the 'frozen columns' experience. They all do that either by rendering two synchronized grids, where one is fixed to the left and using a bit of HTML <div>+CSS to place it on top of the other grid, or they use an HTML <table> and have that one split into two <table>s and render output into those to get the 'one layered over the other' UI/UX.

      Yes, I'm (over)simplifying there. But if you go through their source codes, you'll find that all of them do render the 'freeze' feature at table level, rather than at the individual cell level.

      At least none of the grids that are still performant & responsive under load.

      Back then, I was looking for ways to get a 'column pinning' feature into SlickGrid, which is kind of like taking the 'frozen column' idea and feeding it meth for breakfast, and I did try but failed. The 'pinned columns' idea I had in mind is theoretically doable today using CSS sticky & friends, but I never did, because... ⌚ and thus 💲💲💲 cost of such a feature: it would be cool, quite useful for the grids I was working on, but from a coding cost perspective... (censored).

      If anyone is ever going to try their hand at it, then SlickGrid (or a simile thereof) is a good design to base that work on.

      Bottom line: all those grids always have the frozen part be a single rectangle area that's got special treatment and no cells sticking out there anywhere! --> hence the anno 2021 still present condition of this combo only being able to work when you never freeze a column (or row) that's intersected by a merged cell. Never evar.

      The CSS sticky idea (that I did not describe in detail) is to do this another way: SlickGrid is powerful enough to accomplish this in a truly generic way, I think, but it'll be pretty hard to pull off if you want to freeze column Start and want to see that green merged cell being frozen and sticking out -- I've looked at this approach in '13/'14 but it was too hard to do then (and probably now still) as it requires you to completely throw away and redo the 'frozen' feature: that one then must be done on a by-cell basis, so the SlickGrid grid render code would have to be changed to render frozen cells and regular cells as a single grid, where each individual 'frozen cell' has to be made sticky. That 's the basics of the idea, at least, but you can bet your bottom it'll be a major effort to pull it off -- and I myself never got further than a PoC with CSS fixed that had too many peculiarities and a horrible performance, so I let it go.

      • The GerHobbelt fork has (had?) other enhancements, including an, ah, "adaptive" render engine which would only render a few cells at a time while monitoring user behaviour. It was engineered to quickly follow the user's scrolling position at all times: when the CPU load gets heavy and a user quickly scrolls to another area in the grid, e.g. by dragging the scroll slider, then the render action is aborted ASAP as the render cost of cells that are not relevant any more is high, now useless and causing serious lag in the UI. The adaptive grid renderer would only render a few rows between checks for grid position updates, so we wouldn't be painting lots of useless <div>s while a user scrolls wildly through the huge grid. (That stuff sits in master IIRC, but don't expect that one to work out of the box today. Sorry.)

      Here, merged cells, while very nice visually for some types of grid, add render cost, if only a little. (But multiple a little by many-cells-in-view and it's not so little any more.) With merged cells, your renderer has to become smarter about the virtual viewport into the grid: with regular cells, you can mathematically determine which cells will be visible, partly or whole, and address each. That's fast.

      Merged cells add complexity there: you now have to do more work in the 'which cells do we need to render' section: when you have calculated that a cell X is in-view, it may be part of a merged cell and, given that a merged cell can have any size and be anywhere inside/outside/on-the-edge-of your viewport, you'll need to come up with some smart stuff, e.g. mark up each cell to signal it's part of a merged collective and what the corners of that collective are, because now, all of a sudden, those corners of the merged block determine whether it's to be painted in the viewport, rather than the cell itself.

      @k0stya was one of the few people who did the heavy lifting for that and it's his work I took, tested, liked and added onto. It's doable, merged cells and frozen columns together, as long as you stick to the rule that the edge of the frozen area may not ever be intersected by a merged cell.

      The fun then really starts, because that SlickGrid implementation (and any nice grid with such a feature), of course, allows you to merge cells live, i.e. the status of a cell (merged/single) can change during its lifetime.

      If that doesn't raise a few hairs with you, when you consider maintaining a generic grid, then you're made from stronger stuff than yours truly, as I can already feel the user bug reports streaming in. My conclusion: great stuff, super cool, great UX when you pull it off, but maintain it at end-application level and blithely close as 'will not fix' any issues that pop up due to peeps merging cells that happen to cross that freeze boundary. (Which still makes this a very much non-zero maintenance cost, for you first have to check those bug reports and conclude that it's due to frozen-edge crossing, once again) -- next to the extra effort in your grid API to check cell merges against this rule and barfing a hairball back to the application programmer for him to handle by, f.e., showing an error/info dialog telling the user "Sorry, no can do. Not here anyway."


Sorry, got onto a bit of a soapbox rant there. It's still vivid after all these years. 😄

I hope to be able to revisit SlickGrid one day and see if some of my own doodads are still useful or need redoing another way then, but don't bet on that happening anytime in your lifetime. 😉

To close on a happy and positive note: I was able to pull it off, with the great help of other SlickGrid forks and people. So you can too!

Oh, before y'all go! When I say I had great help from others, I meant: I went looking, checked & compared the code in various forks & revisions, blatently stole merged/purloined what I liked as I found it in there anywhere and went on my merry way. I did not beg and wait for them to do my bidding, but acted instead. Just a generic so-you-know-how from an old curmudgeon. 😉

The truly tough part is keeping at it for a decade, which is why I have great respect for @6pac, @ghiscoding and the others that are still around and active! 👍👍👍

GerHobbelt commented 2 years ago

In case you wonder about MS Excel (which would be considered The Reference for this sort of thing): it has nasty behavioural quirks too. And that's Excel 2019 we're talking about!

Watch the vid where I move around and (try to) edit a merged cell. Notice that Excel splits the cell and does an (awkward) double render of the thing, live-updating the second copy while the edited cell is clipped to the frozen rectangle area. Not nice, pretty confusing. Not having these or other weird artifacts would mean SlickGrid would do it better than MS Excel (and thus the MS dev team).

Also note their scroll bug when I move from right to left into the frozen zone through the merged cell: watch column C not showing up and thus the merged cell render remaining clipped. I consider that a UI bug. (Which would be very similar to the problems SlickGrid and others would be facing with this, BTW.)

Enjoy the vid of the keyboard walk in Excel:

https://user-images.githubusercontent.com/402462/138865939-b0623b30-6eb1-4377-bf38-2b0cef6c4cff.mp4

TL;DR: mixing frozen columns with merged cells is a... challenge! 😉

ghiscoding commented 2 years ago

wow a reply coming directly from @GerHobbelt in person, it's really nice to hear from you. I loved all your huge set of examples and took a look at them multiple times, I admit that I also copied a lot of your code here & there to merge in here as well 😉

I agree that it's hard to keep an Open Source project active for so many years, thanks to @6pac for sticking around for so long and helping with this fork for so many years. We use it at work which is why I contributed, in here and in my multiple SlickGrid wrapper libs, so many new features and bug fixes. I often say/think that if you really want a bug to be fixed, then work on a fix yourself... I'm doing soap opera too, lol I just wish more people would contribute sometime... 😄.

On the subject of row span with frozen feature, it is indeed a complexity to the highest level, dealing with 2 separate divs (which is how the frozen feature works) is making it hard to keep in sync and it brings some unresolved issues, take this one for example #443 😨

EfremBraun commented 2 years ago

Whoa, looks like the issue is a lot more complicated than I thought. I'll just say thank you to all you guys for creating/maintaining such a wonderful open source project!

6pac commented 2 years ago

LOL. Hi @GerHobbelt, great to know you're still out there keeping an eye on things! It's truly a team effort. @ghiscoding is far more active than me these days. Perhaps some day the pendulum will swing again. Even better, perhaps we'll get even more enthusiastic contributors!

Great to see the rant - some great points in there.
For amusement, take a look at this: https://github.com/6pac/SlickGrid/pull/374 - the takeaway being To answer your other question... Yes, we have very large datasets with some reaching into the multiple billions. An internal user identified the bug when attempting to get the context menu on a row in the 5 billion range.

At some point we need to put together a matrix of which features work with each other.

One thing I haven't discussed with @ghiscoding yet, but have been meaning to, is the idea of creating a virtual canvas object. That is, a js object that hides all the split-canvas functionality and makes it look like the grid is dealing with the original single canvas.
This would firstly remove the code complexity associated with the multiple canvases, which is significant, but we could also control the actual number of canvases via an option. For example, if not using the freeze pane option, we could go with a single canvas. If we wanted frozen rows top and bottom and columns left and right, then nine canvases.

Then we could lock a rowspan feature like the OP is talking about to single-canvas mode.

This would be almost as much work as the original frozen panes feature, but I feel like it's probably the best long term road forwards. I haven't yet build a proof of concept to see if it's actually feasible, but I suspect it will be.