18 Star 49 Fork 152

OpenHarmony/applications_photos

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
EventPipeline.ts 29.39 KB
一键复制 编辑 原始数据 按行查看 历史
liujuan 提交于 2023-06-28 15:54 +08:00 . Signed-off-by: Fanny liujuan76@h-partners.com
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Matrix4 from '@ohos.matrix4';
import { MediaItem } from './MediaItem';
import { Log } from '../../../utils/Log';
import { BroadCast } from '../../../utils/BroadCast';
import { MathUtil } from '../../../utils/MathUtil';
import { Constants as PhotoConstants } from './Constants';
import { ScreenManager } from '../../common/ScreenManager';
import { PhotoItemGestureCallback } from '../../browser/photo/PhotoItemGestureCallback';
import { BigDataConstants, ReportToBigDataUtil } from '../../../utils/ReportToBigDataUtil';
import { UiUtil } from '../../../utils/UiUtil';
const TAG: string = 'common_EventPipeline';
export type AnimationParam = {
duration: number,
curve: Curve
};
export class EventPipeline {
// 上次平移
private lastOffset: [number, number] = [0, 0];
// 当前平移
private offset: [number, number] = [0, 0];
// 上次缩放值
private lastScale: number = 1.0;
// 默认缩放值
private defaultScale: number = 1.0;
// 当前缩放值
private scale: number = 1.0;
// 缩放中心点,是相对于控件的百分比位置,非绝对位置
private center: [number, number] = [0.5, 0.5];
// 最左缩放中心,(1 - leftMost)即为最右缩放中心
private leftMost: number = 0.0;
// 最上缩放中心,(1 - topMost)即为最下缩放中心
private topMost: number = 0.0;
// 双击缩放比例
private doubleTapScale: number = 1.0;
// 最大缩放比例
private maxScale: number = 1.0;
// 是否已经到达最左边
private hasReachLeft: boolean = true;
// 是否已经到达最右边
private hasReachRight: boolean = true;
// 事件总线
private broadCast: BroadCast;
// 数据单个条目项
private item: MediaItem;
// 事件总线
private gestureCallback: PhotoItemGestureCallback;
// 宽度
private width: number;
// 高度
private height: number;
// 大图显示控件宽度
private componentWidth: number = vp2px(ScreenManager.getInstance().getWinLayoutWidth());
// 大图显示控件高度
private componentHeight: number = vp2px(ScreenManager.getInstance().getWinLayoutHeight());
// 是否在做动画
private isInAnimation: boolean = false;
// 下拉返回flag,防止触发多次
private isExiting: boolean = false;
private touchEventStartX: number = 0;
private touchEventStartY: number = 0;
private touchEventStartId: number = 0;
private isPullDownAndDragPhoto: boolean = false;
constructor(broadCastParam: BroadCast, item: MediaItem, gestureCallback: PhotoItemGestureCallback) {
this.broadCast = broadCastParam;
this.item = item;
this.gestureCallback = gestureCallback;
this.width = this.item.imgWidth == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.imgWidth;
this.height = this.item.imgHeight == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.imgHeight;
this.evaluateScales();
}
onDataChanged(item: MediaItem) {
this.item = item;
this.width = this.item.imgWidth == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.imgWidth;
this.height = this.item.imgHeight == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.imgHeight;
this.evaluateScales();
}
setDefaultScale(scale) {
this.defaultScale = scale;
this.lastScale = scale;
}
onComponentSizeChanged(componentWidth: number, componentHeight: number) {
Log.info(TAG, `onComponentSizeChanged componentWidth ${componentWidth} componentHeight ${componentHeight}`)
this.componentWidth = componentWidth;
this.componentHeight = componentHeight;
this.evaluateScales();
let animationEndMatrix: Matrix4.Matrix4Transit = this.evaluateAnimeMatrix(this.lastScale, this.center);
this.startAnimation(animationEndMatrix);
}
public canTouch(): Boolean {
return !(this.isInAnimation || this.isExiting);
}
onTouch(event: TouchEvent) {
Log.debug(TAG, `onTouch trigger: ${event.type}, ${[this.isInAnimation, this.isExiting]}`);
if (!this.canTouch()) {
return;
}
if (event.type == TouchType.Down || event.type == TouchType.Up) {
this.emitDirectionChange();
}
this.verifyPullDownAndDragPhotoStatus(event);
// 普通场景up时记录scale及offset,动画场景动画结束时记录
if (event.type == TouchType.Up) {
this.lastOffset = this.evaluateOffset();
this.lastScale = this.lastScale * this.scale;
// 必须重置scale及offset,否则多次操作间会串,但是center不用清,因为this.scale为1时center不起作用
this.scale = 1;
this.offset = [0, 0];
}
}
verifyPullDownAndDragPhotoStatus(event: TouchEvent): void {
let scale = this.lastScale * this.scale;
let isEnlarged = Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS));
let touchList = event.touches;
if (touchList.length > 1) {
return;
}
if (event.type === TouchType.Down) {
// 重置拖动图片场景参数
if (this.canPullDownAndDragPhoto()) {
this.touchEventStartX = 0;
this.touchEventStartY = 0;
this.isPullDownAndDragPhoto = false;
}
this.touchEventStartX = touchList[0].screenX;
this.touchEventStartY = touchList[0].screenY;
this.touchEventStartId = touchList[0].id;
} else if (event.type === TouchType.Move && this.touchEventStartId === touchList[0].id) {
let touchX = touchList[0].screenX;
let touchY = touchList[0].screenY;
let deltaX = Math.abs(touchX - this.touchEventStartX);
let deltaY = touchY - this.touchEventStartY;
if (deltaY - deltaX > PhotoConstants.CAN_PULL_DOWN_DRAG_THRESHOLD && !isEnlarged) {
this.isPullDownAndDragPhoto = true;
}
}
if (this.isPullDownAndDragPhoto) {
this.gestureCallback.onDirectionChangeRespond(PanDirection.All);
}
Log.debug(TAG, 'canPullDownAndDragPhoto ' + this.isPullDownAndDragPhoto);
}
canPullDownAndDragPhoto(): boolean {
return this.isPullDownAndDragPhoto;
}
onMoveStart(offsetX: number, offsetY: number) {
if (this.isInAnimation || this.isExiting) {
return;
}
// 拖动开始时重置offset,防止跳变
this.offset = [0, 0];
this.evaluateBounds();
let scale = this.lastScale * this.scale;
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
// 有缩放拖动时隐藏bars
this.broadCast.emit(PhotoConstants.HIDE_BARS, [null]);
}
if (scale.toFixed(PhotoConstants.RESERVED_DIGITS) === this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS) && offsetY > 0) {
// 下拉返回开始先隐藏详情
this.broadCast.emit(PhotoConstants.PULL_DOWN_START, [null]);
}
}
/**
* 每次回调回来的是相对于此次手势开始点的位移
*
* @param offsetX offsetX
* @param offsetY offsetY
*/
onMove(offsetX: number, offsetY: number) {
if (this.isInAnimation || this.isExiting) {
return;
}
let scale = this.lastScale * this.scale;
let limits = this.evaluateOffsetRange(scale);
let measureX = this.lastOffset[0] + (this.center[0] - 0.5) * this.componentWidth * (this.defaultScale - this.scale) * this.lastScale;
let measureY = this.lastOffset[1] + (this.center[1] - 0.5) * this.componentHeight * ((this.defaultScale - this.scale)) * this.lastScale;
let moveX = offsetX;
let moveY = offsetY;
let offX = measureX + moveX;
let offY = measureY + moveY;
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
// 非缩小场景,始终限制x方向上的offset
offX = MathUtil.clamp(offX, limits[0], limits[1]);
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
// 不可下拉返回场景,限制y
offY = MathUtil.clamp(offY, limits[PhotoConstants.NUMBER_2], limits[PhotoConstants.NUMBER_3]);
} else {
// 可下拉返回场景,只限制y向上拖动,即限制下界
offY = Math.max(limits[PhotoConstants.NUMBER_2], offY);
}
}
let tmpX = offX - measureX;
let tmpY = offY - measureY;
this.offset = [tmpX, tmpY];
this.emitTouchEvent();
}
onMoveEnd(offsetX: number, offsetY: number) {
if (this.isInAnimation || this.isExiting) {
return;
}
let isStartPullDown = false;
let scale = this.lastScale * this.scale;
if (scale.toFixed(PhotoConstants.RESERVED_DIGITS) === this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS) &&
offsetY > PhotoConstants.PULL_DOWN_THRESHOLD) {
// 触发下拉返回
this.emitPullDownToBackEvent();
isStartPullDown = true;
} else if (scale.toFixed(PhotoConstants.RESERVED_DIGITS) === this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS) &&
offsetY < -PhotoConstants.PULL_DOWN_THRESHOLD && !this.canPullDownAndDragPhoto()) {
// 触发上划,但当已处于下拉拖动图片状态时,不触发上滑
this.emitPullUpToDisplayEvent();
} else if (scale.toFixed(PhotoConstants.RESERVED_DIGITS) === this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS)) {
// 未到阈值,触发重置动画
this.startAnimation(Matrix4.identity().scale({
x: this.defaultScale,
y: this.defaultScale
}).copy());
this.emitPullDownCancelEvent()
} else {
this.emitDirectionChange();
}
// 非下拉返回场景,重置拖动相关参数
if (!isStartPullDown) {
UiUtil.resetGeometryTransitionParams();
this.touchEventStartX = 0;
this.touchEventStartY = 0;
this.isPullDownAndDragPhoto = false;
}
}
onScaleStart(scale: number, centerX: number, centerY: number) {
Log.info(TAG, `onScaleStart: ${[this.isInAnimation, this.isExiting]}`);
if (this.isInAnimation || this.isExiting) {
return;
}
// scale开始时重置this.scale为1
this.scale = 1;
this.evaluateBounds();
// Adjust action bar status
this.broadCast.emit(PhotoConstants.HIDE_BARS, []);
this.center = this.evaluateCenter(centerX, centerY);
}
onScale(scale: number) {
Log.info(TAG, `onScale: ${[this.isInAnimation, this.isExiting]}, scale: ${scale}`);
if (this.isInAnimation || this.isExiting) {
return;
}
this.evaluateBounds();
this.scale = scale;
if (this.lastScale * scale <= PhotoConstants.COMPONENT_SCALE_FLOOR) {
this.scale = PhotoConstants.COMPONENT_SCALE_FLOOR / this.lastScale;
}
if (this.lastScale * scale >= this.maxScale * PhotoConstants.OVER_SCALE_EXTRA_FACTOR) {
this.scale = this.maxScale * PhotoConstants.OVER_SCALE_EXTRA_FACTOR / this.lastScale;
}
this.emitTouchEvent();
}
onScaleEnd() {
Log.info(TAG, `onScaleEnd: ${[this.isInAnimation, this.isExiting]}`);
if (this.isInAnimation || this.isExiting) {
return;
}
this.evaluateBounds();
let scale = this.lastScale * this.scale;
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) >= Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS)) && scale <= this.maxScale) {
Log.info(TAG, `does not need to do animation: ${scale}`);
this.emitDirectionChange();
return;
}
let animationEndMatrix: Matrix4.Matrix4Transit = null;
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) <= Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
// 缩小过小,触发恢复的动画
animationEndMatrix = Matrix4.identity().scale({
x: this.defaultScale,
y: this.defaultScale
}).copy();
} else {
// 放大时做缩回maxScale的动画
animationEndMatrix = this.evaluateAnimeMatrix(this.maxScale, this.center);
}
this.startAnimation(animationEndMatrix);
}
/**
* 双击触发缩放,如果当前scale小于等于1,缩放到doubleTapScale;如果当前scale大于1,缩放到1;
*
* @param centerX 双击位置
* @param centerY 双击位置
*/
onDoubleTap(centerX: number, centerY: number) {
if (this.isInAnimation || this.isExiting) {
Log.debug(TAG, `[onDoubleTap] not avaliable: ${[this.isInAnimation, this.isExiting]}`);
return;
}
// Adjust action bar status
this.broadCast.emit(PhotoConstants.HIDE_BARS, []);
let matrix: Matrix4.Matrix4Transit = undefined;
if (Number(this.lastScale.toFixed(PhotoConstants.RESERVED_DIGITS)) * this.scale > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
// scale大于1时缩放到原始状态
matrix = Matrix4.identity().scale({
x: this.defaultScale,
y: this.defaultScale
}).copy();
Log.debug(TAG, '[onDoubleTap] matrix scale 1');
} else {
// 放大状态根据点击位置计算放大中心
this.center = this.evaluateCenter(centerX, centerY);
// 图片宽高比小于控件宽高比时,centerX置为0.5,反之centerY置为0.5,保证双击放大后短边靠边
if (this.width / this.height < this.componentWidth / this.componentHeight) {
this.center[0] = PhotoConstants.COMPONENT_SCALE_FLOOR;
} else {
this.center[1] = PhotoConstants.COMPONENT_SCALE_FLOOR;
}
matrix = this.evaluateAnimeMatrix(this.doubleTapScale * this.defaultScale, this.center);
Log.debug(TAG, '[onDoubleTap] matrix scale center');
}
this.startAnimation(matrix);
}
reset() {
this.lastOffset = [0, 0];
this.offset = [0, 0];
this.lastScale = 1.0;
this.scale = 1;
this.hasReachLeft = true;
this.hasReachRight = true;
this.isInAnimation = false;
this.isExiting = false;
this.emitDirectionChange();
}
onDisAppear() {
Log.info(TAG, 'onDisAppear');
this.reset();
}
/**
* 动画结束,根据结束的变换矩阵刷新当前的各个参数值,保证连续性,防止下次手势操作时发生跳变
*
* @param animationEndMatrix 结束时的变换矩阵
*/
onAnimationEnd(animationEndMatrix: Matrix4.Matrix4Transit): void {
if (animationEndMatrix) {
// @ts-ignore
let matrix = animationEndMatrix.matrix4x4;
Log.info(TAG, `onAnimationEnd: ${matrix}`);
this.lastScale = matrix[0];
this.scale = 1;
this.lastOffset = [matrix[PhotoConstants.NUMBER_12], matrix[PhotoConstants.NUMBER_13]];
this.offset = [0, 0];
this.evaluateBounds();
this.isInAnimation = false;
this.emitDirectionChange();
}
}
public setSwipeStatus(disable: Boolean): void {
this.broadCast.emit(PhotoConstants.SET_DISABLE_SWIPE, [disable]);
}
startAnimation(animationEndMatrix: Matrix4.Matrix4Transit): void {
this.isInAnimation = true;
let animationOption: AnimationParam = {
duration: PhotoConstants.OVER_SCALE_ANIME_DURATION,
curve: Curve.Ease
};
this.gestureCallback.onAnimationEventRespond(animationOption, animationEndMatrix);
this.setSwipeStatus(true);
}
isDefaultScale(): boolean {
return Number(this.lastScale.toFixed(PhotoConstants.RESERVED_DIGITS)) ===
Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS));
}
private emitDirectionChange(): void {
/**
* reachLeft reachRight scale>1这三个变量,只可能有下面五种情况(scale<=1下reachLeft、reachRight必然为true):
* T T T:Vertical
* T T F:Vertical(大图初始状态)
* T F T:Vertical | Left
* F T T:Vertical | Right
* F F T:All
*/
let direction: any = undefined;
let scale = this.lastScale * this.scale;
let isEnlarged = Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS));
if (!this.hasReachLeft && !this.hasReachRight && isEnlarged) {
direction = PanDirection.All;
} else if (!this.hasReachLeft && this.hasReachRight && isEnlarged) {
direction = PanDirection.Vertical | PanDirection.Right;
} else if (this.hasReachLeft && !this.hasReachRight && isEnlarged) {
direction = PanDirection.Vertical | PanDirection.Left;
} else {
direction = PanDirection.Vertical;
}
if (this.isExiting) {
return;
}
if (direction == PanDirection.Vertical || direction == (PanDirection.Vertical | PanDirection.Left) ||
direction == (PanDirection.Vertical | PanDirection.Right)) {
this.setSwipeStatus(false);
} else {
this.setSwipeStatus(true);
}
Log.debug(TAG, `emitDirectionChange reaches: ${[this.hasReachLeft, this.hasReachRight]}, scale ${scale}, direction: ${direction}`);
this.gestureCallback.onDirectionChangeRespond(direction);
}
private evaluateOffset(): [number, number] {
Log.info(TAG, `evaluateOffset lastOffset: ${this.lastOffset}, offset: ${this.offset}`);
let centerX = (this.center[0] - 0.5) * this.componentWidth * (this.defaultScale - this.scale) * this.lastScale;
let centerY = (this.center[1] - 0.5) * this.componentHeight * (this.defaultScale - this.scale) * this.lastScale;
let offsetX = this.lastOffset[0] + this.offset[0] + centerX;
let offsetY = this.lastOffset[1] + this.offset[1] + centerY;
Log.info(TAG, `evaluateOffset offsetX: ${offsetX}, offsetY: ${offsetY}`);
return [offsetX, offsetY];
}
private emitTouchEvent(): void {
let offset: [number, number];
let scale = this.lastScale * this.scale;
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
let limits = this.evaluateOffsetRange(scale);
offset = this.evaluateOffset();
// 非缩小场景,始终限制x方向上的offset
offset[0] = MathUtil.clamp(offset[0], limits[0], limits[1]);
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
// 不可下拉返回场景,限制y
offset[1] = MathUtil.clamp(offset[1], limits[PhotoConstants.NUMBER_2], limits[PhotoConstants.NUMBER_3]);
} else {
// 可下拉返回场景,只限制y向上拖动,即限制下界
offset[1] = Math.max(limits[PhotoConstants.NUMBER_2], offset[1]);
}
} else {
// 缩小时调整缩放中心为显示中心点
offset = [0, 0];
}
let moveX = offset[0];
let moveY = offset[1];
let matrix = Matrix4.identity().scale({
x: scale,
y: scale,
}).translate({
x: moveX,
y: moveY
}).copy();
Log.info(TAG, `emitTouchEvent lastOffset: ${this.lastOffset}, offset: ${this.offset}, center: ${this.center}, scale: ${[this.lastScale, this.scale]}`);
this.gestureCallback.onTouchEventRespond(matrix);
this.evaluateBounds();
}
/**
* 大图放大倍率计算,主要包含:
* 1. 最大放大倍率maxScale
* 最大可放大到 maxScale * PhotoConstants.OVER_SCALE_EXTRA_FACTOR,然后回弹至maxScale;
* 如果小于doubleTapScale * PhotoConstants.MAX_SCALE_EXTRA_FACTOR,取该值作为放大倍率;
* 2. 双击放大倍率doubleTapScale
* 默认使图片长边对齐屏幕边缘,如果小于PhotoConstants.SAME_RATIO_SCALE_FACTOR(4/3)取该值
*/
private evaluateScales(): void {
if (this.width * this.componentHeight < this.componentWidth * this.height) {
// 宽高比小于控件显示宽高比,控件高度与图片高度相等
this.maxScale = this.height / this.componentHeight;
// 双击放大的scale保证左右充满边界
this.doubleTapScale = this.componentWidth * this.height / this.width / this.componentHeight;
// leftMost = (1 - dspW / compW) / 2 = (1 - compH * imgW / imgH / compW) / 2
this.leftMost = (1 - this.componentHeight * this.width / this.height / this.componentWidth) / 2;
this.topMost = 0.0;
} else if (this.width * this.componentHeight == this.componentWidth * this.height) {
// 宽高比等于控件显示宽高比
this.doubleTapScale = PhotoConstants.SAME_RATIO_SCALE_FACTOR;
this.maxScale = this.doubleTapScale * PhotoConstants.MAX_SCALE_EXTRA_FACTOR;
this.leftMost = 0;
this.topMost = 0;
} else {
// 宽高比大于控件显示宽高比,控件宽度与图片宽度相等
this.maxScale = this.width / this.componentWidth;
// 双击放大的scale保证上下充满边界
this.doubleTapScale = this.componentHeight * this.width / this.height / this.componentWidth;
this.leftMost = 0.0;
// topMost = (1 - dspH / compH) / 2 = (1 - compW * imgH / imgW / compH) / 2
this.topMost = (1 - this.componentWidth * this.height / this.width / this.componentHeight) / 2;
}
this.maxScale = Math.max(this.maxScale, PhotoConstants.COMPONENT_SCALE_CEIL);
if (this.doubleTapScale > this.maxScale) {
this.maxScale = this.doubleTapScale * PhotoConstants.MAX_SCALE_EXTRA_FACTOR;
}
Log.debug(TAG, `evaluateScales: ${this.width}*${this.height} & ${this.componentWidth}*${this.componentHeight}, max: ${this.maxScale}, most: [${this.leftMost},${this.topMost}], double: ${this.doubleTapScale}`);
}
private evaluateCompBounds(): [number, number] {
let scale = this.lastScale * this.scale;
let offset = this.evaluateOffset();
// 组件左上角坐标,因放大带来的偏移是-compW*(scale-1)/2,再加上偏移,得到控件左边界,上边界同理
let result: [number, number] = [
offset[0] - this.componentWidth * (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) - Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) / 2,
offset[1] - this.componentHeight * (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) - Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) / 2
];
Log.debug(TAG, `evaluateCompBounds: ${result}`);
return result;
}
private evaluateImgDisplaySize(): [number, number] {
let screenScale = 1;
let widthScale = this.componentWidth / this.item.imgWidth;
let heightScale = this.componentHeight / this.item.imgHeight;
screenScale = widthScale > heightScale ? heightScale : widthScale;
let scale = this.lastScale * this.scale * screenScale;
let imgDisplayWidth = 0;
let imgDisplayHeight = 0;
imgDisplayWidth = this.width * scale;
imgDisplayHeight = this.height * scale;
return [imgDisplayWidth, imgDisplayHeight];
}
private evaluateImgDisplayBounds(): [number, number] {
// 组件左边界,因放大带来的偏移是-compW*(scale-1)/2,再加上手势的偏移,得到控件左边界,上边界同理
let scale = this.lastScale * this.scale;
let leftTop = this.evaluateCompBounds();
let imgDisplaySize: [number, number] = this.evaluateImgDisplaySize();
let imgDisplayWidth = imgDisplaySize[0];
let imgDisplayHeight = imgDisplaySize[1];
let imgLeftBound = 0;
let imgTopBound = 0;
if (this.width / this.height > this.componentWidth / this.componentHeight) {
imgLeftBound = leftTop[0];
imgTopBound = leftTop[1] + (this.componentHeight * scale - imgDisplayHeight) / 2;
} else {
// 控件宽度减掉图片宽度,除以2就能得到图片左边到控件左边的距离,加上offsetX就是就是图片当前显示的左边界
imgLeftBound = (this.componentWidth * scale - imgDisplayWidth) / 2 + leftTop[0];
imgTopBound = leftTop[1];
}
return [imgLeftBound, imgTopBound];
}
// 计算图片显示边界
private evaluateBounds(): void {
let imgDisplaySize: [number, number] = this.evaluateImgDisplaySize();
let imgDisplayWidth = imgDisplaySize[0];
let imgDisplayBounds = this.evaluateImgDisplayBounds();
let imgLeftBound = imgDisplayBounds[0];
// 因底层计算有误差(小数点后6位),不能以0作为精确边界,左右分别容错1像素
this.hasReachLeft = imgLeftBound > -1;
this.hasReachRight = imgLeftBound + imgDisplayWidth < this.componentWidth + 1;
Log.info(TAG, `evaluateBounds scale: ${this.hasReachLeft}, offset: ${this.hasReachRight}`);
}
/**
* 计算当前scale下x及y方向上的offset上下界
*
* @param scale 当前控件显示倍率,通常是 this.lastScale * this.scale
* @returns 0&1 x方向offset下界&上界,2&3 y方向offset下界&上界
*/
private evaluateOffsetRange(scale: number): [number, number, number, number] {
let result: [number, number, number, number] = [0, 0, 0, 0];
let screenScale = 1;
let widthScale = this.componentWidth / this.item.imgWidth;
let heightScale = this.componentHeight / this.item.imgHeight;
screenScale = widthScale > heightScale ? heightScale : widthScale;
let left = (screenScale * scale * this.width - this.componentWidth) / 2;
let top = (screenScale * scale * this.height - this.componentHeight) / 2;
top = Math.max(top, 0);
left = Math.max(left, 0);
result = [-left, left, -top, top];
Log.info(TAG, `evaluateOffsetRange scale: ${scale}, defaultScale: ${this.defaultScale}, result: ${result}`);
return result;
}
private emitPullDownToBackEvent(): void {
Log.debug(TAG, `emitPullDownToBackEvent`);
if (this.isExiting) {
Log.info(TAG, `emitPullDownToBack isExiting: ${this.isExiting}`);
return;
}
this.isExiting = true;
Log.info(TAG, `emitPullDownToBack change isExiting into: ${this.isExiting}`);
this.broadCast.emit(PhotoConstants.PULL_DOWN_END, []);
ReportToBigDataUtil.report(BigDataConstants.PHOTO_PULL_DOWN_ID, null);
}
private emitPullUpToDisplayEvent(): void {
Log.debug(TAG, 'emitPullUpToDisplayEvent');
if (!this.canTouch()) {
return;
}
}
private emitPullDownCancelEvent(): void {
Log.debug(TAG, 'emitPullDownCancelEvent');
this.broadCast.emit(PhotoConstants.PULL_DOWN_CANCEL, []);
}
/**
* 计算当前缩放中心相对控件的百分比位置
*
* @param centerX 触摸点在屏幕上的绝对位置
* @param centerY 触摸点在屏幕上的绝对位置
* @returns 当前缩放中心相对控件的百分比位置
*/
private evaluateCenter(centerX: number, centerY: number): [number, number] {
// 计算出控件左上角相对于当前显示左上角的坐标
let scale = this.lastScale * this.scale;
let leftTop = this.evaluateCompBounds();
// 得出相对于控件的触摸坐标
let cxRelativeToComp = MathUtil.clamp((centerX - leftTop[0]) / (this.componentWidth * scale), this.leftMost, 1 - this.leftMost);
let cyRelativeToComp = MathUtil.clamp((centerY - leftTop[1]) / (this.componentHeight * scale), this.topMost, 1 - this.topMost);
let imgDisplaySize: [number, number] = this.evaluateImgDisplaySize();
let imgDisplayWidth = imgDisplaySize[0];
let imgDisplayHeight = imgDisplaySize[1];
let imgDisplayBounds = this.evaluateImgDisplayBounds();
let imgLeftBound = imgDisplayBounds[0];
let imgTopBound = imgDisplayBounds[1];
// 触摸中心点在图片显示区域外时,取中点
if (this.width / this.height > this.componentWidth / this.componentHeight) {
if (centerY < imgTopBound || centerY > imgTopBound + imgDisplayHeight) {
cyRelativeToComp = 0.5;
}
} else {
if (centerX < imgLeftBound || centerX > imgLeftBound + imgDisplayWidth) {
cxRelativeToComp = 0.5;
}
}
// 算出触摸的中心点百分比
let center: [number, number] = [cxRelativeToComp, cyRelativeToComp];
Log.info(TAG, `evaluateCenter center: ${center}, ${[centerX, centerY]}, size: ${imgDisplaySize}, bounds: ${imgDisplayBounds}, leftTop: ${leftTop}, compSize: ${[this.componentWidth * scale, this.componentHeight * scale]}`);
return center;
}
private evaluateAnimeMatrix(scale: number, center: [number, number]): Matrix4.Matrix4Transit {
let offset = [
this.lastOffset[0] + this.offset[0] + (center[0] - 0.5) * this.componentWidth * (this.defaultScale - scale / this.lastScale) * this.lastScale,
this.lastOffset[1] + this.offset[1] + (center[1] - 0.5) * this.componentHeight * (this.defaultScale - scale / this.lastScale) * this.lastScale
]
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
let limits = this.evaluateOffsetRange(scale);
offset[0] = MathUtil.clamp(offset[0], limits[0], limits[1]);
// 非缩小场景,始终限制x方向上的offset
offset[0] = MathUtil.clamp(offset[0], limits[0], limits[1]);
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
// 不可下拉返回场景,限制y
offset[1] = MathUtil.clamp(offset[1], limits[PhotoConstants.NUMBER_2], limits[PhotoConstants.NUMBER_3]);
} else {
// 可下拉返回场景,只限制y向上拖动,即限制下界
offset[1] = Math.max(limits[PhotoConstants.NUMBER_2], offset[1]);
}
} else {
// 缩小时调整缩放中心为显示中心点
offset = [0, 0];
}
let animationEndMatrix = Matrix4.identity().copy().scale({
x: scale,
y: scale,
}).translate({
x: offset[0],
y: offset[1]
}).copy();
Log.debug(TAG, `evaluateAnimeMatrix scale: ${scale}, center: ${center}, result: ${animationEndMatrix}`);
return animationEndMatrix;
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/openharmony/applications_photos.git
git@gitee.com:openharmony/applications_photos.git
openharmony
applications_photos
applications_photos
master

搜索帮助