|
@@ -1,9 +1,9 @@
|
|
|
import { Component, createRef } from "react";
|
|
|
import PropTypes from "prop-types";
|
|
|
import { gsap, ScrollTrigger } from "gsap/all";
|
|
|
-import styled from "@emotion/styled";
|
|
|
import { css } from "@emotion/react";
|
|
|
-
|
|
|
+const isDebug = Number(import.meta.env.VITE_APP_SOURCE) === 1;
|
|
|
+console.log("isDebug", isDebug);
|
|
|
export default class Viewer extends Component {
|
|
|
constructor() {
|
|
|
super();
|
|
@@ -14,18 +14,22 @@ export default class Viewer extends Component {
|
|
|
this.canvasContainerRef = createRef(null);
|
|
|
this.loadingWrap = createRef(null);
|
|
|
this.viewerOffsetRef = createRef(null);
|
|
|
- this.canvasRef = createRef();
|
|
|
-
|
|
|
+ this.canvasRef = createRef(null);
|
|
|
+ this.processingRef = createRef(null);
|
|
|
+ this.preProcessingRef = createRef(null);
|
|
|
this.sequence = [];
|
|
|
this.loadedRenderPool = [];
|
|
|
this.enterTimeline = false;
|
|
|
this.exitTimeline = false;
|
|
|
this.loadComplete = false;
|
|
|
|
|
|
+ this.playBarTween = false;
|
|
|
+ this.playPreBarTween = false;
|
|
|
this.loadedCount = 0;
|
|
|
this.progress = 0;
|
|
|
this.lastFrame = -1;
|
|
|
this.floatFrame = 0;
|
|
|
+ this.frame = 0;
|
|
|
this.loadedRenderTimeout = null;
|
|
|
this.poolAnimateDelay = 40;
|
|
|
|
|
@@ -41,22 +45,31 @@ export default class Viewer extends Component {
|
|
|
height: PropTypes.string,
|
|
|
path: PropTypes.string,
|
|
|
frameCount: PropTypes.number,
|
|
|
- enterTween: PropTypes.func,
|
|
|
- exitTween: PropTypes.func,
|
|
|
+ startFrame: PropTypes.number,
|
|
|
+ enterTween: PropTypes.object,
|
|
|
+ exitTween: PropTypes.object,
|
|
|
canvasSize: PropTypes.array,
|
|
|
pause: PropTypes.object,
|
|
|
children: PropTypes.object,
|
|
|
};
|
|
|
-
|
|
|
- state = {};
|
|
|
-
|
|
|
componentWillUnmount() {
|
|
|
- this.timeline && this.timeline.kill(true);
|
|
|
+ console.error("remove-timeline");
|
|
|
+ if (this.timeline) {
|
|
|
+ this.timeline.kill(true);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
componentDidMount() {
|
|
|
+ this.fullFrameCount = this.props.frameCount;
|
|
|
+ this.frame = this.props.startFrame || 0;
|
|
|
+ if (this.props.pause) {
|
|
|
+ Object.keys(this.props.pause).forEach((index) => {
|
|
|
+ this.fullFrameCount += this.props.pause[index];
|
|
|
+ });
|
|
|
+ }
|
|
|
this.loadAssets();
|
|
|
this.canvasRef.current && this.initializeCanvas();
|
|
|
+
|
|
|
if (!this.timeline) {
|
|
|
this.initializeTimeline();
|
|
|
this.setTimeline();
|
|
@@ -64,12 +77,15 @@ export default class Viewer extends Component {
|
|
|
if (!this.enterTimeline && this.props.enterTween) {
|
|
|
this.initializeEnterTween();
|
|
|
}
|
|
|
+ if (!this.exitTimeline && this.props.exitTween) {
|
|
|
+ this.initializeExitTween();
|
|
|
+ }
|
|
|
ScrollTrigger.refresh();
|
|
|
}
|
|
|
|
|
|
loadImage(index) {
|
|
|
const img = new Image();
|
|
|
- // console.log("index", this.getSourcePath(index));
|
|
|
+
|
|
|
img.retried = 0;
|
|
|
img.src = this.getSourcePath(index);
|
|
|
img.ogSrc = img.src;
|
|
@@ -86,6 +102,7 @@ export default class Viewer extends Component {
|
|
|
if (this.frame > index && this.timeline.scrollTrigger.isActive) {
|
|
|
this.poolNewFrames(index - 1);
|
|
|
}
|
|
|
+ // var t = 100 - (this.frame / this.fullFrameCount) * 100 + "%";
|
|
|
this.loadedCount += 1;
|
|
|
if (this.loadedCount === parseFloat(this.props.frameCount) - 1) {
|
|
|
this.loadingComplete();
|
|
@@ -142,7 +159,7 @@ export default class Viewer extends Component {
|
|
|
start: "top top",
|
|
|
end: "bottom bottom",
|
|
|
ease: "none",
|
|
|
- markers: true,
|
|
|
+ markers: isDebug,
|
|
|
onUpdate: function (n) {
|
|
|
//处理processloading
|
|
|
},
|
|
@@ -173,13 +190,15 @@ export default class Viewer extends Component {
|
|
|
});
|
|
|
}
|
|
|
setTimeline() {
|
|
|
- console.log("this.fullFrameCount", this.fullFrameCount);
|
|
|
this.timeline.to(this, {
|
|
|
floatFrame: this.fullFrameCount - 1,
|
|
|
ease: "none",
|
|
|
onUpdate: () => {
|
|
|
this.frame = Math.floor(this.floatFrame);
|
|
|
- if (this.lastFrame === this.frame || this.loadedRenderPool.length > 0) {
|
|
|
+ if (
|
|
|
+ this.lastFrame === this.frame ||
|
|
|
+ this.loadedRenderPool.length === 0
|
|
|
+ ) {
|
|
|
this.renderImageToCanvas(this.frame);
|
|
|
}
|
|
|
},
|
|
@@ -187,21 +206,61 @@ export default class Viewer extends Component {
|
|
|
}
|
|
|
|
|
|
initializeEnterTween() {
|
|
|
- console.log("initializeEnterTween");
|
|
|
+ const duration = this.props.enterTween.duration || 1;
|
|
|
+ console.log("initializeEnterTween", duration, this.props.enterTween.pin);
|
|
|
+ gsap.set(this.viewerRef.current, {
|
|
|
+ yPercent: -100 * duration,
|
|
|
+ });
|
|
|
+ if (this.props.enterTween.pin !== 0) {
|
|
|
+ console.warn("tutu", this.props.enterTween.pin);
|
|
|
+ this.enterTimeline = gsap.timeline({
|
|
|
+ scrollTrigger: {
|
|
|
+ trigger: this.viewerRef.current,
|
|
|
+ scrub: true,
|
|
|
+ pin: this.props.enterTween.pin,
|
|
|
+ start: function () {
|
|
|
+ return "top top";
|
|
|
+ },
|
|
|
+ end: function () {
|
|
|
+ return "top top-=" + window.innerHeight * duration;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ initializeExitTween() {
|
|
|
+ console.log(this.props.path, "initializing exit tween ");
|
|
|
+ console.warn("this.props.exitTween", this.props.exitTween);
|
|
|
+ this.exitTimeline = gsap.timeline({
|
|
|
+ scrollTrigger: {
|
|
|
+ scrub: true,
|
|
|
+ trigger: this.containerRef.current,
|
|
|
+ pin: this.viewerRef.current,
|
|
|
+ onLeave: this.props.exitTween.onLeave,
|
|
|
+ onLeaveBack: this.props.exitTween.onLeaveBack,
|
|
|
+ onEnterBack: this.props.exitTween.onEnterBack,
|
|
|
+ start: function () {
|
|
|
+ return "bottom bottom";
|
|
|
+ },
|
|
|
+ end: function () {
|
|
|
+ return "bottom top";
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
poolNewFrames(index) {
|
|
|
- console.log("poolNewFrames", index);
|
|
|
this.loadedRenderPool.unshift(index);
|
|
|
- this.loadedRenderPool.sort(function (e, t) {
|
|
|
- return t - e;
|
|
|
+ this.loadedRenderPool.sort(function (a, b) {
|
|
|
+ return b - a;
|
|
|
});
|
|
|
this.animatePool();
|
|
|
}
|
|
|
+
|
|
|
animatePool() {
|
|
|
if (!this.loadedRenderTimeout && this.loadedRenderPool.length) {
|
|
|
this.loadedRenderTimeout = setTimeout(() => {
|
|
|
- this.loadedRenderTimeout = true;
|
|
|
+ this.loadedRenderTimeout = false;
|
|
|
var poolFrame = this.loadedRenderPool[this.loadedRenderPool.length - 1];
|
|
|
if (poolFrame <= this.frame) {
|
|
|
var remainFrame = this.loadedRenderPool.pop();
|
|
@@ -217,39 +276,88 @@ export default class Viewer extends Component {
|
|
|
renderImageToCanvas(index) {
|
|
|
if (this.sequence[index]) {
|
|
|
if (this.context.drawImage) {
|
|
|
- console.log("renderImageToCanvas", index);
|
|
|
this.context.drawImage(this.sequence[index], 0, 0);
|
|
|
this.lastFrame = index;
|
|
|
+ this.handleSyncProessBar(index);
|
|
|
} else {
|
|
|
this.initializeCanvas();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- render() {
|
|
|
- // process props
|
|
|
- this.fullFrameCount = this.props.frameCount;
|
|
|
- if (this.props.pause) {
|
|
|
- Object.keys(this.props.pause).forEach((index) => {
|
|
|
- this.fullFrameCount += this.props.pause[index];
|
|
|
- });
|
|
|
- }
|
|
|
- const Wrapper = styled.div({
|
|
|
- position: "relative",
|
|
|
- margin: "auto",
|
|
|
- textAlign: "center",
|
|
|
- pointerEvents: "none",
|
|
|
- maxWidth: "100vw",
|
|
|
+ handleSyncProessBar(index) {
|
|
|
+ const progressingPreload =
|
|
|
+ 100 - (this.frame / this.fullFrameCount) * 100 + "%";
|
|
|
+ const progressing = 100 - (index / this.fullFrameCount) * 100 + "%";
|
|
|
+ this.playPreBarTween = gsap.to(this.preProcessingRef.current, {
|
|
|
+ duration: 0.05,
|
|
|
+ right: progressingPreload,
|
|
|
+ ease: "none",
|
|
|
});
|
|
|
+ this.playBarTween = gsap.to(this.processingRef.current, {
|
|
|
+ duration: 0.05,
|
|
|
+ right: progressing,
|
|
|
+ ease: "none",
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ render() {
|
|
|
return (
|
|
|
<>
|
|
|
- <Wrapper
|
|
|
+ <div
|
|
|
+ css={css`
|
|
|
+ position: "relative";
|
|
|
+ margin: "auto";
|
|
|
+ textalign: "center";
|
|
|
+ pointerevents: "none";
|
|
|
+ maxwidth: "100vw";
|
|
|
+ `}
|
|
|
ref={this.containerRef}
|
|
|
style={{ height: this.props.height || "500vh" }}
|
|
|
>
|
|
|
<div>{this.props.name}</div>
|
|
|
<div className="loading-wrap" ref={this.loadingWrap}></div>
|
|
|
|
|
|
+ <div
|
|
|
+ css={css`
|
|
|
+ position: fixed;
|
|
|
+ top: calc(100vh - 4px);
|
|
|
+ // top: calc(var(--vh, 1vh) * 100 - 4px);
|
|
|
+ left: 0;
|
|
|
+ width: 100vw;
|
|
|
+ max-width: 100%;
|
|
|
+ border-top: 1px solid rgba(33, 33, 44, 0.6);
|
|
|
+ background-color: rgba(17, 17, 34, 0.6);
|
|
|
+ height: 4px;
|
|
|
+ z-index: 9;
|
|
|
+ `}
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ css={css`
|
|
|
+ position: absolute;
|
|
|
+ width: auto;
|
|
|
+ height: 4px;
|
|
|
+ left: 0;
|
|
|
+ bottom: 0;
|
|
|
+ z-index: 10;
|
|
|
+ background-color: rgba(120, 120, 163, 0.33);
|
|
|
+ `}
|
|
|
+ ref={this.preProcessingRef}
|
|
|
+ ></div>
|
|
|
+ <div
|
|
|
+ css={css`
|
|
|
+ position: absolute;
|
|
|
+ width: auto;
|
|
|
+ height: 4px;
|
|
|
+ left: 0;
|
|
|
+ bottom: 0;
|
|
|
+ z-index: 10;
|
|
|
+ background-color: hsla(0, 0%, 79.2%, 0.5);
|
|
|
+ `}
|
|
|
+ ref={this.processingRef}
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
<div ref={this.viewerRef}>
|
|
|
<div style={{ overflow: "hidden" }}>
|
|
|
<canvas
|
|
@@ -265,9 +373,8 @@ export default class Viewer extends Component {
|
|
|
></canvas>
|
|
|
</div>
|
|
|
</div>
|
|
|
-
|
|
|
<>{this.props.children}</>
|
|
|
- </Wrapper>
|
|
|
+ </div>
|
|
|
</>
|
|
|
);
|
|
|
}
|