Skip to content

Commit

Permalink
Fix an incorrect zooming behaviour on ScreenSpace-Camera render mode.
Browse files Browse the repository at this point in the history
Updated
- Optimize Calculation during zoom deceleration.
- Update a proper way to handle stretched anchor content.
  • Loading branch information
LokoSoloGames committed Dec 21, 2022
1 parent 75d60d0 commit a30b00d
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 29 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.5] - 2022-12-22
### Fixed
- Fix an incorrect zooming behaviour on ScreenSpace-Camera render mode.
### Updated
- Optimize Calculation during zoom deceleration.
- Update a proper way to handle stretched anchor content.

## [1.0.4] - 2022-09-15
### Fixed
- Fix an incorrect zooming behaviour on ScreenSpace-Camera & WorldSpace render mode.
Expand Down
59 changes: 31 additions & 28 deletions Runtime/PinchableScrollRect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class PinchableScrollRect : ScrollRect, IPinchStartHandler, IPinchEndHand
private Vector3 initScale;
private float zoomVelocity = 0f;
private Vector2 zoomPosDelta = Vector2.zero;
private bool updatePivot;

protected bool isZooming = false;
protected Vector2 pinchStartPos;
Expand Down Expand Up @@ -85,6 +86,7 @@ public virtual void OnPinchZoom(PinchEventData eventData) {
isZooming = true;
zoomVelocity = zoomValue;
zoomPosDelta = localPos;
updatePivot = true;
}

public override void OnScroll(PointerEventData eventData) {
Expand All @@ -103,6 +105,7 @@ public override void OnScroll(PointerEventData eventData) {
isZooming = true;
zoomVelocity = zoomValue;
zoomPosDelta = localPos;
updatePivot = true;
}

protected virtual void Update() {
Expand Down Expand Up @@ -131,37 +134,36 @@ protected override void LateUpdate() {
protected virtual void HandleZoom(float zoomValue) {
Vector3 _localScale = content.localScale;
Rect _rect = content.rect;
Vector3 _worldPos = content.position;

Vector2 pixelDelta = new Vector2(zoomPosDelta.x / Mathf.Max(1f, _localScale.x), zoomPosDelta.y / Mathf.Max(1f, _localScale.x));
// Set to new pivot before scaling
Vector2 pivotDelta = new Vector2(pixelDelta.x / _rect.width, pixelDelta.y / _rect.height);
this.UpdateBounds();
this.SetContentPivotPosition(content.pivot + pivotDelta);
// Then set scale

if (updatePivot) {
var _anchorMin = content.anchorMin;
var _anchorMax = content.anchorMax;
var _localPos = content.localPosition;
// Set to new pivot before scaling
Vector2 pivotDelta = new Vector2(zoomPosDelta.x / _rect.width, zoomPosDelta.y / _rect.height);
// Set fixed anchor to avoid incorrect calculation due to stretched anchors
content.anchorMin = new Vector2(0.5f, 0.5f);
content.anchorMax = new Vector2(0.5f, 0.5f);
this.UpdateBounds();
this.SetContentPivotPosition(content.pivot + pivotDelta);
// Apply position compensation due to pivot change
_localPos += new Vector3(zoomPosDelta.x * _localScale.x, zoomPosDelta.y * _localScale.y);
// Reset to original anchors
content.anchorMin = _anchorMin;
content.anchorMax = _anchorMax;
// Apply final position
content.localPosition = _localPos;
}
// Set scale
Vector3 newScale = _localScale + Vector3.one * zoomValue;
newScale = new Vector3(
Mathf.Clamp(newScale.x, lowerScale.x, upperScale.x),
Mathf.Clamp(newScale.y, lowerScale.y, upperScale.y),
Mathf.Clamp(newScale.z, lowerScale.z, upperScale.z));
this.SetContentLocalScale(newScale);
// The world position should remain the same
content.position = _worldPos + (Vector3)pixelDelta * getScaleFactor(); // compensate for value due to pivot change
// Reset delta since zooming deceleration take place at the same pivot
zoomPosDelta = Vector2.zero;
}

float getScaleFactor() {
switch (_canvas.renderMode) {
case RenderMode.ScreenSpaceOverlay:
return _canvas.scaleFactor;
case RenderMode.ScreenSpaceCamera:
return _canvas.scaleFactor / _canvas.referencePixelsPerUnit;
case RenderMode.WorldSpace:
return _canvas.transform.localScale.x;
default:
throw new ArgumentOutOfRangeException();
}
updatePivot = false;
}

protected virtual void SetContentPivotPosition(Vector2 pivot) {
Expand All @@ -175,18 +177,19 @@ protected virtual void SetContentPivotPosition(Vector2 pivot) {
protected virtual void SetContentLocalScale(Vector3 newScale) {
Rect _rect = content.rect;
Rect _viewRect = viewRect.rect;
bool invalidX = _rect.width * newScale.x < _viewRect.width;
bool invalidY = _rect.height * newScale.y < _viewRect.height;
if (invalidX) newScale.x = _viewRect.width / _rect.width;
if (invalidY) newScale.y = _viewRect.height / _rect.height;
if (invalidX || invalidY) ResetZoom();
// bool invalidX = _rect.width * newScale.x < _viewRect.width;
// bool invalidY = _rect.height * newScale.y < _viewRect.height;
// if (invalidX) newScale.x = _viewRect.width / _rect.width;
// if (invalidY) newScale.y = _viewRect.height / _rect.height;
// if (invalidX || invalidY) ResetZoom();
content.localScale = newScale;
_onScaleChanged.Invoke(newScale);
}

protected void ResetZoom() {
zoomVelocity = 0f;
zoomPosDelta = Vector2.zero;
updatePivot = false;
}

// For External Control
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "com.lokosolo.pinchable-scrollrect",
"version": "1.0.4",
"version": "1.0.5",
"displayName": "Pinchable ScrollRect",
"description": "Pinchable ScrollRect allows users to zoom in and out on the ScrollRect with both touches pinching input or mouse scroll input.",
"unity": "2018.4",
Expand Down

0 comments on commit a30b00d

Please sign in to comment.