|
@@ -0,0 +1,276 @@
|
|
|
+using UnityEngine;
|
|
|
+using UnityEngine.UI;
|
|
|
+using UnityEngine.EventSystems;
|
|
|
+#if UNITY_EDITOR
|
|
|
+using UnityEditor;
|
|
|
+#endif
|
|
|
+
|
|
|
+public class AdvancedImageViewer : MonoBehaviour,
|
|
|
+ IBeginDragHandler, IDragHandler, IEndDragHandler,
|
|
|
+ IScrollHandler, IPointerClickHandler
|
|
|
+{
|
|
|
+ [Header("Zoom Settings")]
|
|
|
+ [Range(0.1f, 0.5f)] public float minZoom = 0.3f;
|
|
|
+ [Range(2f, 10f)] public float maxZoom = 4f;
|
|
|
+ [Range(0.01f, 0.2f)] public float zoomSpeed = 0.1f;
|
|
|
+ [Range(0.001f, 0.05f)] public float touchZoomSpeed = 0.01f;
|
|
|
+
|
|
|
+ [Header("Move Settings")]
|
|
|
+ [Range(0.5f, 2f)] public float moveSpeed = 1f;
|
|
|
+ [Range(0.01f, 0.3f)] public float elasticFactor = 0.1f;
|
|
|
+
|
|
|
+ [Header("References")]
|
|
|
+ public RectTransform imageRect;
|
|
|
+ public RectTransform contentRect;
|
|
|
+
|
|
|
+ private Vector2 lastDragPosition;
|
|
|
+ private float currentZoom = 1f;
|
|
|
+ private Vector2 initialAnchoredPosition;
|
|
|
+ private Vector2 initialSizeDelta;
|
|
|
+
|
|
|
+ private float lastTapTime;
|
|
|
+ private const float DoubleTapTime = 0.3f;
|
|
|
+ private bool isDragging;
|
|
|
+ private Vector2 velocity;
|
|
|
+ private const float friction = 0.95f;
|
|
|
+
|
|
|
+ private void OnEnable()
|
|
|
+ {
|
|
|
+
|
|
|
+ Screen.orientation = ScreenOrientation.LandscapeLeft;
|
|
|
+ Screen.autorotateToLandscapeLeft = false;
|
|
|
+ Screen.autorotateToLandscapeRight = false;
|
|
|
+ Screen.autorotateToPortrait = false;
|
|
|
+ Screen.autorotateToPortraitUpsideDown = false;
|
|
|
+ Initialize();
|
|
|
+ }
|
|
|
+ private void OnDisable()
|
|
|
+ {
|
|
|
+
|
|
|
+ Screen.orientation = ScreenOrientation.Portrait;
|
|
|
+ Screen.autorotateToLandscapeLeft = false;
|
|
|
+ Screen.autorotateToLandscapeRight = false;
|
|
|
+ Screen.autorotateToPortrait = false;
|
|
|
+ Screen.autorotateToPortraitUpsideDown = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void Initialize()
|
|
|
+ {
|
|
|
+ if (imageRect == null) imageRect = GetComponent<RectTransform>();
|
|
|
+ if (contentRect == null) contentRect = transform.parent.GetComponent<RectTransform>();
|
|
|
+
|
|
|
+ initialAnchoredPosition = imageRect.anchoredPosition;
|
|
|
+ initialSizeDelta = imageRect.sizeDelta;
|
|
|
+ currentZoom = 1f;
|
|
|
+ imageRect.localScale = Vector3.one;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void Update()
|
|
|
+ {
|
|
|
+ #if UNITY_EDITOR
|
|
|
+ if (!Application.isPlaying)
|
|
|
+ {
|
|
|
+
|
|
|
+ if (currentZoom != 1f)
|
|
|
+ {
|
|
|
+ currentZoom = 1f;
|
|
|
+ imageRect.localScale = Vector3.one;
|
|
|
+ imageRect.anchoredPosition = initialAnchoredPosition;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ HandleTouchZoom();
|
|
|
+ ApplyInertia();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void HandleTouchZoom()
|
|
|
+ {
|
|
|
+ if (Input.touchCount == 2)
|
|
|
+ {
|
|
|
+ Touch touchZero = Input.GetTouch(0);
|
|
|
+ Touch touchOne = Input.GetTouch(1);
|
|
|
+
|
|
|
+ if (touchZero.phase == TouchPhase.Moved || touchOne.phase == TouchPhase.Moved)
|
|
|
+ {
|
|
|
+ Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
|
|
|
+ Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
|
|
|
+
|
|
|
+ float prevDistance = Vector2.Distance(touchZeroPrevPos, touchOnePrevPos);
|
|
|
+ float currentDistance = Vector2.Distance(touchZero.position, touchOne.position);
|
|
|
+
|
|
|
+ float difference = currentDistance - prevDistance;
|
|
|
+ ZoomImage(1 + difference * touchZoomSpeed, (touchZero.position + touchOne.position) / 2);
|
|
|
+ }
|
|
|
+ isTwo=true;
|
|
|
+ }
|
|
|
+ else if(Input.touchCount == 0)
|
|
|
+ {
|
|
|
+ isTwo=false;
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ApplyInertia()
|
|
|
+ {
|
|
|
+ if (!isDragging && velocity.magnitude > 0.1f)
|
|
|
+ {
|
|
|
+ imageRect.anchoredPosition += velocity * Time.deltaTime;
|
|
|
+ velocity *= friction;
|
|
|
+ ClampImagePosition();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ velocity = Vector2.zero;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void OnBeginDrag(PointerEventData eventData)
|
|
|
+ {
|
|
|
+ if (Input.touchCount > 1) return;
|
|
|
+
|
|
|
+ isDragging = true;
|
|
|
+ lastDragPosition = eventData.position;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void OnDrag(PointerEventData eventData)
|
|
|
+ {
|
|
|
+ if (Input.touchCount > 1 || currentZoom <= 1f) return;
|
|
|
+
|
|
|
+ Vector2 delta = eventData.position - lastDragPosition;
|
|
|
+ imageRect.anchoredPosition += delta * moveSpeed;
|
|
|
+ velocity = delta * moveSpeed;
|
|
|
+ lastDragPosition = eventData.position;
|
|
|
+
|
|
|
+ ClampImagePosition();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void OnEndDrag(PointerEventData eventData)
|
|
|
+ {
|
|
|
+ isDragging = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void OnScroll(PointerEventData eventData)
|
|
|
+ {
|
|
|
+ float scrollDelta = eventData.scrollDelta.y;
|
|
|
+ float zoomFactor = 1f + scrollDelta * zoomSpeed;
|
|
|
+ ZoomImage(zoomFactor, eventData.position);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool isTwo=false;
|
|
|
+ public void OnPointerClick(PointerEventData eventData)
|
|
|
+ {
|
|
|
+ if (eventData.clickCount == 2)
|
|
|
+ {
|
|
|
+ HandleDoubleTap(eventData.position);
|
|
|
+ }
|
|
|
+ else if (eventData.clickCount == 1&&!isTwo)
|
|
|
+ {
|
|
|
+ float currentTime = Time.time;
|
|
|
+ if (currentTime - lastTapTime < DoubleTapTime)
|
|
|
+ {
|
|
|
+ HandleDoubleTap(eventData.position);
|
|
|
+ }
|
|
|
+ lastTapTime = currentTime;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void HandleDoubleTap(Vector2 position)
|
|
|
+ {
|
|
|
+ if (currentZoom > 1f)
|
|
|
+ {
|
|
|
+ ResetView();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ZoomImage(2f, position);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ZoomImage(float zoomFactor, Vector2 zoomCenter)
|
|
|
+ {
|
|
|
+ float newZoom = currentZoom * zoomFactor;
|
|
|
+ newZoom = Mathf.Clamp(newZoom, minZoom, maxZoom);
|
|
|
+
|
|
|
+ RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
|
|
+ imageRect,
|
|
|
+ zoomCenter,
|
|
|
+ null,
|
|
|
+ out Vector2 localPoint);
|
|
|
+
|
|
|
+ Vector2 pivotOffset = (Vector2)imageRect.pivot - new Vector2(0.5f, 0.5f);
|
|
|
+ Vector2 offset = localPoint * (newZoom - currentZoom);
|
|
|
+
|
|
|
+ imageRect.localScale = Vector3.one * newZoom;
|
|
|
+
|
|
|
+ currentZoom = newZoom;
|
|
|
+
|
|
|
+ ClampImagePosition();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ClampImagePosition()
|
|
|
+ {
|
|
|
+ if (currentZoom <= 1f)
|
|
|
+ {
|
|
|
+ imageRect.anchoredPosition = initialAnchoredPosition;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Vector3[] corners = new Vector3[4];
|
|
|
+ imageRect.GetWorldCorners(corners);
|
|
|
+
|
|
|
+ if (contentRect == null) return;
|
|
|
+
|
|
|
+ Vector3[] contentCorners = new Vector3[4];
|
|
|
+ contentRect.GetWorldCorners(contentCorners);
|
|
|
+
|
|
|
+ float imageWidth = (corners[2].x - corners[0].x)*imageRect.localScale.x;
|
|
|
+ float imageHeight = (corners[2].y - corners[0].y)*imageRect.localScale.x;
|
|
|
+
|
|
|
+ float contentWidth = contentCorners[2].x - contentCorners[0].x;
|
|
|
+ float contentHeight = contentCorners[2].y - contentCorners[0].y;
|
|
|
+
|
|
|
+ float minX = contentWidth - imageWidth;
|
|
|
+ float maxX = 0+ imageWidth;
|
|
|
+ float minY = contentHeight - imageHeight;
|
|
|
+ float maxY = 0+ imageHeight;
|
|
|
+
|
|
|
+ Vector3 pos = imageRect.localPosition;
|
|
|
+ pos.x = Mathf.Clamp(pos.x, minX, maxX);
|
|
|
+ pos.y = Mathf.Clamp(pos.y, minY, maxY);
|
|
|
+
|
|
|
+
|
|
|
+ if (pos.x != imageRect.localPosition.x || pos.y != imageRect.localPosition.y)
|
|
|
+ {
|
|
|
+ velocity = Vector2.zero;
|
|
|
+ imageRect.localPosition = Vector3.Lerp(imageRect.localPosition, pos, elasticFactor);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ imageRect.localPosition = pos;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void ResetView()
|
|
|
+ {
|
|
|
+ currentZoom = 1f;
|
|
|
+ imageRect.localScale = Vector3.one;
|
|
|
+ imageRect.anchoredPosition = initialAnchoredPosition;
|
|
|
+ velocity = Vector2.zero;
|
|
|
+ }
|
|
|
+
|
|
|
+ #if UNITY_EDITOR
|
|
|
+ private void OnValidate()
|
|
|
+ {
|
|
|
+ if (EditorApplication.isPlayingOrWillChangePlaymode) return;
|
|
|
+
|
|
|
+ if (imageRect == null) imageRect = GetComponent<RectTransform>();
|
|
|
+ if (contentRect == null && transform.parent != null)
|
|
|
+ contentRect = transform.parent.GetComponent<RectTransform>();
|
|
|
+
|
|
|
+ initialAnchoredPosition = imageRect.anchoredPosition;
|
|
|
+ initialSizeDelta = imageRect.sizeDelta;
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+}
|