|
@@ -0,0 +1,304 @@
|
|
|
|
+<template>
|
|
|
|
+ <div
|
|
|
|
+ class="history-view"
|
|
|
|
+ @touchstart.passive="onTouchStart"
|
|
|
|
+ @touchmove.passive="onTouchMove"
|
|
|
|
+ @touchend="onTouchEnd"
|
|
|
|
+ @touchcancel="onTouchCancel"
|
|
|
|
+ >
|
|
|
|
+ <div
|
|
|
|
+ class="gear-wrap"
|
|
|
|
+ @click="doTest"
|
|
|
|
+ >
|
|
|
|
+ <img
|
|
|
|
+ v-show="gearStatus==='idle'"
|
|
|
|
+ class="gear gear-static-1"
|
|
|
|
+ src="@/assets/images/gear-idle.png"
|
|
|
|
+ alt=""
|
|
|
|
+ draggable="false"
|
|
|
|
+ >
|
|
|
|
+ <img
|
|
|
|
+ v-show="gearStatus==='clockwise'"
|
|
|
|
+ class="gear gear-clockwise"
|
|
|
|
+ src="@/assets/images/gear-clockwise.png"
|
|
|
|
+ alt=""
|
|
|
|
+ draggable="false"
|
|
|
|
+ >
|
|
|
|
+ <img
|
|
|
|
+ v-show="gearStatus==='countercockwise'"
|
|
|
|
+ class="gear gear-counterclockwise"
|
|
|
|
+ src="@/assets/images/gear-counterclockwise.png"
|
|
|
|
+ alt=""
|
|
|
|
+ draggable="false"
|
|
|
|
+ >
|
|
|
|
+ </div>
|
|
|
|
+ <div
|
|
|
|
+ class="time-axis-wrap"
|
|
|
|
+ :style="{
|
|
|
|
+ left: timeAxisLeft,
|
|
|
|
+ }"
|
|
|
|
+ >
|
|
|
|
+ <img
|
|
|
|
+ class="time-axis one"
|
|
|
|
+ src="@/assets/images/time-axis.png"
|
|
|
|
+ alt=""
|
|
|
|
+ draggable="false"
|
|
|
|
+ >
|
|
|
|
+ <img
|
|
|
|
+ class="time-axis two"
|
|
|
|
+ src="@/assets/images/time-axis.png"
|
|
|
|
+ alt=""
|
|
|
|
+ draggable="false"
|
|
|
|
+ >
|
|
|
|
+ </div>
|
|
|
|
+ <div
|
|
|
|
+ class="test"
|
|
|
|
+ :style="{
|
|
|
|
+ left: testLeft,
|
|
|
|
+ }"
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script>
|
|
|
|
+import { reactive, toRefs, ref, watch, onMounted, onBeforeUnmount, } from 'vue'
|
|
|
|
+
|
|
|
|
+export default {
|
|
|
|
+ setup () {
|
|
|
|
+ // 时代阶段
|
|
|
|
+ const stageList = [
|
|
|
|
+ {
|
|
|
|
+ name: '开埠通商',
|
|
|
|
+ startTime: '1843',
|
|
|
|
+ endTime: '1894',
|
|
|
|
+ startTimeFriendly: '十九世纪四十年代',
|
|
|
|
+ endTimeFriendly: '十九世纪九十年代',
|
|
|
|
+ components: '上海近代工业蹒跚起步',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ name: '曲折发展',
|
|
|
|
+ startTime: '1895',
|
|
|
|
+ endTime: '1936',
|
|
|
|
+ startTimeFriendly: '十九世纪九十年代',
|
|
|
|
+ endTimeFriendly: '二十世纪三十年代',
|
|
|
|
+ components: '上海近代工业起起伏伏',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ name: '步履维艰',
|
|
|
|
+ startTime: '1937',
|
|
|
|
+ endTime: '1949',
|
|
|
|
+ startTimeFriendly: '二十世纪三十年代',
|
|
|
|
+ endTimeFriendly: '二十世纪五十年代',
|
|
|
|
+ components: '上海民族工业几经崩溃',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ name: '筚路蓝缕',
|
|
|
|
+ startTime: '1950',
|
|
|
|
+ endTime: '1978',
|
|
|
|
+ startTimeFriendly: '二十世纪五十年代',
|
|
|
|
+ endTimeFriendly: '二十世纪七十年代',
|
|
|
|
+ components: '上海现代工业扬帆起航',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ name: '改革开放',
|
|
|
|
+ startTime: '1979',
|
|
|
|
+ endTime: '1996',
|
|
|
|
+ startTimeFriendly: '二十世纪七十年代',
|
|
|
|
+ endTimeFriendly: '二十世纪九十年代',
|
|
|
|
+ components: '上海工业凤凰涅槃',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ name: '战略负重',
|
|
|
|
+ startTime: '1997',
|
|
|
|
+ endTime: '2011',
|
|
|
|
+ startTimeFriendly: '二十世纪九十年代',
|
|
|
|
+ endTimeFriendly: '本世纪一十年代',
|
|
|
|
+ components: '上海工业筑梦前行',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ name: '创新驱动',
|
|
|
|
+ startTime: '2012',
|
|
|
|
+ endTime: '2020',
|
|
|
|
+ startTimeFriendly: '本世纪一十年代',
|
|
|
|
+ endTimeFriendly: '本世纪二十年代',
|
|
|
|
+ components: '上海工业转型升级',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ name: '追梦未来',
|
|
|
|
+ startTime: '2021',
|
|
|
|
+ endTime: '2035',
|
|
|
|
+ startTimeFriendly: '本世纪二十年代',
|
|
|
|
+ endTimeFriendly: '本世纪三十年代',
|
|
|
|
+ components: '上海工业再创辉煌',
|
|
|
|
+ },
|
|
|
|
+ ]
|
|
|
|
+ const currentTimeIdx = ref(0)
|
|
|
|
+
|
|
|
|
+ // 用户操作相关
|
|
|
|
+ const isMouseDown = ref(false)
|
|
|
|
+ const lastMoveEventTimeStamp = ref(0)
|
|
|
|
+ const lastTouchPos = ref(0)
|
|
|
|
+
|
|
|
|
+ // 镜头平移相关
|
|
|
|
+ const moveSpeed = ref(0)
|
|
|
|
+ const translateLength = ref(0)
|
|
|
|
+ const maxTranslateLength = ref(1000000)
|
|
|
|
+
|
|
|
|
+ // 用户操作改变镜头平移速度
|
|
|
|
+ function onTouchStart(e) {
|
|
|
|
+ isMouseDown.value = true
|
|
|
|
+ moveSpeed.value = 0
|
|
|
|
+ lastMoveEventTimeStamp.value = 0
|
|
|
|
+ lastAnimationTimeStamp = Date.now()
|
|
|
|
+ lastTouchPos.value = e.changedTouches[0].clientX
|
|
|
|
+ console.log('start!')
|
|
|
|
+ }
|
|
|
|
+ function onTouchEnd(e) {
|
|
|
|
+ isMouseDown.value = false
|
|
|
|
+ console.log('end!')
|
|
|
|
+ }
|
|
|
|
+ function onTouchCancel() {
|
|
|
|
+ isMouseDown.value = false
|
|
|
|
+ }
|
|
|
|
+ function onTouchMove(e) {
|
|
|
|
+ console.log('move!')
|
|
|
|
+ if (isMouseDown.value && e.changedTouches.length === 1) {
|
|
|
|
+ // 疯狂操作的极端情况下两个时间戳之间的时差会不合理,甚至为0
|
|
|
|
+ if (lastMoveEventTimeStamp.value && (e.timeStamp - lastMoveEventTimeStamp.value > 1)) {
|
|
|
|
+ // 更新speed
|
|
|
|
+ console.log('shabi')
|
|
|
|
+ const currentMoveSpeed = - (e.changedTouches[0].clientX - lastTouchPos.value) / (e.timeStamp - lastMoveEventTimeStamp.value) * 0.5
|
|
|
|
+ moveSpeed.value = moveSpeed.value * 0.9 + currentMoveSpeed * 0.1
|
|
|
|
+ lastTouchPos.value = e.changedTouches[0].clientX
|
|
|
|
+ }
|
|
|
|
+ lastMoveEventTimeStamp.value = e.timeStamp
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 动画帧相关
|
|
|
|
+ */
|
|
|
|
+ let lastAnimationTimeStamp = 0
|
|
|
|
+ let animationFrameId = null
|
|
|
|
+ // 在每一帧更新镜头速度、位置
|
|
|
|
+ function animationFrameTask() {
|
|
|
|
+ const timeStamp = Date.now()
|
|
|
|
+ const timeElapsed = timeStamp - lastAnimationTimeStamp
|
|
|
|
+
|
|
|
|
+ // 速度减慢
|
|
|
|
+ if (moveSpeed.value > 0) {
|
|
|
|
+ moveSpeed.value -= ($.valueisMobile ? 0.001 : 0.003) * timeElapsed
|
|
|
|
+ if (moveSpeed.value < 0) {
|
|
|
|
+ moveSpeed.value = 0
|
|
|
|
+ }
|
|
|
|
+ } else if (moveSpeed.value < 0) {
|
|
|
|
+ moveSpeed.value += ($.valueisMobile ? 0.001 : 0.003) * timeElapsed
|
|
|
|
+ if (moveSpeed.value > 0) {
|
|
|
|
+ moveSpeed.value = 0
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 根据速度更新位置
|
|
|
|
+ translateLength.value += moveSpeed.value * timeElapsed
|
|
|
|
+ if (translateLength.value < 0) {
|
|
|
|
+ translateLength.value = 0
|
|
|
|
+ moveSpeed.value = 0
|
|
|
|
+ } else if (translateLength.value > maxTranslateLength.value) {
|
|
|
|
+ translateLength.value = maxTranslateLength.value
|
|
|
|
+ moveSpeed.value = 0
|
|
|
|
+ }
|
|
|
|
+ console.log(translateLength.value)
|
|
|
|
+ lastAnimationTimeStamp = timeStamp
|
|
|
|
+ animationFrameId = requestAnimationFrame(animationFrameTask)
|
|
|
|
+ }
|
|
|
|
+ onMounted(() => {
|
|
|
|
+ animationFrameId = requestAnimationFrame(animationFrameTask)
|
|
|
|
+ })
|
|
|
|
+ onBeforeUnmount(() => {
|
|
|
|
+ cancelAnimationFrame(animationFrameId)
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ // 动画
|
|
|
|
+ // 恢复历史位置
|
|
|
|
+ // if (this.longImageTranslateLengthRecord) {
|
|
|
|
+ // this.translateLength = this.longImageTranslateLengthRecord
|
|
|
|
+ // this.setLongImageTranslateLengthRecord(null)
|
|
|
|
+ // }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // 根据镜头平移距离计算当前时代
|
|
|
|
+ watch(translateLength, (vNew) => {
|
|
|
|
+ }, {
|
|
|
|
+ immediate: true,
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ const testSpeedRate = 1
|
|
|
|
+ const initialTestLeft = `1000px`
|
|
|
|
+ const testLeft = ref(initialTestLeft)
|
|
|
|
+ watch(translateLength, (vNew) => {
|
|
|
|
+ console.log('sdjgflksklfg', vNew)
|
|
|
|
+ testLeft.value = `calc(${initialTestLeft} - ${vNew * testSpeedRate}px)`
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ // 时间轴位移
|
|
|
|
+ const timeAxisLeft = ref('0px')
|
|
|
|
+ watch(translateLength, (vNew) => {
|
|
|
|
+ timeAxisLeft.value = `${-(vNew % 1920)}px`
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ // 齿轮
|
|
|
|
+ const gearStatus = ref('idle')
|
|
|
|
+ function doTest() {
|
|
|
|
+ gearStatus.value = 'clockwise'
|
|
|
|
+ setTimeout(() => {
|
|
|
|
+ gearStatus.value = 'idle'
|
|
|
|
+ }, 2000)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ onTouchStart,
|
|
|
|
+ onTouchEnd,
|
|
|
|
+ onTouchCancel,
|
|
|
|
+ onTouchMove,
|
|
|
|
+ testLeft,
|
|
|
|
+ timeAxisLeft,
|
|
|
|
+ gearStatus,
|
|
|
|
+ doTest,
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style lang="less" scoped>
|
|
|
|
+.history-view {
|
|
|
|
+ position: absolute;
|
|
|
|
+ left: 0;
|
|
|
|
+ top: 0;
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ >.gear-wrap {
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: 0;
|
|
|
|
+ left: 50%;
|
|
|
|
+ transform: translateX(-50%);
|
|
|
|
+ width: calc(100vw * 940 / 1920);
|
|
|
|
+ >img.gear{
|
|
|
|
+ width: 100%;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ >.time-axis-wrap{
|
|
|
|
+ top: 54%;
|
|
|
|
+ position: absolute;
|
|
|
|
+ display: flex;
|
|
|
|
+ >.time-axis{
|
|
|
|
+ width: 1920px;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ >.test{
|
|
|
|
+ position: absolute;
|
|
|
|
+ width: 100px;
|
|
|
|
+ height: 100px;
|
|
|
|
+ background-color: red;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+</style>
|