js实现一个可调节参数的倒立摆动画效果代码

代码语言:html

所属分类:动画

代码描述:js实现一个可调节参数的倒立摆动画效果代码

代码标签: 调节 参数 倒立 动画 效果

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开


<!DOCTYPE html>
<html lang="en" >

<head>

  <meta charset="UTF-8">

  
  
  
<style>
* {
    margin: 0;
    padding: 0;
    font-family: 'Spartan', sans-serif;
    user-select: none;
    box-sizing: border-box;
    touch-action: none;
	-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

body {
    display: grid;
}

#background {
    display: grid;
    background-color: AliceBlue;
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    justify-self: center;
    align-self: center;
    justify-content: center;
    align-content: center;
}

#container {
    justify-self: center;
    align-self: center;
    width: 37rem;
    height: min-content;
    display: grid;
    transform: scale(1);
}

#title {
    grid-row: 1;
    grid-column: 1;
    justify-self: center;
    font-size: 3.5rem;
    white-space: nowrap;
    color: #8CBCE5;
}

#buttons {
    display: grid;
    width: 100%;
    justify-self: stretch;
    grid-template-columns: auto auto auto;
    grid-gap: 1rem;
    white-space: nowrap;
}

button {
    min-width: 6rem;
    font-size: 1.2rem;
    color: white;
    background-color: #8CBCE5;
    padding: 0.8rem;
    border-radius: 0.7rem;
    border: none;
    cursor: pointer;
    border: 0.25rem solid #8CBCE5;
}

button:hover {
    border: 0.25rem solid #7ea9ce;
}

button:active {
    background: #6387A7;
}

button:focus {
    outline: none;
    border: 0.25rem solid #6387A7;
}

#upper-sliders {
    width: 100%;
    display: grid;
    grid-gap: 1rem;
    grid-template-columns: 12rem auto 7rem;
    align-items: center;
    margin-bottom: 2rem;
}

#lower-sliders {
    margin-top: 2rem;
    width: 100%;
    display: grid;
    grid-gap: 1rem;
    grid-template-columns: 1.8rem auto 7rem;
    align-items: center;
}

#lower-sliders .left,
#upper-sliders .left {
    grid-column: 1;
}

#lower-sliders .middle,
#upper-sliders .middle {
    grid-column: 2;
    min-width: 1rem;
}

#lower-sliders .right,
#upper-sliders .right {
    grid-column: 3;
}

p {
    font-size: 1.4rem;
    font-weight: bold;
    color: #8CBCE5;
    text-align: justify;
    line-height: 1.32;
}

input[type="number"] {
    font-size: 1rem;
    padding: 0.8rem 0.7rem 0.6rem 0.7rem;
    border-radius: 0.5rem;
    text-align: left;
    background-color: #DDECFB;
    border: 0.25rem solid #DDECFB;
    color: #6387A7;
}

input[type="number"]:hover {
    border: 0.25rem solid #C9DFF4;
}

input[type="number"]:focus {
    outline: none;
    border: 0.25rem solid #8AB1D6;
}

svg {
    justify-self: center;
    grid-column: 1;
    grid-row: 1;
    width: 30rem;
    height: 23rem;
    overflow: visible;
    pointer-events: none;
}

svg * {
    fill: #eee;
    stroke-width: 1;
    stroke: black;
}

.top-circle {
    transform: translateX( 0px ) translateY( -65px );
}

#drag-target {
    pointer-events: auto;
}

#bottom-text {
    margin-top: 1.5rem;
    justify-self: right;
    font-size: 1.2rem;
}

a {
    text-decoration: none;
    opacity: 0.6;
}

input[type=range] {
    -webkit-appearance: none; /* Hides the slider so that custom slider can be made */
    width: 100%; /* Specific width is required for Firefox. */
    background: transparent; /* Otherwise white in Chrome */
    height: 1.5rem;
}

input[type=range]::-webkit-slider-thumb {
    -webkit-appearance: none;
}

input[type=range]:focus {
    outline: none; /* Removes the blue border. You should probably do some kind of focus styling for accessibility reasons though. */
}

input[type=range]::-ms-track {
    width: 100%;
    cursor: pointer;

    /* Hides the slider so custom styles can be added */
    background: transparent; 
    border-color: transparent;
    color: transparent;
}

/* Special styling for WebKit/Blink */
input[type=range]::-webkit-slider-thumb {
    -webkit-appearance: none;
    height: 1.7rem;
    width: 1.7rem;
    border-radius: 0.5rem;
    background-color: #8CBCE5;
    cursor: pointer;
    margin-top: -0.6rem; /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */
}
   
input[type=range]:hover::-webkit-slider-thumb {
    border: 0.25rem solid rgba(0, 0, 0, 0.1);
}

