JavaFx zooming to mouse as pivot -


i have tried example given in another post learn zooming , panning relative mouse pointer. when on grid, zooming works expected:

when zooming mouse pointer location on top left image, zoomed exact location seen in top right image.

if dragged off grid, e.g. pivot starts 'misbehave':

when zooming mouse pointer location on bottom left image, zoomed location other 1 intended, seen in bottom right image.

the bounds of canvas inside parent changes 600x600 (without scale) 600x700… affects outcomes dx, dy of following function.

double dx = (event.getscenex() - (canvas.getboundsinparent().getwidth()/2 + canvas.getboundsinparent().getminx())); double dy = (event.getsceney() - (canvas.getboundsinparent().getheight()/2 + canvas.getboundsinparent().getminy())); 

when editing function changing .getwidth() .getheight() , again move rectangle out right… zoom works correctly. however, if rectangle moved out vertically (to bottom or top) , left problem again reproduced again.

is above function correct, trying do? why zoom not work same, when on grid?

enter image description here

import javafx.application.application; import javafx.beans.property.doubleproperty; import javafx.beans.property.simpledoubleproperty; import javafx.event.eventhandler; import javafx.scene.group; import javafx.scene.node; import javafx.scene.scene; import javafx.scene.canvas.canvas; import javafx.scene.canvas.graphicscontext; import javafx.scene.control.label; import javafx.scene.input.mouseevent; import javafx.scene.input.scrollevent; import javafx.scene.layout.pane; import javafx.scene.paint.color; import javafx.scene.shape.circle; import javafx.scene.shape.rectangle; import javafx.stage.stage;  class pannablecanvas extends pane {      doubleproperty myscale = new simpledoubleproperty(1.0);      public pannablecanvas() {         setprefsize(600, 600);         setstyle("-fx-background-color: lightgrey; -fx-border-color: blue;");          // add scale transform         scalexproperty().bind(myscale);         scaleyproperty().bind(myscale);     }      /**      * add grid canvas, send      */     public void addgrid() {          double w = getboundsinlocal().getwidth();         double h = getboundsinlocal().getheight();          // add grid         canvas grid = new canvas(w, h);          // don't catch mouse events         grid.setmousetransparent(true);          graphicscontext gc = grid.getgraphicscontext2d();          gc.setstroke(color.gray);         gc.setlinewidth(1);          // draw grid lines         double offset = 50;         for( double i=offset; < w; i+=offset) {             gc.strokeline( i, 0, i, h);             gc.strokeline( 0, i, w, i);         }          getchildren().add( grid);          grid.toback();     }      public double getscale() {         return myscale.get();     }      public void setscale( double scale) {         myscale.set(scale);     }      public void setpivot( double x, double y) {         settranslatex(gettranslatex()-x);         settranslatey(gettranslatey()-y);     } }   /**  * mouse drag context used scene , nodes.  */ class dragcontext {      double mouseanchorx;     double mouseanchory;      double translateanchorx;     double translateanchory;  }  /**  * listeners making nodes draggable via left mouse button. considers if parent zoomed.  */ class nodegestures {      private dragcontext nodedragcontext = new dragcontext();      pannablecanvas canvas;      public nodegestures( pannablecanvas canvas) {         this.canvas = canvas;      }      public eventhandler<mouseevent> getonmousepressedeventhandler() {         return onmousepressedeventhandler;     }      public eventhandler<mouseevent> getonmousedraggedeventhandler() {         return onmousedraggedeventhandler;     }      private eventhandler<mouseevent> onmousepressedeventhandler = new eventhandler<mouseevent>() {          public void handle(mouseevent event) {              // left mouse button => dragging             if( !event.isprimarybuttondown())                 return;              nodedragcontext.mouseanchorx = event.getscenex();             nodedragcontext.mouseanchory = event.getsceney();              node node = (node) event.getsource();              nodedragcontext.translateanchorx = node.gettranslatex();             nodedragcontext.translateanchory = node.gettranslatey();          }      };      private eventhandler<mouseevent> onmousedraggedeventhandler = new eventhandler<mouseevent>() {         public void handle(mouseevent event) {              // left mouse button => dragging             if( !event.isprimarybuttondown())                 return;              double scale = canvas.getscale();              node node = (node) event.getsource();              node.settranslatex(nodedragcontext.translateanchorx + (( event.getscenex() - nodedragcontext.mouseanchorx) / scale));             node.settranslatey(nodedragcontext.translateanchory + (( event.getsceney() - nodedragcontext.mouseanchory) / scale));              event.consume();          }     }; }  /**  * listeners making scene's canvas draggable , zoomable  */ class scenegestures {      private static final double max_scale = 10.0d;     private static final double min_scale = .1d;      private dragcontext scenedragcontext = new dragcontext();      pannablecanvas canvas;      public scenegestures( pannablecanvas canvas) {         this.canvas = canvas;     }      public eventhandler<mouseevent> getonmousepressedeventhandler() {         return onmousepressedeventhandler;     }      public eventhandler<mouseevent> getonmousedraggedeventhandler() {         return onmousedraggedeventhandler;     }      public eventhandler<scrollevent> getonscrolleventhandler() {         return onscrolleventhandler;     }      private eventhandler<mouseevent> onmousepressedeventhandler = new eventhandler<mouseevent>() {          public void handle(mouseevent event) {              // right mouse button => panning             if( !event.issecondarybuttondown())                 return;              scenedragcontext.mouseanchorx = event.getscenex();             scenedragcontext.mouseanchory = event.getsceney();              scenedragcontext.translateanchorx = canvas.gettranslatex();             scenedragcontext.translateanchory = canvas.gettranslatey();          }      };      private eventhandler<mouseevent> onmousedraggedeventhandler = new eventhandler<mouseevent>() {         public void handle(mouseevent event) {              // right mouse button => panning             if( !event.issecondarybuttondown())                 return;              canvas.settranslatex(scenedragcontext.translateanchorx + event.getscenex() - scenedragcontext.mouseanchorx);             canvas.settranslatey(scenedragcontext.translateanchory + event.getsceney() - scenedragcontext.mouseanchory);              event.consume();         }     };      /**      * mouse wheel handler: zoom pivot point      */     private eventhandler<scrollevent> onscrolleventhandler = new eventhandler<scrollevent>() {          @override         public void handle(scrollevent event) {              double delta = 1.2;              double scale = canvas.getscale(); // use y, same value used x             double oldscale = scale;              if (event.getdeltay() < 0)                 scale /= delta;             else                 scale *= delta;              scale = clamp( scale, min_scale, max_scale);              double f = (scale / oldscale)-1;              double dx = (event.getscenex() - (canvas.getboundsinparent().getwidth()/2 + canvas.getboundsinparent().getminx()));             double dy = (event.getsceney() - (canvas.getboundsinparent().getheight()/2 + canvas.getboundsinparent().getminy()));              canvas.setscale( scale);              // note: pivot value must untransformed, i. e. without scaling             canvas.setpivot(f*dx, f*dy);              event.consume();          }      };       public static double clamp( double value, double min, double max) {          if( double.compare(value, min) < 0)             return min;          if( double.compare(value, max) > 0)             return max;          return value;     } }    /**  * application zoomable , pannable canvas.  */ public class zoomandscrollapplication extends application {     public static void main(string[] args) {         launch(args);     }      @override     public void start(stage stage) {          group group = new group();          // create canvas         pannablecanvas canvas = new pannablecanvas();          // don't want canvas on top/left in example =>         // translate bit         canvas.settranslatex(100);         canvas.settranslatey(100);          // create sample nodes can dragged         nodegestures nodegestures = new nodegestures( canvas);          label label1 = new label("draggable node 1");         label1.settranslatex(10);         label1.settranslatey(10);         label1.addeventfilter( mouseevent.mouse_pressed, nodegestures.getonmousepressedeventhandler());         label1.addeventfilter( mouseevent.mouse_dragged, nodegestures.getonmousedraggedeventhandler());          label label2 = new label("draggable node 2");         label2.settranslatex(100);         label2.settranslatey(100);         label2.addeventfilter( mouseevent.mouse_pressed, nodegestures.getonmousepressedeventhandler());         label2.addeventfilter( mouseevent.mouse_dragged, nodegestures.getonmousedraggedeventhandler());          label label3 = new label("draggable node 3");         label3.settranslatex(200);         label3.settranslatey(200);         label3.addeventfilter( mouseevent.mouse_pressed, nodegestures.getonmousepressedeventhandler());         label3.addeventfilter( mouseevent.mouse_dragged, nodegestures.getonmousedraggedeventhandler());          circle circle1 = new circle( 300, 300, 50);         circle1.setstroke(color.orange);         circle1.setfill(color.orange.derivecolor(1, 1, 1, 0.5));         circle1.addeventfilter( mouseevent.mouse_pressed, nodegestures.getonmousepressedeventhandler());         circle1.addeventfilter( mouseevent.mouse_dragged, nodegestures.getonmousedraggedeventhandler());          rectangle rect1 = new rectangle(100,100);         rect1.settranslatex(450);         rect1.settranslatey(450);         rect1.setstroke(color.blue);         rect1.setfill(color.blue.derivecolor(1, 1, 1, 0.5));         rect1.addeventfilter( mouseevent.mouse_pressed, nodegestures.getonmousepressedeventhandler());         rect1.addeventfilter( mouseevent.mouse_dragged, nodegestures.getonmousedraggedeventhandler());          canvas.getchildren().addall(label1, label2, label3, circle1, rect1);          group.getchildren().add(canvas);          // create scene can dragged , zoomed         scene scene = new scene(group, 1024, 768);          scenegestures scenegestures = new scenegestures(canvas);         scene.addeventfilter( mouseevent.mouse_pressed, scenegestures.getonmousepressedeventhandler());         scene.addeventfilter( mouseevent.mouse_dragged, scenegestures.getonmousedraggedeventhandler());         scene.addeventfilter( scrollevent.any, scenegestures.getonscrolleventhandler());          stage.setscene(scene);         stage.show();          canvas.addgrid();      } } 

as nobody answered question until , stumbled on same problem, post solution, adds simple calculation of left/up/lower , right overhang of nodes.

if replace part of zooming-code part attached below, should got.

//maxx = right overhang, maxy = lower overhang double maxx = canvas.getboundsinparent().getmaxx() - canvas.localtoparent(canvas.getprefwidth(), canvas.getprefheight()).getx(); double maxy = canvas.getboundsinparent().getmaxy() - canvas.localtoparent(canvas.getprefwidth(), canvas.getprefheight()).gety();  // minx = left overhang, miny = upper overhang double minx = canvas.localtoparent(0,0).getx() - canvas.getboundsinparent().getminx(); double miny = canvas.localtoparent(0,0).gety() - canvas.getboundsinparent().getminy();  // adding overhangs together, consider width of canvas double subx = maxx + minx; double suby = maxy + miny;  // subtracting overall overhang width , left , upper overhang upper left point double dx = (event.getscenex() - ((canvas.getboundsinparent().getwidth()-subx)/2 + (canvas.getboundsinparent().getminx()+minx))); double dy = (event.getsceney() - ((canvas.getboundsinparent().getheight()-suby)/2 + (canvas.getboundsinparent().getminy()+miny))); 

warning: left , overhang computed correctly, did not find working way, compute right , lower overhang of nodes without use of preferred height , width attributes. keep in mind, need these.

also, can improve performance computing canvas.getboundsinparent() thing once before the other calculations computed multiple times.

hope helps someone.


Comments

Popular posts from this blog

routing - AngularJS State management ->load multiple states in one page -

python - GRASS parser() error -

Swift game error message -