mauriciopoppe / function-plot

A 2d function plotter for the web
https://mauriciopoppe.github.io/function-plot/
MIT License
914 stars 112 forks source link

Inquiry about Manual Control of Zoom and Persistent Configuration in Your Open Source Framework #274

Open LatoAndroid opened 5 months ago

LatoAndroid commented 5 months ago

Hello, and thank you very much for your open-source framework, which is very user-friendly! Currently, I have two questions I would like to ask:

Is it possible to manually control zooming, for example, having zoom in and zoom out buttons on the touchscreen, where clicking the buttons can control zoom similar to a scroll wheel? Are there any relevant APIs for this, or if not, are there other ways to achieve this? I've seen others ask this question in historical issues, but there hasn't been a resolution.

After zooming and panning, is it possible to persist the configuration? For example, saving the configuration of this zoom locally and automatically applying this zoom and pan the next time it opens.

mauriciopoppe commented 5 months ago

hi there, answering inline:

Is it possible to manually control zooming, for example, having zoom in and zoom out buttons on the touchscreen, where clicking the buttons can control zoom similar to a scroll wheel? Are there any relevant APIs for this, or if not, are there other ways to achieve this? I've seen others ask this question in historical issues, but there hasn't been a resolution.

I do believe it's possible, given instance = functionPlot({ }) you have access to a d3.zoom instance through instance.meta.zoomBehavior, you can do something like this:

    instance.canvas.merge(window.instance.canvas.enter)
      .call(
        instance.meta.zoomBehavior.transform,
        d3.zoomIdentity.translate(1000, 1000)
      )

That would move the graph as expected but it you zoom or pan it goes back to its original location, I'm not sure why that's happening, I think there might be a bug in this codebase.

After zooming and panning, is it possible to persist the configuration? For example, saving the configuration of this zoom locally and automatically applying this zoom and pan the next time it opens.

Yes, I believe the current zoom should be stored in instance.meta.zoomBehavior.transform (it's an instance of https://d3js.org/d3-zoom#ZoomTransform), you'd need to serialize it and apply it to the graph with the d3 API.

LatoAndroid commented 5 months ago

Thank you for your response. I have tried the methods you provided, and indeed, I can translate and scale, but whenever I use the mouse to move or scale the graph again, it resets the state.

I attempted to simulate button clicks for manual zoom events, simulate reset events, and persistently store zoom and pan events by recalculating xDomain and yDomain settings. Persistent storage of zoom and pan is effective and achieves the desired results. However, the first two conflict with mouse zoom and pan. I wonder if I should destroy the original function-plot before the operation and then redraw it with the new domain? Would this solve the problem? I noticed you added a destroy method two months ago, but I couldn't find this method in the latest npm version 1.24.0.

I am a developer from China, using ChatGPT to translate my question. If there are any translation issues, please forgive me!

reset() { this.options.xAxis = { domain: [-10, 10] } this.options.yAxis = { domain: [-10, 10] } this.draw() },

zoomIn() { const [xStart, xEnd] = this.options.xAxis.domain; const [yStart, yEnd] = this.options.yAxis.domain; const xMid = (xStart + xEnd) / 2; const yMid = (yStart + yEnd) / 2; const xDomain = [(xStart - xMid) 0.9 + xMid, (xEnd - xMid) 0.9 + xMid]; const yDomain = [(yStart - yMid) 0.9 + yMid, (yEnd - yMid) 0.9 + yMid]; this.options.xAxis.domain = xDomain; this.options.yAxis.domain = yDomain; this.draw(); },

this.instance?.on('all:zoom', (event) => { console.log('xy',this.instance?.options.xAxis.domain,this.instance?.options.yAxis.domain) })

mauriciopoppe commented 5 months ago

I have tried the methods you provided, and indeed, I can translate and scale, but whenever I use the mouse to move or scale the graph again, it resets the state.

Yes this is what I saw too, what I remember doing is overriding the default zoom behavior so that zoom works across multiple instances of function plot (done with these lines) so it's unfortunately not implemented the same way as the zoom example from the d3 docs.

I wonder if I should destroy the original function-plot before the operation and then redraw it with the new domain?

Interesting idea, calling destroy removes the SVG node from the page and all listener associated with it, however I believe for every pan/zoom you'd redraw from scratch and that's a little bit expensive. It's also true that it's in the master branch and not released yet and hopefully destroy comes in 1.25 soon.