RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1015179
Accepted
Alexandr_TT
Alexandr_TT
Asked:2020-08-19 23:04:32 +0000 UTC2020-08-19 23:04:32 +0000 UTC 2020-08-19 23:04:32 +0000 UTC

如何使用 div 创建相机快门效果

  • 772

我试图制作一个圆形相机快门相机,但我很难让它看起来很逼真。

它应该是这样的:

在此处输入图像描述

以下是我尝试过的代码:

let partAmount = 10;
let cont = document.getElementById('cont');
let parts = [];
for(let i = 1; i <= partAmount; i++){
  let partCont = createElement('div','partCont');
  let part = createElement('div','part');
  parts.push(part);
  partCont.appendChild(part);
  cont.appendChild(partCont);
  partCont.style.transform = 'rotate('+ 360 / partAmount * i+'deg) translatey(-250px)';
}
function createElement(tag,className){
  let elem = document.createElement(tag);
  elem.classList.add(className);
  return elem;
}
#cont{
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);

  border-radius: 50%;
}
.dia{
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
  width: 300px;
  height: 300px;
  border-radius: 50%;
  overflow: hidden;
}
.partCont{
  position: absolute;
  transform-origin: left top;
}
.part{
  width: 500px;
  height: 100px;
  background-color: lightgray;
  border-bottom: 3px solid gray;
  box-sizing: border-box;
  transform-origin: left bottom;
  transform: rotate(60deg);
  transition-duration: 1s;
}
<div class="dia">
  <div id="cont">
  </div>
</div>

第一个“花瓣”应该低于最后一个,高于下一个。

怎么做?

