android - posicion - obtener coordenadas de una imagen javascript
Cómo encontrar la posición absoluta del clic mientras se hace zoom (3)
Consulte cada sección a continuación para obtener una descripción de mi problema, que se describe de tres maneras distintas. Con suerte, debería ayudar a las personas a responder.
Problema: ¿Cómo se encuentra un par de coordenadas expresadas en lienzo / espacio de usuario cuando solo se tienen las coordenadas expresadas en términos de una imagen ampliada, dado el punto de escala y el factor de escala originales?
Problema en la práctica:
Actualmente estoy intentando replicar la funcionalidad de zoom utilizada en aplicaciones como la galería / mapas, cuando puedes pellizcar para acercar / alejar con el zoom moviéndote hacia el punto medio de la pizca.
En la parte inferior guardo el punto central del zoom (que está en coordenadas X, Y en función de la pantalla actual). Luego hago que esta función actúe cuando se detecta un gesto de "escala":
class ImageScaleGestureDetector extends SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
if(mScaleAllowed)
mCustomImageView.scale(detector.getScaleFactor(), mCenterX, mCenterY);
return true;
}
}
La función de escala de CustomImageView se ve así:
public boolean scale(float scaleFactor, float focusX, float focusY) {
mScaleFactor *= scaleFactor;
// Don''t let the object get too small or too large.
mScaleFactor = Math.max(MINIMUM_SCALE_VALUE, Math.min(mScaleFactor, 5.0f));
mCenterScaleX = focusX;
mCenterScaleY = focusY;
invalidate();
return true;
}
El dibujo de la imagen escalada se logra anulando el método onDraw que escala el lienzo alrededor del centro y le dibuja la imagen.
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(mCenterScaleX, mCenterScaleY);
canvas.scale(mScaleFactor, mScaleFactor);
canvas.translate(-mCenterScaleX, -mCenterScaleY);
mIcon.draw(canvas);
canvas.restore();
}
Todo esto funciona bien cuando se escala desde ScaleFactor 1, esto es porque el mCenterX inicial y el mCenterY son coordenadas que se basan en la pantalla del dispositivo. 10, 10 en el dispositivo es 10, 10 en el lienzo.
Sin embargo, una vez que haya hecho el zoom, la próxima vez que haga clic en la posición 10, 10 ya no corresponderá a 10, 10 en el lienzo debido a la escala y la transformación que ya se realizó.
Problema en la abstracción:
La siguiente imagen es un ejemplo de una operación de zoom alrededor del punto central A. Cada cuadro representa la posición y el tamaño de la vista cuando está en ese factor de escala (1, 2, 3, 4, 5).
En el ejemplo, si escalaste por un factor de 2 alrededor de A, entonces hiciste clic en la posición B, la X, Y informada como B se basaría en la posición de la pantalla, no en la posición relativa al 0,0 del lienzo inicial.
Necesito encontrar una forma de obtener la posición absoluta de B.
Aquí está mi solución basada en la respuesta de Graeme:
public float[] getAbsolutePosition(float Ax, float Ay) {
MatrixContext.drawMatrix.getValues(mMatrixValues);
float x = mWidth - ((mMatrixValues[Matrix.MTRANS_X] - Ax) / mMatrixValues[Matrix.MSCALE_X])
- (mWidth - getTranslationX());
float y = mHeight - ((mMatrixValues[Matrix.MTRANS_Y] - Ay) / mMatrixValues[Matrix.MSCALE_X])
- (mHeight - getTranslationY());
return new float[] { x, y };
}
los parámetros Axe y Ay son los puntos que el usuario toca a través de onTouch (). Poseía mi instancia de matriz estática en la clase MatrixContext para mantener los valores escalados / traducidos anteriores.
Entonces, después de volver a dibujar el problema, encontré la solución que estaba buscando. Ha pasado por algunas iteraciones, pero así es como lo resolví:
B - Punto, centro de la operación de escala
A1, A2, A3 - Puntos, iguales en espacio de usuario pero diferentes en espacio de lienzo.
Conoces los valores para Bx
y By
porque siempre son constantes sin importar el factor de escala (conoces este valor tanto en el espacio de lienzo como en el espacio de usuario).
Conoces Ax
y Ay
en el espacio de usuario para que puedas encontrar la distancia entre Ax
a Bx
y Ay
a By
. Esta medida está en espacio de usuario, para convertirla en una medición de espacio de lienzo simplemente divídala por el factor de escala. (Una vez convertido a canvas-space, puede ver estas líneas en rojo, naranja y amarillo).
Como el punto B
es constante, la distancia entre él y los bordes es constante (Estos están representados por líneas azules). Este valor es igual en espacio de usuario y espacio de lienzo.
Usted conoce el ancho del Lienzo en el espacio lienzo, por lo que restando estas dos medidas del espacio del lienzo ( Ax
a Bx
y Bx
a Edge
) del ancho total le quedan las coordenadas del punto A en el espacio lienzo:
public float[] getAbsolutePosition(float Ax, float Ay) {
float fromAxToBxInCanvasSpace = (mCenterScaleX - Ax) / mScaleFactor;
float fromBxToCanvasEdge = mCanvasWidth - Bx;
float x = mCanvasWidth - fromAxToBxInCanvasSpace - fromBxToCanvasEdge;
float fromAyToByInCanvasSpace = (mCenterScaleY - Ay) / mScaleFactor;
float fromByToCanvasEdge = mCanvasHeight - By;
float y = mCanvasHeight - fromAyToByInCanvasSpace - fromByToCanvasEdge;
return new float[] { x, y };
}
El código y la imagen de arriba describen cuando haces clic en la esquina superior izquierda del centro original. Utilicé la misma lógica para encontrar A sin importar en qué cuadrante estaba ubicado y refactorizado a lo siguiente:
public float[] getAbsolutePosition(float Ax, float Ay) {
float x = getAbsolutePosition(mBx, Ax);
float y = getAbsolutePosition(mBy, Ay);
return new float[] { x, y };
}
private float getAbsolutePosition(float oldCenter, float newCenter, float mScaleFactor) {
if(newCenter > oldCenter) {
return oldCenter + ((newCenter - oldCenter) / mScaleFactor);
} else {
return oldCenter - ((oldCenter - newCenter) / mScaleFactor);
}
}
Realmente lo siento, esta es una respuesta breve, apurada. Pero también he estado viendo esto recientemente: he encontrado http://code.google.com/p/android-multitouch-controller/ para hacer lo que quiera (creo que tuve que leer detenidamente su publicación). Espero que esto ayude. Tendré una mirada apropiada esta noche si esto no ayuda y veo si puedo ayudar más.