リビジョン b526df4f
| 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());
|
||
|
}
|
||
|
|
||
|
}
|
||
拡大縮小時は表示中心を維持するよう修正