I now draw a dot on the canvas, which may be zoomed in or out.
As far as I know, the drawing function, canvas.drawCircle()
takes in the coordinates in canvas coordinate system. Furthermore, the co-ordinates remain unchanged when the canvas is zoomed.
E.g. previously you draw a dot at (50, 50)
in the canvas coordinate system, and then you zoom in the canvas, the dot's coordinates in the canvas still remain (50, 50)
. But obviously, the dot has been moved w.r.t. the screen.
When the canvas is zoomed, the dot should be kept at the same position on the screen. *i.e. After the dot moves w.r.t. to the screen, I want to move it back to its original position w.r.t. the screen.*
My onDraw()
function is as follows:
@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();
}
I tried the following method to move the dot back on screen after the scaling.
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;
}
}
The idea is based on the fact that I notice when I zoom in or out the canvas, its left top corner never moves. That is, the canvas' let top corner is the zooming center.
Then I successfully keep updating the zooming center's co-ordinates when the canvas is moved. So in this way, no matter I move the canvas or zoom it, I always have the zooming center's coordinates in my canvasLeftTopCornerOnScreenX
and canvasLeftTopCornerOnScreenY
.
Then I try to utilize the distance between the never-moved-during-scaling zooming center and the desired position where I hope to place my dot, (336, 578)
here. I calculate it as pinToCornerOnScreenDistance
.
As its name suggests, it is the on-screen distance. I have to scale it into canvas distance so that I can draw the dot, since the drawing function is based on the canvas coordinate system instead of the screen coordinate system. Currently, the code is device-specific, i.e. it is only for HTC One X, which has a 1280*720 screen, for now. So I do the scaling as follows:
canvasToScreenDiffRatioX = canvasWidth * mScaleFactor / 720;
canvasToScreenDiffRatioY = canvasHeight * mScaleFactor / 1280;
Then, finally I calculate the new on-canvas coordinates of on-screen point (336, 578)
and then draw the dot there.
But the result is not correct. When I zoom the canvas, the dot I draw fails to remain at (336, 578)
on screen.
Can anybody tell me where goes wrong?
Or propose another way of doing this?
Any comment or Answer will be greatly appreciated!