javascript
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Alexandr_TT
    2020-08-20T00:14:01Z2020-08-20T00:14:01Z
    1. 解决方案是考虑到您具有对称形状的事实,因此您可以使用两个不同的元素构建它,在其中应用相同的东西,然后旋转其中一个元素以产生一种形状的错觉。

      我将使用多重背景和线性渐变来创建它:

    .camera{
      width:200px;
      height:200px;
      margin:auto;
      border-radius: 50%;
      border:1px solid;
      overflow:hidden;
      position:relative;
      --c1: transparent 55%,#000 calc(55% + 1px) calc(55% + 4px),grey calc(55% + 5px);
      --c2: transparent 40%,#000 calc(40% + 1px) calc(40% + 4px),grey calc(40% + 5px);
    }
    .camera::before,
    .camera::after{
      content:"";
      position:absolute;
      top:0;
      left:0;
      height:100%;
      width:50%;
      background: 
        linear-gradient(-153deg,var(--c1)),      
        linear-gradient(-107deg,var(--c2)),      
        linear-gradient(-73deg ,var(--c2)),      
        linear-gradient(-27deg ,var(--c1));
    }
    
    .camera::after {
      transform:rotate(180deg);
      transform-origin:right;
    }
    <div class="camera">
    </div>

    1. 正如您在上面看到的,我们几乎接近结果,并且我们可以使用额外的渐变添加两行缺失的行,如下所示:

    .camera{
      width:200px;
      height:200px;
      margin:auto;
      border-radius: 50%;
      border:1px solid;
      overflow:hidden;
      position:relative;
      --c1: transparent 55%,#000 calc(55% + 1px) calc(55% + 4px),grey calc(55% + 5px);
      --c2: transparent 40%,#000 calc(40% + 1px) calc(40% + 4px),grey calc(40% + 5px);
    }
    .camera::before,
    .camera::after{
      content:"";
      position:absolute;
      top:0;
      left:0;
      height:100%;
      width:50%;
      background: 
        linear-gradient( 153deg,var(--c1)) bottom/100% 43.5% no-repeat,    
        
        linear-gradient(-153deg,var(--c1)),      
        linear-gradient(-107deg,var(--c2)),      
        linear-gradient(-73deg ,var(--c2)), /* 180 - 107 = 73deg*/ 
        linear-gradient(-27deg ,var(--c1)); /* 180 - 153 = 27deg*/
    }
    
    .camera::after{
      transform:rotate(180deg);
      transform-origin:right;
    }
    <div class="camera">
    </div>

    一点数学

    1. 如果我们需要精确计算,我们必须考虑到里面绘制的图形是一个八边形:

    在此处输入图像描述

    由此我们可以确定旋转的角度。第一个将是 -45 градусов / 2 = 22,5度。
    然后我们放大 45 度以找到其余部分:

    代码将变为:

    .camera{
      width:200px;
      height:200px;
      margin:auto;
      border-radius: 50%;
      border:1px solid;
      overflow:hidden;
      position:relative;
      --p1:55%;
      --p2:40%;
      
      --c1: transparent var(--p1),#000 calc(var(--p1) + 1px) calc(var(--p1) + 4px),grey calc(var(--p1) + 5px);
      --c2: transparent var(--p2),#000 calc(var(--p2) + 1px)calc(var(--p2) + 4px),grey calc(var(--p2) + 5px);
    }
    .camera::before,
    .camera::after{
      content:"";
      position:absolute;
      top:0;
      left:0;
      height:100%;
      width:50%;
      background: 
        linear-gradient( 112.5deg,var(--c1)) bottom right/10%  14% no-repeat,
        linear-gradient( 157.5deg,var(--c1)) bottom      /100% 54% no-repeat,    
        
        linear-gradient(-157.5deg,var(--c1)), /* -135deg */    
        linear-gradient(-112.5deg,var(--c2)), /* -90deg */     
        linear-gradient(-67.5deg ,var(--c2)), /* -45deg */
        linear-gradient(-22.5deg ,var(--c1));
    }
    
    .camera::after{
      transform:rotate(180deg);
      transform-origin:right;
    }
    <div class="camera">
    </div>

    1. 您可能会注意到我们需要 2 个额外的渐变,因为会有更多的缺失线。

      要控制形状,你必须调整值color stops(--p1和--p2)并调整附加渐变的大小(仍然需要找到这些值之间的关系)

    在此处输入图像描述

    .camera{
      width:200px;
      height:200px;
      display:inline-block;
      border-radius: 50%;
      border:1px solid;
      overflow:hidden;
      position:relative;
      --p1:55%;
      --p2:40%;
      
      --c1: transparent var(--p1),#000 calc(var(--p1) + 1px) calc(var(--p1) + 4px),grey calc(var(--p1) + 5px);
      --c2: transparent var(--p2),#000 calc(var(--p2) + 1px)calc(var(--p2) + 4px),grey calc(var(--p2) + 5px);
    }
    .camera::before,
    .camera::after{
      content:"";
      position:absolute;
      top:0;
      left:0;
      height:100%;
      width:50%;
      background: 
        linear-gradient( 112.5deg,var(--c1)) bottom right/var(--e1,10%)  var(--e2,14%) no-repeat,
        linear-gradient( 157.5deg,var(--c1)) bottom      /100% var(--e3,54%) no-repeat,    
        
        linear-gradient(-157.5deg,var(--c1)), /* -135deg */    
        linear-gradient(-112.5deg,var(--c2)), /* -90deg */     
        linear-gradient(-67.5deg ,var(--c2)), /* -45deg */
        linear-gradient(-22.5deg ,var(--c1));
    }
    
    .camera::after{
      transform:rotate(180deg);
      transform-origin:right;
    }
    <div class="camera">
    </div>
    
    <div class="camera" style="--p1:65%;--p2:55%;  --e1:0;--e3:40%">
    </div>
    
    <div class="camera" style="--p1: 46%;--p2: 29%;  --e1: 26%;--e2: 35%;--e3: 62%;">
    </div>

    1. 通过添加更多层并正确计算旋转度,我们可以轻松过渡到任何多边形形状。

      十边形示例:

    .camera{
      width:200px;
      height:200px;
      display:inline-block;
      border-radius: 50%;
      border:1px solid;
      overflow:hidden;
      position:relative;
      --p1:60%;
      --p2:48%;
      --p3:38%;
      
      --c1: transparent var(--p1),#000 calc(var(--p1) + 1px) calc(var(--p1) + 4px),grey calc(var(--p1) + 5px);
      --c2: transparent var(--p2),#000 calc(var(--p2) + 1px) calc(var(--p2) + 4px),grey calc(var(--p2) + 5px);
      --c3: transparent var(--p3),#000 calc(var(--p3) + 1px) calc(var(--p3) + 4px),grey calc(var(--p3) + 5px);
    }
    .camera::before,
    .camera::after{
      content:"";
      position:absolute;
      top:0;
      left:0;
      height:100%;
      width:50%;
      background: 
        linear-gradient( 126deg,var(--c1)) bottom right/var(--e1,40%) var(--e2,20%) no-repeat,
        linear-gradient( 162deg,var(--c1)) bottom      /100% var(--e3,60%) no-repeat, 
        
        linear-gradient(-162deg,var(--c1)),
        linear-gradient(-126deg,var(--c2)),      
        linear-gradient(-90deg, var(--c3)),      
        linear-gradient(-54deg ,var(--c2)),
        linear-gradient(-18deg ,var(--c1)); /* 36deg/2 then we increment by 36deg*/
    }
    
    .camera::after{
      transform:rotate(180deg);
      transform-origin:right;
    }
    <div class="camera">
    </div>
    <div class="camera" style="--p1: 66.5%;--p2: 56%;--p3: 51%;  --e3: 51%;--e2: 8%;--e1: 13%;">
    </div>
    
    <div class="camera" style="--p1: 50%;--p2: 37%;--p3: 15%; --e3: 68%;--e2: 41%;--e1: 50%;">
    </div>

    1. 由于我们正在处理背景,我们可以为图像添加一个额外的层:

    #camera{
      width:200px;
      height:200px;
      display:inline-block;
      border-radius: 50%;
      border:1px solid;
      overflow:hidden;
      position:relative;
      background:url(https://picsum.photos/id/155/800/800) center/80% 80%;
      --p1:60%;
      --p2:48%;
      --p3:38%;
      
      --c1: transparent var(--p1),#000 calc(var(--p1) + 1px) calc(var(--p1) + 3px),grey calc(var(--p1) + 4px);
      --c2: transparent var(--p2),#000 calc(var(--p2) + 1px) calc(var(--p2) + 3px),grey calc(var(--p2) + 4px);
      --c3: transparent var(--p3),#000 calc(var(--p3) + 1px) calc(var(--p3) + 3px),grey calc(var(--p3) + 4px);
    }
    #camera::before,
    #camera::after{
      content:"";
      position:absolute;
      top:0;
      left:0;
      height:100%;
      width:50%;
      background: 
        linear-gradient( 126deg,var(--c1)) bottom right/var(--e1,40%) var(--e2,20%) no-repeat,
        linear-gradient( 162deg,var(--c1)) bottom      /100% var(--e3,60%) no-repeat, 
        
        linear-gradient(-162deg,var(--c1)),
        linear-gradient(-126deg,var(--c2)),      
        linear-gradient(-90deg, var(--c3)),      
        linear-gradient(-54deg ,var(--c2)),
        linear-gradient(-18deg ,var(--c1)); /* 36deg/2 then we increment by 36deg*/
    }
    
    #camera::after{
      transform:rotate(180deg);
      transform-origin:right;
    }
    <div id="camera">
    </div>
    <div id="camera" style="--p1: 66.5%;--p2: 56%;--p3: 51%;  --e3: 51%;--e2: 8%;--e1: 13%;">
    </div>
    
    <div id="camera" style="--p1: 50%;--p2: 37%;--p3: 15%; --e3: 68%;--e2: 41%;--e1: 50%;">
    </div>

    快门动画

    1. И вот идея, как создать анимацию открытия / закрытия затвора:

    .camera{
      width:200px;
      height:200px;
      display:inline-block;
      border-radius: 50%;
      border:1px solid;
      overflow:hidden;
      position:relative;
      background:url(https://picsum.photos/id/155/800/800) center/cover;
      --p1:60%;
      --p2:48%;
      --p3:38%;
      
      --c1: transparent var(--p1),#000 calc(var(--p1) + 1px) calc(var(--p1) + 4px),grey calc(var(--p1) + 5px);
      --c2: transparent var(--p2),#000 calc(var(--p2) + 1px) calc(var(--p2) + 4px),grey calc(var(--p2) + 5px);
      --c3: transparent var(--p3),#000 calc(var(--p3) + 1px) calc(var(--p3) + 4px),grey calc(var(--p3) + 5px);
    }
    .camera::before,
    .camera::after{
      content:"";
      position:absolute;
      top:-50%;
      left:50%;
      height:200%;
      width:100%;
      transition:.5s all linear;
      background: 
        linear-gradient(-126deg,var(--c1)) bottom left/var(--e1,40%) var(--e2,20%) no-repeat,
        linear-gradient(-162deg,var(--c1)) bottom      /100% var(--e3,60%) no-repeat, 
        
        linear-gradient(162deg,var(--c1)),
        linear-gradient(126deg,var(--c2)),      
        linear-gradient(90deg, var(--c3)),      
        linear-gradient(54deg ,var(--c2)),
        linear-gradient(18deg ,var(--c1)); /* 36deg/2 then we increment by 36deg*/
    }
    
    .camera::after{
      transform:rotate(180deg);
      transform-origin:left;
    }
    
    .camera:hover::before,
    .camera:hover::after {
      top:0;
      left:50%;
      height:100%;
      width:50%;
    }
    <div class="camera">
    </div>

    Альтернативное решение

    1. Мы можем объединить код автора вопроса и идею двух симметричных фигур и создать его, как показано ниже:

    let partAmount = 10;
    let cont = document.querySelector('.cont');
    let parts = [];
    for(let i = 1; i <= partAmount ; i++){
      let partCont = createElement('div','partCont');
      let part = createElement('div','part');
      parts.push(part);
      partCont.appendChild(part);
      cont.appendChild(partCont);
      partCont.style.transform = 'rotate('+ 360 / partAmount * i+'deg) translatey(-250px)';
    }
    function createElement(tag,className){
      let elem = document.createElement(tag);
      elem.classList.add(className);
      return elem;
    }
    /*added*/
    let alt = cont.cloneNode(true);
    document.querySelector('.dia').appendChild(alt);
    .cont{
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%,-50%);
      border-radius: 50%;
      clip-path: polygon(0 -150px, 0 150px, -150px 150px,-150px -150px); /*added*/
    }
    .cont:last-child {
      transform:rotate(180deg); /*added*/
    }
    .dia{
      width: 300px;
      height: 300px;
      border-radius: 50%;
      overflow: hidden;
      position:relative;
    }
    .partCont{
      position: absolute;
      transform-origin: left top;
    }
    .part{
      width: 300px;
      height: 100px;
      background-color: lightgray;
      border-bottom: 3px solid gray;
      box-sizing: border-box;
      transform-origin: left bottom;
      transform: rotate(60deg);
      transition-duration: 1s;
    }
    <div class="dia">
      <div class="cont">
      </div>
    </div>

    • 16
  2. Stranger in the Q
    2020-08-20T04:10:38Z2020-08-20T04:10:38Z

    Специально посмотрел видео, как устроена диафрагма.

    На HTML+CSS сделать реалистично намного сложнее чем на SVG.

    Вся сложность данного примера в подсчете координат конечной точки дуги, образующей границу створки диафрагмы.

    Здесь я воспользовался одним наблюдением, не проверял работает ли оно в общем случае, для 6 створок работает идеально.

    Эта точка лежит на окружности, построенной через точку крепления соседней по часовой стрелке створки, с таким же радиусом как и у ограничивающей окружности.

    UPD:减少了文档结构更改的数量,现在形状具有正确的形状并添加了填充,因此它们可以充当光圈 - 覆盖另一个图像

    在此处输入图像描述

    let r = 80, value = 0.5;
    let arc = (x, y, sweep) => `A${r},${r},0,0,${sweep},${x},${y}`;
    let paths = document.querySelectorAll('path');
    paths.forEach((path, i) => path.setAttribute('fill', `hsl(${i*60},75%,55%)`))
    requestAnimationFrame(draw);
    
    function draw() {
      upd();
      requestAnimationFrame(draw);
    }
    
    function upd() {
      value = Math.min(0.98, Math.max(value, 0));
      paths.forEach((path, i) => {
        let rot = Math.PI*(0.5 + 2/paths.length),
          cx = Math.cos(rot)*r,
          cy = Math.sin(rot)*r,
          radians = Math.PI*value*2/paths.length,
          cos = Math.cos(radians),
          sin = Math.sin(radians),
          x = cx - cos*cx - sin * cy,
          y = cy - cos*cy + sin * cx;
        path.setAttribute('d', `M0,${r}${arc(x,y,1)}${arc(cx,cy,0)}${arc(0,r,0)}`);
        path.setAttribute('transform', `rotate(${i/paths.length*360})`);
      });
    };
    
    addEventListener('mousemove', e => value = e.y/innerHeight*1.2-0.1);
    addEventListener('touchmove', e => value = e.touches[0].pageY/innerHeight*1.2-0.2);
    body, svg {
      margin: 0;
      height: 100vh;
    }
    <svg viewbox=-100,-100,200,200 preserveAspectRatio="xMidYMid meet">
      <path></path><path></path><path></path><path></path><path></path><path></path>
    </svg>

    • 14
  3. Best Answer
    Stranger in the Q
    2020-08-21T03:45:29Z2020-08-21T03:45:29Z

    此答案中的片段支持不同数量的虹膜襟翼。

    该解决方案基于寻找两个圆的交点的算法

    在此处输入图像描述

    let r = 80, 
        arc = (x,y,s) => `A${r},${r},0,0,${s},${x},${y}`,
        path = (i,d) => `<path transform='rotate(${i/+count.value*360})' ${d}></path>`;
    
    function upd (val) {
        
        let step = Math.PI*(0.5 + 2/+count.value);
        let p1x = Math.cos(step)*r; 
        let p1y = Math.sin(step)*r;
        let cos = Math.cos(-val);
        let sin = Math.sin(-val);
        let c1x = p1x - cos * p1x - sin * p1y;
        let c1y = p1y - cos * p1y + sin * p1x;
        let dx = - sin * r - c1x;
        let dy = r - cos * r - c1y;
        let dc = Math.sqrt(dx*dx + dy*dy);
        let a = Math.atan2(dy, dx) - Math.acos(dc/2/r);
        let x = c1x + Math.cos(a)*r;
        let y = c1y + Math.sin(a)*r;
        
        let edge = `M${p1x},${p1y}${arc(0,r,0)}${arc(x,y,1)}`;
        edges.innerHTML = bodies.innerHTML = '';
        for (let i = 0; i < +count.value; i++) {
            edges.innerHTML += path(i, `fill=none stroke=black d='${edge}'`);
            bodies.innerHTML += path(i, `fill=lightgray d='${edge}${arc(p1x,p1y,0)}'`); 
        }
    };
    
    upd(0.5);
    
    addEventListener('mousemove', e => upd(e.y/innerHeight*1.04));
    <svg viewbox=-100,-100,200,200 style="height:90vh" id=svg>
        <g id=bodies></g><g id=edges></g>
    </svg><br>
    <input id=count type=range min=2 max=13 value=5 style="position:absolute;top:2px">

    • 12

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5