mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-07-25 19:05:03 +02:00
wip
This commit is contained in:
@@ -59,6 +59,8 @@ export type Image = {
|
||||
const props = withDefaults(defineProps<{
|
||||
image: Image;
|
||||
activated: boolean;
|
||||
openAnimDuration: number;
|
||||
closeAnimDuration: number;
|
||||
}>(), {
|
||||
});
|
||||
|
||||
@@ -78,22 +80,17 @@ const originalImageLoaded = ref(false);
|
||||
const padding = 30;
|
||||
const ANIMATION_DURATION = 200;
|
||||
|
||||
// maxからはみ出す場合は縮小、maxに満たない場合は拡大する(contain)
|
||||
function calcNeutralSize(image: Image) {
|
||||
const maxWidth = window.innerWidth - padding * 2;
|
||||
const maxHeight = window.innerHeight - padding * 2;
|
||||
|
||||
let width = image.width;
|
||||
let height = image.height;
|
||||
const widthRatio = maxWidth / image.width;
|
||||
const heightRatio = maxHeight / image.height;
|
||||
const ratio = widthRatio < heightRatio ? widthRatio : heightRatio;
|
||||
|
||||
if (width > maxWidth) {
|
||||
height = height * (maxWidth / width);
|
||||
width = maxWidth;
|
||||
}
|
||||
|
||||
if (height > maxHeight) {
|
||||
width = width * (maxHeight / height);
|
||||
height = maxHeight;
|
||||
}
|
||||
const width = image.width * ratio;
|
||||
const height = image.height * ratio;
|
||||
|
||||
return { width, height };
|
||||
}
|
||||
@@ -326,18 +323,41 @@ function onPointerup(ev: PointerEvent) {
|
||||
const shouldCloseByDownwardSwipe = verticalSwipeDelta > 200 || (verticalSwipeDelta > 0 && pointerVec.y > 5); // 下の方で離された、または下に向かって強めに弾かれた
|
||||
if (shouldCloseByUpwardSwipe || shouldCloseByDownwardSwipe) {
|
||||
emit('close');
|
||||
//beginAnimation({
|
||||
// from: {
|
||||
// x: translation.value.x,
|
||||
// y: translation.value.y,
|
||||
// },
|
||||
// to: {
|
||||
// x: translation.value.x,
|
||||
// y: translation.value.y + (shouldCloseByUpwardSwipe ? -window.innerHeight : window.innerHeight),
|
||||
// },
|
||||
// duration: 200,
|
||||
// easing: easing_easeInOutQuad,
|
||||
// apply: (state) => {
|
||||
// translation.value.x = state.x;
|
||||
// translation.value.y = state.y;
|
||||
// },
|
||||
//});
|
||||
const sourceRect = getSizeAndTranslationForSourceElement();
|
||||
beginAnimation({
|
||||
from: {
|
||||
width: size.value.width,
|
||||
height: size.value.height,
|
||||
x: translation.value.x,
|
||||
y: translation.value.y,
|
||||
},
|
||||
to: {
|
||||
x: translation.value.x,
|
||||
y: translation.value.y + (shouldCloseByUpwardSwipe ? -window.innerHeight : window.innerHeight),
|
||||
width: sourceRect.width,
|
||||
height: sourceRect.height,
|
||||
x: sourceRect.x,
|
||||
y: sourceRect.y,
|
||||
},
|
||||
duration: 200,
|
||||
duration: props.closeAnimDuration,
|
||||
easing: easing_easeInOutQuad,
|
||||
apply: (state) => {
|
||||
size.value.width = state.width;
|
||||
size.value.height = state.height;
|
||||
translation.value.x = state.x;
|
||||
translation.value.y = state.y;
|
||||
},
|
||||
@@ -417,40 +437,52 @@ onBeforeUnmount(() => {
|
||||
});
|
||||
//#endregion
|
||||
|
||||
onMounted(() => {
|
||||
// 画像の初期位置・サイズをsourceElementの位置に合わせてdefaultの位置にアニメーションする
|
||||
if (props.image.sourceElement != null && props.activated) {
|
||||
const elementStyles = window.getComputedStyle(props.image.sourceElement);
|
||||
const fit = elementStyles.objectFit;
|
||||
function getSizeAndTranslationForSourceElement() {
|
||||
const elementStyles = window.getComputedStyle(props.image.sourceElement);
|
||||
const fit = elementStyles.objectFit;
|
||||
|
||||
const sourceRect = props.image.sourceElement.getBoundingClientRect();
|
||||
if (fit === 'contain') {
|
||||
const sourceAspectRatio = sourceRect.width / sourceRect.height;
|
||||
const imageAspectRatio = props.image.width / props.image.height;
|
||||
const sourceRect = props.image.sourceElement.getBoundingClientRect();
|
||||
if (fit === 'contain') {
|
||||
const sourceAspectRatio = sourceRect.width / sourceRect.height;
|
||||
const imageAspectRatio = props.image.width / props.image.height;
|
||||
|
||||
if (sourceAspectRatio > imageAspectRatio) {
|
||||
// 横長の画像
|
||||
const newWidth = sourceRect.height * imageAspectRatio;
|
||||
const newHeight = sourceRect.height;
|
||||
size.value.width = newWidth;
|
||||
size.value.height = newHeight;
|
||||
translation.value.x = sourceRect.left + (sourceRect.width - newWidth) / 2;
|
||||
translation.value.y = sourceRect.top;
|
||||
} else {
|
||||
// 縦長の画像
|
||||
const newWidth = sourceRect.width;
|
||||
const newHeight = sourceRect.width / imageAspectRatio;
|
||||
size.value.width = newWidth;
|
||||
size.value.height = newHeight;
|
||||
translation.value.x = sourceRect.left;
|
||||
translation.value.y = sourceRect.top + (sourceRect.height - newHeight) / 2;
|
||||
}
|
||||
} else {
|
||||
size.value.width = sourceRect.width;
|
||||
size.value.height = sourceRect.height;
|
||||
translation.value.x = sourceRect.left;
|
||||
translation.value.y = sourceRect.top;
|
||||
if (sourceAspectRatio > imageAspectRatio) { // 横長
|
||||
const newWidth = sourceRect.height * imageAspectRatio;
|
||||
const newHeight = sourceRect.height;
|
||||
return {
|
||||
width: newWidth,
|
||||
height: newHeight,
|
||||
x: sourceRect.left + (sourceRect.width - newWidth) / 2,
|
||||
y: sourceRect.top,
|
||||
};
|
||||
} else { // 縦長
|
||||
const newWidth = sourceRect.width;
|
||||
const newHeight = sourceRect.width / imageAspectRatio;
|
||||
return {
|
||||
width: newWidth,
|
||||
height: newHeight,
|
||||
x: sourceRect.left,
|
||||
y: sourceRect.top + (sourceRect.height - newHeight) / 2,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
width: sourceRect.width,
|
||||
height: sourceRect.height,
|
||||
x: sourceRect.left,
|
||||
y: sourceRect.top,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 画像の初期位置・サイズをsourceElementの位置に合わせてneutralの位置にアニメーションする
|
||||
if (props.image.sourceElement != null && props.activated) {
|
||||
const sourceRect = getSizeAndTranslationForSourceElement();
|
||||
size.value.width = sourceRect.width;
|
||||
size.value.height = sourceRect.height;
|
||||
translation.value.x = sourceRect.x;
|
||||
translation.value.y = sourceRect.y;
|
||||
|
||||
beginAnimation({
|
||||
from: {
|
||||
@@ -465,7 +497,7 @@ onMounted(() => {
|
||||
x: neutralTranslation.x,
|
||||
y: neutralTranslation.y,
|
||||
},
|
||||
duration: 300,
|
||||
duration: props.openAnimDuration,
|
||||
easing: easing_easeInOutQuad,
|
||||
apply: (state) => {
|
||||
size.value.width = state.width;
|
||||
|
||||
@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
:leaveActiveClass="prefer.s.animation ? $style.transition_root_leaveActive : ''"
|
||||
:enterFromClass="prefer.s.animation ? $style.transition_root_enterFrom : ''"
|
||||
:leaveToClass="prefer.s.animation ? $style.transition_root_leaveTo : ''"
|
||||
:duration="300"
|
||||
:duration="{ enter: prefer.s.animation ? openAnimDuration : 0, leave: prefer.s.animation ? closeAnimDuration : 0 }"
|
||||
appear
|
||||
@afterLeave="emit('closed')"
|
||||
>
|
||||
@@ -23,6 +23,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<XItem
|
||||
:image="image"
|
||||
:activated="activatedIndexes.has(i)"
|
||||
:openAnimDuration="openAnimDuration"
|
||||
:closeAnimDuration="closeAnimDuration"
|
||||
@close="onItemClose"
|
||||
@horizontalSwipe="onHorizontalSwipe"
|
||||
@prev="onPrev"
|
||||
@@ -61,6 +63,8 @@ watch(currentIndex, (newIndex) => {
|
||||
activatedIndexes.value.add(newIndex);
|
||||
}, { immediate: true });
|
||||
|
||||
const openAnimDuration = 200;
|
||||
const closeAnimDuration = 200;
|
||||
const zIndex = os.claimZIndex('high');
|
||||
const showing = ref(true);
|
||||
const screenWidth = ref(window.innerWidth);
|
||||
@@ -116,11 +120,13 @@ function onItemClose() {
|
||||
<style lang="scss" module>
|
||||
.transition_root_enterActive {
|
||||
> .bg {
|
||||
transition: opacity 300ms; // 子Itemコンポーネントがフェードイン/アウトするdurationと合わせる
|
||||
transition: opacity v-bind("openAnimDuration + 'ms'"); // 子Itemコンポーネントがフェードイン/アウトするdurationと合わせる
|
||||
}
|
||||
}
|
||||
.transition_root_leaveActive {
|
||||
transition: opacity 300ms; // 子Itemコンポーネントがフェードイン/アウトするdurationと合わせる
|
||||
> .bg {
|
||||
transition: opacity v-bind("closeAnimDuration + 'ms'"); // 子Itemコンポーネントがフェードイン/アウトするdurationと合わせる
|
||||
}
|
||||
}
|
||||
.transition_root_enterFrom {
|
||||
> .bg {
|
||||
@@ -128,7 +134,9 @@ function onItemClose() {
|
||||
}
|
||||
}
|
||||
.transition_root_leaveTo {
|
||||
opacity: 0;
|
||||
> .bg {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.root {
|
||||
|
||||
Reference in New Issue
Block a user