プロジェクト

全般

プロフィール

« | » 

リビジョン b526df4f

高徹 高橋 徹 さんが約9年前に追加

拡大縮小時は表示中心を維持するよう修正

差分を表示:

learn/java/javafx/ZoomPanCanvas/src/zoompancanvas/ZoomPanCanvasController.java
import javafx.util.converter.NumberStringConverter;
/**
*
* 拡大縮小、平行移動するベクターグラフィックスの表示コントローラ。
*
* @author TAKAHASHI,Toru
*/
public class ZoomPanCanvasController implements Initializable {
private static final Logger logger = Logger.getLogger(ZoomPanCanvasController.class.getName());
private static final Affine IDENTITY_TRANSFORM = new Affine(1f, 0f, 0f, 0f, 1f, 0);
private static final double RADIUS = 10_000f;
private static final Affine IDENTITY_TRANSFORM = new Affine(1, 0, 0, 0, 1, 0);
private static final double SCALE_RATIO = 1.4;
private static final double RADIUS = 10_000;
@FXML
private Canvas canvas;
@FXML
private Label scaleLabel;
private DoubleProperty scale = new SimpleDoubleProperty(1.0);
private Point2D translate = new Point2D(0f, 0f);
private Point2D originTranslate = new Point2D(0, 0);
private Point2D prevDragPoint;
/**
* データの中心を画面表示中心に合わせ、拡大率を1.0に設定する。
* データ座標系の原点と画面座標系の原点を一致させ、それをCanvas描画の中心に合わせ、
* 拡大率を6段階縮小に設定する。
*
* @param event
*/
@FXML
private void handleButtonAction(ActionEvent event) {
logger.info("Draw button pressed.");
translate = new Point2D(canvas.getWidth() / 2f, canvas.getHeight() / 2f);
scale.set(1f / Math.pow(1.4f, 6));
originTranslate = new Point2D(0, 0);
scale.set(1 / Math.pow(SCALE_RATIO, 6));
drawCanvas();
}
/**
* Canvasの中心位置を計算し、Point2Dインスタンスに詰めて返却する。
*
* @return Canvasの中心位置
*/
private Point2D getCenterOfCanvas() {
return new Point2D(canvas.getWidth() / 2, canvas.getHeight() / 2);
}
@Override
public void initialize(URL url, ResourceBundle rb) {
scaleLabel.textProperty().bindBidirectional(scale, new NumberStringConverter());
canvas.setOnScroll(ev -> {
scale.set((ev.getDeltaY() >= 0) ? scale.get() * 1.4f : scale.get() / 1.4f);
double prevScaleValue = scale.get();
double nextScaleValue = (ev.getDeltaY() >= 0) ? scale.get() * SCALE_RATIO : scale.get() / SCALE_RATIO;
scale.set(nextScaleValue);
originTranslate = originTranslate.multiply(nextScaleValue / prevScaleValue);
drawCanvas();
});
canvas.setOnMousePressed(ev -> {
......
});
canvas.setOnMouseDragged(ev -> {
Point2D dragPoint = new Point2D(ev.getSceneX(), ev.getSceneY());
translate = translate.add(dragPoint.subtract(prevDragPoint));
originTranslate = originTranslate.add(dragPoint.subtract(prevDragPoint));
prevDragPoint = dragPoint;
logger.info(() -> String.format("OnMouseDragged, sceneXY=(%f, %f), translate=%s",
ev.getSceneX(), ev.getSceneY(), translate));
ev.getSceneX(), ev.getSceneY(), originTranslate));
drawCanvas();
});
}
......
GraphicsContext gc = canvas.getGraphicsContext2D();
logger.info(() -> String.format("GraphicsContext's transform=%s%n", gc.getTransform().toString()));
clearCanvas();
gc.setTransform(getZoomPanTransform(scale.get(), translate));
gc.setTransform(getZoomPanTransform(scale.get(), originTranslate));
gc.setStroke(Color.DARKBLUE);
gc.setLineWidth(1 / scale.get());
gc.strokeLine(-RADIUS, 0, RADIUS, 0);
......
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
}
/**
* データ座標系から画面座標系への座標変換行列(Affine)を生成する。
*
* @param scale 拡大率
* @param translate データ座標系原点から画面座標系原点への平行移動量
* @return 座標変換行列
*/
private Affine getZoomPanTransform(double scale, Point2D translate) {
return new Affine(scale, 0, translate.getX(), 0, -scale, translate.getY());
Point2D center = getCenterOfCanvas();
Point2D totalTranslate = translate.add(center);
return new Affine(scale, 0, totalTranslate.getX(), 0, -scale, totalTranslate.getY());
}
}

他の形式にエクスポート: Unified diff