input[type=range]:focus::-webkit-slider-thumb {
    border: 0.25rem solid #6387A7;
}

input[type=range]::-webkit-slider-runnable-track {
  width: 100%;
  height: 0.5rem;
  cursor: pointer;
  background-color: #DDECFB;
  border-radius: 0.5rem;
}

/* All the same stuff for Firefox */
input[type=range]::-moz-range-thumb {    
    height: 1.2rem;
    width: 1.2rem;
    border-radius: 0.5rem;
    background-color: #8CBCE5;
    cursor: pointer;
    border: 0.25rem solid #8CBCE5;
}
   
input[type=range]:hover::-moz-range-thumb {
    border: 0.25rem solid rgba(0, 0, 0, 0.1);
}

input[type=range]:focus::-moz-range-thumb {
    border: 0.25rem solid #6387A7;
}

input[type=range]::-moz-range-track {
  width: 100%;
  height: 0.5rem;
  cursor: pointer;
  background-color: #DDECFB;
  border-radius: 0.5rem;
}
</style>


<link href="https://fonts.googleapis.com/css2?family=Spartan:wght@500&display=swap" rel="stylesheet">

</head>

<body >


<div id="background">

    <div id="container">
        
        <h1 id="title"> inverted pendulum </h1>
        
        <div id="upper-sliders"> 
            
            <p class="left"> gravitational acceleration </p>
            <input id="g-slider" class="middle" type="range" min="-10" max="50" value="9.81" step="0.01"> </input>
            <input id="g-input"  type="number" class="right number" step="0.01" value="9.81"> </input>
    
            <p class="left"> pendulum length </p>
            <input id="pendulum-length-slider" class="middle" type="range" min="0.01" max="3" value="0.65" step="0.01"> </input>
            <input id="pendulum-length-input"  type="number" class="right number" step="0.01" value="0.65"> </input>

            <p class="left"> pendulum mass </p>
            <input id="pendulum-mass-slider" class="middle" type="range" min="0.01" max="100" value="1" step="0.01"> </input>
            <input id="pendulum-mass-input"  type="number" class="right number" step="0.01" value="1"> </input>

            <p class="left"> slider mass </p>
            <input id="slider-mass-slider" class="middle" type="range" min="0.01" max="100" value="1" step="0.01"> </input>
            <input id="slider-mass-input"  type="number" class="right number" step="0.01" value="1"> </input>
            
            
        </div>
        
        <div id="buttons">
            <button id="reset"> reset </button>
            <button id="toggle-controller"> turn on controller </button>
            <button id="nudge"> nudge </button>
        </div>
        
        <div id="lower-sliders">
            
            <p class="left"> P<sub>θ</sub> </p>
            <input id="ptheta-slider" type="range" class="middle" min="-500" max="500" value="100" step="1"> </input>
            <input id="ptheta-input"  type="number" class="right number" step="1" value="100"> </input>
            
            <p class="left"> D<sub>θ</sub> </p>
            <input id="dtheta-slider" type="range" class="middle" min="-200" max="200" value="10" step="1"> </input>
            <input id="dtheta-input"  type="number" class="right number" step="1" value="10"> </input>
            
            <p class="left"> P<sub>x</sub> </p>
            <input id="px-slider" type="range" class="middle" min="-200" max="200" value="20" step="1"> </input>
            <input id="px-input"  type="number" class="right number" step="1" value="20"> </input>
            
            <p class="left"> D<sub>x</sub> </p>
            <input id="dx-slider" type="range" class="middle" min="-200" max="200" value="10" step="1"> </input>
            <input id="dx-input"  type="number" class="right number" step="1" value="10"> </input>
        </div>

        <p style="margin-top: 2rem; font-size: 1rem;"> this is a simulation of an inverted pendulum with a PD controller to bring the pendulum angle θ and silder displacement x to zero. it uses RK4 numerical integration and the controller function at the top of the JS code can be easily modified to test new controllers. </p>

        <p id="bottom-text"> made by <a href="https://www.github.com/OscarSaharoy" target="_blank"> oscar saharoy </a> </p>
        
        <svg width="100" height="100" viewbox="-50 -40 100 50" id="shadow" xmlns="http://www.w3.org/2000/svg" style="pointer-events: none">
            
            <mask id="pendulum-shadow">
                <rect class="pole" x="-12.5" y="-55" width="5" height="65" style="fill: white; stroke: none" transform-origin="-10 10" />
                <circle class="top-circle" cx="-10" cy="10" r="10" style="fill: white; stroke: none" />
                <rect class="slider" x="-23" y="4" width="26" height="12" rx="3" style="fill: white; stroke: none" />
                <rect x="-110" y="7.5" width="200" height="5" style="fill: white; stroke: none" />
            </mask>
            
            <rect x="-300" y="-300" width="600" height="600" mask="url(#pendulum-shadow)" style="stroke: none; fill: rgba(0, 0, 0, 0.07)" />
            
            
        </svg>
           
        <svg width="100" height="100" viewbox="-50 -40 100 50" id="pendulum" xmlns="http://www.w3.org/2000/svg">

            <rect id="rail" x="-100" y="-2.5" width="200" height="5" />
            <line x1="-99.5" y1="-1.5" x2="99.5" y2="-1.5" style="stroke: white; pointer-events: none;" />
            <line x1="-100" y1="1.7" x2="100" y2="1.7" style="stroke: rgba(0, 0, 0, 0.15); pointer-events: none;" />
            
            <mask id="slider-rail-shadow">
                <polygon class="slider" points="-13,-2.5 -13,2.5 -18,2.5 -14.5,-2.5" style="fill: white; stroke: none" />
            </mask>
            
            <rect x="-100" y="-2.5" width="200" height="5" mask="url(#slider-rail-shadow)" style="fill: rgba(0, 0, 0, 0.2); stroke: none; pointer-events: none;" />
            

            <rect class="pole" x="-2.5" y="-65" width="5" height="65" />
            <line class="pole" x1="1" y1="-64" x2="1" y2="0" style="stroke: white" />
            <line class="pole" x1="-1.5" y1="-64" x2="-1.5" y2="0" style="stroke: rgba(0, 0, 0, 0.1);" />

            <clipPath id="pole-shadow-clip">
                <rect class="pole" x="-2.5" y="-70" width="5" height="70" style="fill: black;" />
            </clipPath>


            <mask id="top-circle-shadow">
                <circle cx="0" cy="0" r="10" style="stroke: none; fill: white;" />
                <circle cx="2" cy="-2" r="10" style="stroke: none; fill: black;" />
            </mask>

            <mask id="top-circle-pole-shadow-mask">
                <circle class="top-circle" cx="-1.5" cy="2.5" r="11" style="stroke: none; fill: white;" />
            </mask>

            <rect x="-200" y="-200" width="400" height="400" mask="url(#top-circle-pole-shadow-mask)" clip-path="url(#pole-shadow-clip)" style="fill: rgba(0, 0, 0, 0.15); stroke: none" />

            <circle class="top-circle" id="drag-target" cx="0" cy="0" r="20" style="fill: transparent; stroke: none;" />
            <circle class="top-circle" cx="0" cy="0" r="10" style="fill: #b0e4fE" />
            <circle class="top-circle" cx="4" cy="-4" r="1.7" style="fill: rgba(255, 255, 255, 0.6); stroke: none" />
            <circle class="top-circle" cx="0" cy="0" r="10.5" mask="url(#top-circle-shadow)" style="fill: rgba(0, 0, 0, 0.1)" />


            <mask id="slider-pole-shadow-mask">
                <rect class="slider" x="-15.5" y="-6.5" width="28.7" height="15" rx="5" style="fill: white; stroke: none" />
            </mask>

            <rect x="-100" y="-100" width="200" height="200" mask="url(#slider-pole-shadow-mask)" clip-path="url(#pole-shadow-clip)" style="fill: rgba(0, 0, 0, 0.15); stroke: none" />
            <rect class="slider" x="-13" y="-6" width="26" height="12" rx="3" style="fill: #3672a0" />
            <rect class="slider" x="1.25" y="-4.25" width="10" height="2" rx="1" style="fill: rgba(255, 255, 255, 0.3); stroke: none" />
            <rect class="slider" x="-12" y="-6" width="25" height="11" rx="2" style="fill: none; stroke: rgba(0, 0, 0, 0.15)" />

        </svg>

    </div>
</div>


  
      <script>
// Oscar Saharoy 2021



// rewrite me!!!!
function controller() {

  // don't even try if the angle is too far off upright
  if (Math.abs(theta) > 0.5) return 0;

  // pid controller (i=0)
  return (ptheta * theta + dtheta * thetadot + px * x + dx * xdot) * controllerOn;
}




// get some of the elements
const svgs = Array.from(document.querySelectorAll("svg"));
const sliderElements = Array.from(document.querySelectorAll(".slider"));
const topCircleElements = Array.from(document.querySelectorAll(".top-circle"));
const poleElements = Array.from(document.querySelectorAll(".pole"));
const preventDrag = Array.from(document.querySelectorAll("input, button, #drag-target"));

const [pendulumSVG, shadowSVG] = svgs;
const background = document.que.........完整代码请登录后点击上方下载按钮下载查看

网友评论0