キャンバス上にドットを描画します。これはズームインまたはズームアウトできます。
私の知る限り、描画関数canvas.drawCircle()
はキャンバス座標系の座標を取り込みます。さらに、キャンバスをズームしても座標は変わりません。
たとえば、以前(50, 50)
にキャンバス座標系でドットを描画してから、キャンバスを拡大しても、キャンバス内のドットの座標はそのまま(50, 50)
です。しかし、明らかに、ドットは画面に対して移動されています。
キャンバスがズームされている場合、ドットは画面上の同じ位置に保持する必要があります。*つまり、ドットが画面に対して移動した後、画面に対して元の位置に戻します。*
私のonDraw()
機能は次のとおりです。
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvasWidth = canvas.getWidth();
canvasHeight = canvas.getHeight();
canvas.save();
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
mImage.draw(canvas); // draw the map as the background
Paint PointStyle = new Paint();
PointStyle.setColor(Color.BLUE);
PointStyle.setStyle(Paint.Style.FILL_AND_STROKE);
PointStyle.setStrokeWidth(2);
canvas.drawCircle(Constant.INITIAL_X, Constant.INITIAL_Y, 3, PointStyle);
canvas.restore();
}
スケーリング後にドットを画面に戻すには、次の方法を試しました。
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor(); // accumulate the scale factors
// Don't let the object get too small or too large.
mScaleFactor = Math.max(1f, Math.min(mScaleFactor, 10.0f)); // 1 ~ 10
float pinToCornerOnScreenXDistance = 0;
float pinToCornerOnScreenYDistance = 0;
float canvasToScreenDiffRatioX = 0;
float canvasToScreenDiffRatioY = 0;
float pinOnCanvasX = 0;
float pinOnCanvasY = 0;
// pin's location on the screen --> S:(336, 578)
pinToCornerOnScreenXDistance = 336 - canvasLeftTopCornerOnScreenX;
pinToCornerOnScreenYDistance = 578 - canvasLeftTopCornerOnScreenY;
Log.d("Screen Diff", "X: " + pinToCornerOnScreenXDistance + " Y: " + pinToCornerOnScreenYDistance);
canvasToScreenDiffRatioX = canvasWidth * mScaleFactor / 720; // screen of HTC One X --> 720*1280
canvasToScreenDiffRatioY = canvasHeight * mScaleFactor / 1280;
Log.d("Ratio", canvasToScreenDiffRatioX + " " + canvasToScreenDiffRatioY);
pinOnCanvasX = 0 + pinToCornerOnScreenXDistance * canvasToScreenDiffRatioX; // canvas left top corner is the origin (0, 0)
pinOnCanvasY = 0 + pinToCornerOnScreenYDistance * canvasToScreenDiffRatioY;
Log.d("Pin on Canvas", "X: " + pinOnCanvasX + " Y: " + pinOnCanvasY);
Constant.setInitialX(pinOnCanvasX);
Constant.setInitialY(pinOnCanvasY);
historyXSeries.set(0, Constant.INITIAL_X);
historyYSeries.set(0, Constant.INITIAL_Y);
invalidate();
return true;
}
}
このアイデアは、キャンバスをズームインまたはズームアウトしても、左上隅が動かないことに気付いたという事実に基づいています。つまり、キャンバスの一番上の角がズームの中心です。
次に、キャンバスが移動したときに、ズーム中心の座標を正常に更新し続けます。このように、キャンバスを移動したりズームしたりしても、常にズーム中心の座標が と にcanvasLeftTopCornerOnScreenX
ありcanvasLeftTopCornerOnScreenY
ます。
次に、スケーリング中に移動したことのないズーム中心と、ここでドットを配置したい目的の位置との間の距離を利用しようとし(336, 578)
ます。として計算しpinToCornerOnScreenDistance
ます。
その名の通り画面上の距離です。描画関数はスクリーン座標系ではなくキャンバス座標系に基づいているため、ドットを描画できるようにキャンバス距離にスケーリングする必要があります。現在、コードはデバイス固有です。つまり、現時点では 1280*720 の画面を持つ HTC One X 専用です。したがって、次のようにスケーリングを行います。
canvasToScreenDiffRatioX = canvasWidth * mScaleFactor / 720;
canvasToScreenDiffRatioY = canvasHeight * mScaleFactor / 1280;
次に、最後に、画面上のポイントの新しいキャンバス上の座標を計算し、(336, 578)
そこにドットを描画します。
しかし、結果は正しくありません。キャンバスをズームすると、描画した点が(336, 578)
画面上に表示されません。
どこが悪いのか誰か教えてもらえますか?または、これを行う別の方法を提案しますか?
コメントや回答は大歓迎です!