Skip to content

Instantly share code, notes, and snippets.

@harunpehlivan
Created June 5, 2021 07:26
Show Gist options
  • Save harunpehlivan/dbc149a4368216a5737c0c91bf7f12d7 to your computer and use it in GitHub Desktop.
Save harunpehlivan/dbc149a4368216a5737c0c91bf7f12d7 to your computer and use it in GitHub Desktop.
properties - motion path
main#home-page(data-wrapper="", role="main")
.container
h2.font-sz-3xl.font-sans.font-400 Properties
.animation-containers.jumbotron.jumbotron-fluid.my-2.p-4.rounded-lg.box-shadow.text-dark.bg-warning
.motion-path-demo
.flex.justify-evenly.flex-wrap
.motion-path
h2.text-center.text-lg.font-bold Motion Path/Offset Path
.relative
.small.square.shadow.el-initial
.small.square.el.el-1
svg(width="256", height="112", viewbox="0 0 256 112")
path#follow-path(
fill="none",
stroke="currentColor",
stroke-width="1",
d="M8,56 C8,33.90861 25.90861,16 48,16 C70.09139,16 88,33.90861 88,56 C88,78.09139 105.90861,92 128,92 C150.09139,92 160,72 160,56 C160,40 148,24 128,24 C108,24 96,40 96,56 C96,72 105.90861,92 128,92 C154,93 168,78 168,56 C168,33.90861 185.90861,16 208,16 C230.09139,16 248,33.90861 248,56 C248,78.09139 230.09139,96 208,96 L48,96 C25.90861,96 8,78.09139 8,56 Z"
)
.motion-path
h2.text-center.text-lg.font-bold getTotalLength()
.relative
.small.square.shadow.el-initial
.small.square.el.el-2
svg(width="256", height="112", viewbox="0 0 256 112")
path#follow-path(
fill="none",
stroke="currentColor",
stroke-width="1",
d="M8,56 C8,33.90861 25.90861,16 48,16 C70.09139,16 88,33.90861 88,56 C88,78.09139 105.90861,92 128,92 C150.09139,92 160,72 160,56 C160,40 148,24 128,24 C108,24 96,40 96,56 C96,72 105.90861,92 128,92 C154,93 168,78 168,56 C168,33.90861 185.90861,16 208,16 C230.09139,16 248,33.90861 248,56 C248,78.09139 230.09139,96 208,96 L48,96 C25.90861,96 8,78.09139 8,56 Z"
)
.controls.row.mx-0.mt-5.align-items-center
.col-2
button#playstate-toggle.btn.btn-light(
type="button",
title="Play/Pause Toggle",
data-playstate="paused"
)
i.fa.fa-play(aria-hidden="true")
i.fa.fa-pause(aria-hidden="true")
i.fa.fa-redo(aria-hidden="true")
span.text-center(id=`progress-output`) 0
input#progress.col-10.form-control-range(
type="range",
value="0",
min="0",
max="100",
step="0.01"
)
import { animate } from "https://cdn.skypack.dev/@okikio/animate";
import { methodCall } from "https://cdn.skypack.dev/@okikio/manager";
/* Properties Section */
// Motion Paths Demo
let playbackFn = (containerSel, anims) => {
let playstateEl = document.querySelector(`${containerSel} #playstate-toggle`);
let progressEl = document.querySelector(`${containerSel} #progress`);
let progressOutputEl = document.querySelector(
`${containerSel} #progress-output`
);
let oldState: AnimationPlayState;
let updatePlayState = () => {
oldState = anims[0].getPlayState();
playstateEl.setAttribute("data-playstate", oldState);
};
anims[0].on("finish begin", updatePlayState).on("update", (progress) => {
progressEl.value = `` + progress.toFixed(2);
progressOutputEl.textContent = `${Math.round(progress)}%`;
});
playstateEl.addEventListener("click", () => {
if (anims[0].is("running")) methodCall(anims, "pause");
else if (anims[0].is("finished")) methodCall(anims, "reset");
else methodCall(anims, "play");
updatePlayState();
});
progressEl.addEventListener("input", (e) => {
let percent = +progressEl.value;
methodCall(anims, "pause");
methodCall(anims, "setProgress", percent);
});
progressEl.addEventListener("change", () => {
oldState !== "paused"
? methodCall(anims, "play")
: methodCall(anims, "pause");
updatePlayState();
});
};
(() => {
let options: IAnimationOptions = {
padEndDelay: true,
easing: "linear",
duration: 2000,
loop: 4,
speed: 1
};
let containerSel = ".motion-path-demo";
let el = document.querySelector(".motion-path .el-1") as HTMLElement;
let motionPath = animate({
target: el,
offsetDistance: ["0%", "100%"],
...options
});
let path = document.querySelector(".motion-path path");
let el2 = document.querySelector(".motion-path .el-2");
let pts = new Set();
let rotateArr = [];
let len = path.getTotalLength();
let ptAtZero = path.getPointAtLength(0);
for (var i = 0; i < len; i++) {
let { x, y } = path.getPointAtLength(i);
pts.add([x, y]);
let { x: x0, y: y0 } = i - 1 >= 1 ? path.getPointAtLength(i - 1) : ptAtZero;
let { x: x1, y: y1 } = i + 1 >= 1 ? path.getPointAtLength(i + 1) : ptAtZero;
let calc = +((Math.atan2(y0 - y1, x0 - x1) * 180) / Math.PI);
rotateArr.push(calc);
}
let getTotalLength = animate({
target: el2,
translate: [...pts],
rotate: rotateArr,
fillMode: "both",
...options
});
playbackFn(containerSel, [motionPath, getTotalLength]);
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.min.js"></script>
.div {
@apply bg-blue-400 w-10 h-10 rounded relative m-2;
--size: 8vmin;
width: var(--size);
height: var(--size);
}
.relative {
position: relative;
margin: 0 auto;
}
.flex-wrap {
flex-wrap: wrap;
}
.motion-path {
position: relative;
}
.el,
.el-initial {
--size: 4vmin;
width: var(--size);
height: var(--size);
/* transform: scale(1); */
// border-radius: 8%;
margin: 5px;
background: #616aff;
position: relative;
}
.el-initial {
opacity: 0.6;
position: absolute;
display: block;
margin-top: 0;
top: 0;
left: 0;
}
.motion-path .el-1 {
position: absolute;
offset-path: path(
"M8,56 C8,33.90861 25.90861,16 48,16 C70.09139,16 88,33.90861 88,56 C88,78.09139 105.90861,92 128,92 C150.09139,92 160,72 160,56 C160,40 148,24 128,24 C108,24 96,40 96,56 C96,72 105.90861,92 128,92 C154,93 168,78 168,56 C168,33.90861 185.90861,16 208,16 C230.09139,16 248,33.90861 248,56 C248,78.09139 230.09139,96 208,96 L48,96 C25.90861,96 8,78.09139 8,56 Z"
);
offset-path: url("#follow-path");
offset-distance: 0;
}
.motion-path .el-2 {
position: absolute;
transform-origin: center center;
top: calc(var(--size) / -2);
left: calc(var(--size) / -2);
}
.animation-container {
transition: background-color 0.5s ease;
background-color: rgba(0, 0, 0, 0.085);
border-radius: 5px;
padding: 5px;
cursor: pointer;
&:hover {
background-color: rgba(255, 255, 255, 0.25);
}
}
.contain {
position: relative;
}
.animation-container + .animation-container {
margin-top: 2em;
}
input[type="range"] {
width: 100%;
padding: 0;
margin: 0;
}
html:not(.unsupported) .support {
display: none;
}
.col-2 {
display: flex;
justify-content: space-between;
align-items: center;
}
// Cool
#playstate-toggle[data-playstate="running"] {
.fa-play,
.fa-redo {
display: none;
}
}
#playstate-toggle[data-playstate="paused"] {
.fa-pause,
.fa-redo {
display: none;
}
}
#playstate-toggle[data-playstate="finished"] {
.fa-play,
.fa-pause {
display: none;
}
}
.flex.justify-evenly {
display: flex;
justify-content: space-evenly;
}
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@500;600;700;800&amp;family=Material+Icons&amp;family=Material+Icons+Round&amp;display=swap" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment