Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Touch scrolling zooming non native #584

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<meta name="fragment" content="!">

<!-- mobile -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-title" content="Kinopio">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
Expand Down
43 changes: 32 additions & 11 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,6 @@ const isSpacePage = computed(() => store.getters.isSpacePage)

// styles and position

const pageWidth = computed(() => {
if (!isSpacePage.value) { return }
const size = Math.max(store.state.pageWidth, store.state.viewportWidth)
return size + 'px'
})
const pageHeight = computed(() => {
if (!isSpacePage.value) { return }
const size = Math.max(store.state.pageHeight, store.state.viewportHeight)
return size + 'px'
})
const pageCursor = computed(() => {
const isPanning = store.state.currentUserIsPanning
const isPanningReady = store.state.currentUserIsPanningReady
Expand All @@ -56,6 +46,21 @@ const pageCursor = computed(() => {
}
return undefined
})
const styles = computed(() => {
if (!isSpacePage.value) { return }
let width = Math.max(store.state.pageWidth, store.state.viewportWidth)
let height = Math.max(store.state.pageHeight, store.state.viewportHeight)
const zoom = spaceZoomDecimal.value
if (zoom > 1) {
width = Math.round(width * zoom)
height = Math.round(height * zoom)
}
return {
width: width + 'px',
height: height + 'px',
cursor: pageCursor.value
}
})
const spaceZoomDecimal = computed(() => store.getters.spaceZoomDecimal)

// users
Expand Down Expand Up @@ -156,13 +161,29 @@ const updateMetaRSSFeed = () => {
link.href = url
head.appendChild(link)
}

// prevent native touch scrolling

const preventTouchScrolling = (event) => {
if (!isSpacePage.value) { return }
const isDialogScope = event.target.closest('dialog')
if (isDialogScope) { return }
event.preventDefault()
store.commit('currentUserIsPanning', true)
}
</script>

<template lang='pug'>
.app(
@pointermove="broadcastUserLabelCursor"
@touchstart="isTouchDevice"
:style="{ width: pageWidth, height: pageHeight, cursor: pageCursor }"

@touchmove="preventTouchScrolling"
@gesturestart="preventTouchScrolling"
@gesturechange="preventTouchScrolling"
@gestureend="preventTouchScrolling"

:style="styles"
:class="{ 'no-background': !isSpacePage, 'is-dark-theme': isThemeDark }"
:data-current-user-id="currentUserId"
)
Expand Down
7 changes: 0 additions & 7 deletions src/components/OutsideSpaceBackground.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,6 @@ const spaceZoomDecimal = computed(() => store.getters.spaceZoomDecimal)
const outsideSpaceBackgroundIsStatic = computed(() => store.state.currentUser.outsideSpaceBackgroundIsStatic)
const backgroundTintColor = computed(() => store.state.currentSpace.backgroundTint)
const isThemeDark = computed(() => store.getters['themes/isThemeDark'])
const preventTouchScrolling = (event) => {
const shouldPrevent = store.state.currentUserIsResizingBox || store.state.currentUserIsPaintingLocked
if (shouldPrevent) {
event.preventDefault()
}
}

// update color

Expand Down Expand Up @@ -155,7 +149,6 @@ const styles = computed(() => {
<template lang="pug">
canvas#outside-space-background(
:style="styles"
@touchmove="preventTouchScrolling"
)
</template>

Expand Down
51 changes: 33 additions & 18 deletions src/components/Slider.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@ const badgeElement = ref(null)
const progressElement = ref(null)
const buttonElement = ref(null)

let unsubscribe
// let unsubscribe

onMounted(() => {
// bind events to window to receive events when mouse is outside window
window.addEventListener('mousemove', dragPlayhead)
// window.addEventListener('mousemove', dragPlayhead)
window.addEventListener('mouseup', endMovePlayhead)
window.addEventListener('touchend', endMovePlayhead)
updateButtonPosition()
unsubscribe = store.subscribe(mutation => {
if (mutation.type === 'spaceZoomPercent') {
updateButtonPosition()
}
})
// unsubscribe = store.subscribe(mutation => {
// if (mutation.type === 'spaceZoomPercent') {
// updateButtonPosition()
// }
// })
})
onBeforeUnmount(() => {
unsubscribe()
window.removeEventListener('mousemove', dragPlayhead)
// unsubscribe()
// window.removeEventListener('mousemove', dragPlayhead)
window.removeEventListener('mouseup', endMovePlayhead)
window.removeEventListener('touchend', endMovePlayhead)
})
Expand All @@ -38,14 +38,16 @@ const props = defineProps({
minValue: Number,
maxValue: Number,
value: Number,
defaultValue: Number,
animateJiggleRight: Boolean,
animateJiggleLeft: Boolean,
minKeyboardShortcut: String,
shouldHideBadge: Boolean
})
watch(() => props.value, (value, prevValue) => {
updateButtonPosition()
})
// watch(() => props.value, (value, prevValue) => {
// console.log('🎃🎃spaceZoomPercent',value, props.defaultValue)
// // updateButtonPosition()
// })

const state = reactive({
playheadIsBeingDragged: false,
Expand All @@ -54,9 +56,10 @@ const state = reactive({

// badge

const defaultValue = computed(() => props.defaultValue || props.maxValue)
const zoomPercentBadgeIsVisible = computed(() => {
if (props.shouldHideBadge) { return }
if (props.value !== props.maxValue) {
if (props.value !== defaultValue.value) {
return true
} else {
return false
Expand All @@ -78,11 +81,12 @@ const removeAnimations = () => {
const integerValue = computed(() => Math.round(props.value))
const currentValueIsMin = computed(() => integerValue.value === props.minValue)
const sliderValue = computed(() => {
const value = utils.percentageBetween({
let value = utils.percentageBetween({
value: props.value,
min: props.minValue,
max: props.maxValue
})
value = Math.round(value)
return value
})

Expand All @@ -98,7 +102,7 @@ const movePlayhead = (event) => {
percent = Math.min(percent, 100)
percent = Math.max(percent, 0)
updateButtonPosition()
emit('updatePlayhead', percent)
updatePlayhead(percent)
}
const updateButtonPosition = () => {
if (!progressElement.value) { return }
Expand Down Expand Up @@ -136,7 +140,7 @@ const dragPlayheadWheel = (event) => {
percent += speed
percent = Math.min(percent, 100)
percent = Math.max(percent, 0)
emit('updatePlayhead', percent)
updatePlayhead(percent)
}
const dragPlayhead = (event) => {
if (!state.playheadIsBeingDragged) { return }
Expand All @@ -160,11 +164,21 @@ const stopMovingPlayhead = () => {

const resetPlayhead = async () => {
state.playheadIsBeingDragged = false
emit('updatePlayhead', props.maxValue)
const value = utils.percentageBetween({
value: defaultValue.value,
min: props.minValue,
max: props.maxValue
})
updatePlayhead(value)
emit('resetPlayhead')
await nextTick()
updateButtonPosition()
}

const updatePlayhead = (value) => {
emit('updatePlayhead', value)
}

</script>

<template lang="pug">
Expand All @@ -186,6 +200,7 @@ const resetPlayhead = async () => {
:data-max="props.maxValue"
:data-min="props.minValue"
)
//- percent badge
span.badge.info.zoom-percent-badge(
ref="badgeElement"
v-if="zoomPercentBadgeIsVisible"
Expand All @@ -198,7 +213,7 @@ const resetPlayhead = async () => {
img.icon.close(src="@/assets/add.svg")

progress(
:value="sliderValue"
:value="props.value"
:max="props.maxValue"
:min="props.minValue"
ref="progressElement"
Expand Down
39 changes: 21 additions & 18 deletions src/components/SpaceZoom.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ let unsubscribe
onMounted(() => {
unsubscribe = store.subscribe((mutation, state) => {
if (mutation.type === 'triggerSpaceZoomReset') {
updateSpaceZoomFromTrigger(max.value)
updateSpaceZoomFromTrigger(consts.spaceZoom.default) // 100
window.scrollTo(0, 0)
} else if (mutation.type === 'triggerCenterZoomOrigin') {
centerZoomOrigin()
updateZoomOriginToCenter()
} else if (mutation.type === 'triggerSpaceZoomOutMax') {
zoomOutOrInMax()
}
Expand All @@ -32,16 +32,17 @@ const state = reactive({
animateJiggleLeft: false
})

const max = computed(() => consts.spaceZoom.max) // 100
const max = computed(() => consts.spaceZoom.max) // 200~
const min = computed(() => consts.spaceZoom.min) // 20
const spaceZoomPercent = computed(() => store.state.spaceZoomPercent)
const spaceZoomPercent = computed(() => store.state.spaceZoomPercent) // 100
const minKeyboardShortcut = computed(() => 'Z')

const isMobileOrTouch = computed(() => {
const isMobile = utils.isMobile()
return store.isTouchDevice || isMobile
})
const closeAllDialogs = () => {
updateZoomOriginToCenter()
store.dispatch('clearMultipleSelected')
store.dispatch('closeAllDialogs')
}
Expand All @@ -61,31 +62,32 @@ const updateSpaceZoomFromTrigger = (percent) => {
const updateSpaceZoomPercent = (percent) => {
percent = percent / 100
percent = Math.round(min.value + (max.value - min.value) * percent)
const isPrev = percent === store.state.spaceZoomPercent
if (isPrev) { return }
store.commit('spaceZoomPercent', percent)
}
const centerZoomOrigin = () => {
const scroll = { x: window.scrollX, y: window.scrollY }
const origin = {
x: scroll.x + (store.state.viewportWidth / 6),
y: scroll.y + (store.state.viewportHeight / 6)
}
store.dispatch('zoomOrigin', origin)
}
const zoomOutOrInMax = () => {
centerZoomOrigin()
updateZoomOriginToCenter()
if (store.state.spaceZoomPercent === min.value) {
store.commit('spaceZoomPercent', max.value)
} else {
store.commit('spaceZoomPercent', min.value)
}
}

// slider
// zoom origin

const updateSpaceZoom = (percent) => {
centerZoomOrigin()
updateSpaceZoomPercent(percent)
const updateZoomOriginToCenter = () => {
const scroll = { x: window.scrollX, y: window.scrollY }
const origin = {
x: scroll.x + (store.state.viewportWidth / 2),
y: scroll.y + (store.state.viewportHeight / 2)
}
store.commit('zoomOrigin', origin)
}

// slider

const resetZoom = () => {
store.commit('zoomOrigin', { x: 0, y: 0 })
}
Expand All @@ -107,11 +109,12 @@ const handleMouseLeave = (event) => {
<template lang="pug">
.space-zoom(v-if="!isMobileOrTouch" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave")
Slider(
@updatePlayhead="updateSpaceZoom"
@updatePlayhead="updateSpaceZoomPercent"
@resetPlayhead="resetZoom"
:minValue="min"
:value="spaceZoomPercent"
:maxValue="max"
:defaultValue="consts.spaceZoom.default"
:animateJiggleRight="state.animateJiggleRight"
:animateJiggleLeft="state.animateJiggleLeft"
@removeAnimations="removeAnimations"
Expand Down
5 changes: 3 additions & 2 deletions src/consts.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ const env = import.meta.env

export default {
spaceZoom: {
max: 100,
min: 20
max: 180,
min: 20,
default: 100
},
spaceBetweenCards: 12,
defaultCharacterLimit: 300,
Expand Down
6 changes: 0 additions & 6 deletions src/store/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -2110,12 +2110,6 @@ const store = createStore({
isTouchDevice: (state) => {
return state.isTouchDevice || utils.isMobile() || consts.isSecureAppContext
},
zoomTransform: (state, getters) => {
const zoom = getters.spaceZoomDecimal
const origin = state.zoomOrigin
const transform = `translate(${origin.x}px, ${origin.y}px) scale(${zoom}) translate(-${origin.x}px, -${origin.y}px)`
return transform
},
windowScrollWithSpaceOffset: (state) => () => {
let scroll = { x: window.scrollX, y: window.scrollY }
return utils.updatePositionWithSpaceOffset(scroll)
Expand Down
30 changes: 26 additions & 4 deletions src/views/Space.vue
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,35 @@ const users = computed(() => {
const spaceZoomDecimal = computed(() => store.getters.spaceZoomDecimal)
const pageHeight = computed(() => store.state.pageHeight)
const pageWidth = computed(() => store.state.pageWidth)
const updateStylesWithZoomTransform = (styles) => {
const zoom = spaceZoomDecimal.value
const origin = store.state.zoomOrigin
styles.transform = `translate(${origin.x}px, ${origin.y}px) scale(${zoom}) translate(-${origin.x}px, -${origin.y}px)`
if (zoom > 1) {
// window.scrollBy(origin.x, origin.y, 'instant')

// TODO get current page/prev zoom value from rel data , - new zoom value = delta
// use delta to calc window.scrollby
styles.transform = `scale(${zoom})`

// styles.transform = `scale(${zoom})`
// translate(${origin.x}px, ${origin.y}px
// styles.transformOrigin = `${origin.x}px ${origin.y}px`
// console.log(styles.transformOrigin, origin)
}
return styles
}
const styles = computed(() => {
const zoom = 1 / spaceZoomDecimal.value
return {
width: `${pageWidth.value * zoom}px`,
height: `${pageHeight.value * zoom}px`,
transform: store.getters.zoomTransform
let styles = {
// width: `${pageWidth.value * zoom}px`,
// height: `${pageHeight.value * zoom}px`
}
if (zoom !== 1) {
styles.willChange = 'transform'
}
styles = updateStylesWithZoomTransform(styles)
return styles
})

// page history
Expand Down