RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 943685
Accepted
Alexandr_TT
Alexandr_TT
Asked:2020-02-12 04:13:10 +0000 UTC2020-02-12 04:13:10 +0000 UTC 2020-02-12 04:13:10 +0000 UTC

如何从一个圆圈中切割两个小段并在悬停时旋转它们

  • 772

在许多网站上,开始出现对称切出小区域的旋转圆圈的效果。看起来不错。如何复制这种效果?

我设法使用属性剪切了一段stroke-dasharray

下面的代码:

.txt1  {fill:white; pointer-events:none;}
.rect {fill:gray;}
.txt1:hover {fill:white;}
.rect:hover {fill:black; transition:fill 0.5s all;}
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
   <g id="gr1" >
    
   <rect class="rect"  x="62" y="11" rx="10" width="250" height="40" />
       <text class="txt1" x="75" y="40" font-size="22" > SPECIAL OPERATIONS </text>
 <circle id="crc1" cx="30" cy="30" r="20"   stroke='grey' stroke-width="3" fill='transparent' 
        stroke-dasharray="115.66 10"  stroke-dashoffset="-35.41" >
	   </circle> 	
  </g>
</svg>	 

将鼠标悬停在标签上时如何剪切第二个对称段并使其旋转?

更新

添加了新答案:

选项 - 仅 HTML 和 CSS @UModeL

比赛附加条件:

使用实现动画的解决方案来获得答案会非常有趣,就像 SVG 的CSS动画答案一样JS

  • 单段旋转
  • 创建具有两个以上段的形状动画的技术
  • 从一点对称填充形状的动画

在决策平等的情况下,将优先选择带有良好注释代码的答案。

不接受使用插件、第三方库作为竞争性答案的答案。

2019 年 2 月 24 日更新

恭喜 UModel 竞赛获胜者

比赛的所有困难条件都满足了!
我相信很多人最终会一次又一次地回到这个话题来使用答案作者的原始解决方案。整个代码以非常详细和易于访问的方式进行注释,这使得更容易感知和掌握各种解决方案技术的有趣组合。

javascript
  • 4 4 个回答
  • 10 Views

4 个回答

  • Voted
  1. Best Answer
    UModeL
    2020-02-12T19:27:22Z2020-02-12T19:27:22Z

    只有 HTML 和 CSS。边框颜色和旋转伪元素

    我将立即预订 SVG 在形状和动画方面提供了更多机会(从相邻的答案中可以看出)。确实,有几个缺点——这是标记代码的权重(同时没有人取消样式和脚本)和对 SVG 的研究(虽然“入门门槛”不高,但它不是在旅途中很容易理解)。

    对于简单的形状,最少的 HTML 标记就足够了,其他一切都通过 CSS 实现:

    .spin,
    .spin:after {
      display: inline-block;
      width: 40px;
      height: 40px;
      vertical-align: middle;
      box-sizing: border-box;
      /* Толщина окружности */
      border: 3px solid grey;
      border-radius: 50%;
      border-color: grey transparent grey transparent;
    }
    .spin {
      position: relative;
      margin: 10px 8px;
      /* Начальный угол */
      transform: rotate(0deg);
      transition: 1.5s ease;
    }
    .spin:after {
      content: '';
      position: absolute;
      z-index: 1;
      top: -3px;
      left: -3px;
      /* Размер зазоров */
      transform: rotate(65deg);
    }
    
    #spin {
      width: 0;
      height: 0;
      border: none;
      position: absolute;
    }
    #spin:hover+.spin {
      transform: rotate(720deg);
    }
    
    label {
      display: inline-block;
      height: 38px;
      vertical-align: middle;
      border-radius: 10px;
      font: 20px/40px "Times New Roman";
      text-align: center;
      transition: .3s ease;
      background: grey;
      color: white;
    }
    label:hover {
      background: black;
    }
    <input id="spin">
    <div class="spin"></div><label for="spin">&nbsp;&nbsp;SPECIAL&nbsp;OPERATIONS&nbsp;&nbsp;</label>

    装载机

    创作可以分为几个阶段:

    1. 在 HTML 标记中创建一个块<div class="spin"></div>;
    2. 在 CSS 中创建规则.spin, .spin:after {}并添加以下属性:
      • width和height- 为宽度和高度指定相同的值;
      • box-sizing: border-box;- 这样框架的厚度不会影响周围的元素;
      • border: 3px solid grey;- 实际上,一个带有厚度指示的框架;
      • border-radius: 50%;- 使元素的角变圆,从而转动 围成一圈;
      • (注意!魔术:)为框架的不同侧面指定不同的颜色。在这种情况下,需要成对设置平行边的透明度和主色 - border-color: grey transparent grey transparent;。
    3. 创建.spin {}具有属性的规则:
      • position: relative;- 用于伪元素的正确定位;
      • transform: rotate(0deg);- 块初始位置的旋转角度;
      • transition: 1.5s ease;- 我们设置了过渡,以便发生平滑的旋转动画,而不是从初始位置到最终位置的急剧跳跃
    4. 创建规则.spin:after {}和属性:
      • position: absolute; z-index: 1; top: -3px; left: -3px;- 相对于主块放置和对齐伪元素;
      • (注意!魔术:)用于transform: rotate(65deg);设置伪元素的旋转角度,从而改变间隙的宽度。

    如果您运行下面的示例并移动滑块,则原理会变得更加清晰:

    var oControl=document.querySelector('.control'),oCode=document.querySelector('.code>pre');oControl.addEventListener('input',function(ev){document.documentElement.style.setProperty(`--${ev.target.id}`,ev.target.value);if(ev.target.id=='spin_width'){oCode.innerText=oCode.innerText.replace(/border: \d+px/gi,`border: ${ev.target.value}px`)};if(ev.target.id=='spin_angle'){oCode.innerText=oCode.innerText.replace(/(угол[\s\S]+?rotate\()[-\d]+(deg\))/gi,`$1${ev.target.value}$2`)};if(ev.target.id=='spin-a_angle'){oCode.innerText=oCode.innerText.replace(/(зазоров[\s\S]+?rotate\()[-\d]+(deg\))/gi,`$1${ev.target.value}$2`)}});oControl.addEventListener('mouseover',function(ev){if(ev.target.id=='spin-a_angle'){document.documentElement.style.setProperty(`--spin-a_color`,'rgba(255, 0, 0, 0.5)')};if(ev.target.tagName=='INPUT'){oCode.className=ev.target.id}});oControl.addEventListener('mouseout',function(ev){if(ev.target.id=='spin-a_angle'){document.documentElement.style.setProperty(`--spin-a_color`,'rgba(128, 128, 128, 1)')}})
    :root{--spin_color:rgba(128,128,128,1);--spin-a_color:rgba(128,128,128,1);--spin_width:3;--spin_angle:0;--spin-a_angle:65;--code-top:.2em}.wrapper_621x183{position:relative;display:block;width:621px;height:183px;min-width:621px;min-height:183px;max-width:621px;max-height:183px;margin:0 auto;border:0 dashed #ccc}.control{position:absolute;z-index:10;top:10px;right:10px;display:inline-flex;flex-flow:column nowrap;background:rgba(230,230,230,1);box-shadow:2px 10px 20px -7px rgba(0,0,0,.3);padding:5px;border-radius:5px;font:12px/20px 'Arial';text-align:center}.code{position:absolute;z-index:5;bottom:1px;left:10px;width:540px;height:98px;background:rgba(255,255,255,.9);box-shadow:inset 0 3px 23px -4px rgba(0,0,0,.3);padding:8px;border-radius:4px;overflow:hidden}.code>pre{position:absolute;top:var(--code-top);margin:0;font:13px 'Consolas','Courier New',monospace;transition:top 1.5s ease}.code>pre.spin_width{--code-top:.2em}.code>pre.spin_angle{--code-top:-8.5em}.code>pre.spin-a_angle{--code-top:-17.5em}.spin,.spin:after{display:inline-block;width:40px;height:40px;vertical-align:middle;box-sizing:border-box;border:calc(var(--spin_width) * 1px) solid var(--spin_color);border-radius:50%}.spin{position:relative;margin:10px 8px;border-color:var(--spin_color) transparent var(--spin_color) transparent;transform:rotate(calc(var(--spin_angle) * -1deg));transition:1.5s ease}.spin:after{content:'';position:absolute;z-index:1;top:calc(var(--spin_width) * -1px);left:calc(var(--spin_width) * -1px);border-color:var(--spin-a_color) transparent var(--spin-a_color) transparent;transform:rotate(calc(var(--spin-a_angle) * 1deg))}#spin{width:0;height:0;border:none;position:absolute}#spin:hover+.spin{transform:rotate(720deg)}label{display:inline-block;height:38px;vertical-align:middle;border-radius:10px;font:20px/40px 'Times New Roman';text-align:center;transition:.3s ease;background:grey;color:white}label:hover{background:black}
    <div class="wrapper_621x183"> <input id="spin"> <div class="spin"></div><label for="spin">&nbsp;&nbsp;SPECIAL&nbsp;OPERATIONS&nbsp;&nbsp;</label> <div class="control"> <div>Толщина окружности<br><input id="spin_width" min="1" max="20" value="3" type="range"></div><div>Начальный угол<br><input id="spin_angle" min="0" max="360" value="0" type="range"></div><div>Размер зазоров<br><input id="spin-a_angle" min="0" max="90" value="65" type="range"></div></div><div class="code"> <pre>.spin,<br>.spin:after {<br>  ···<br>  /* Толщина окружности */<br>  border: 3px solid grey;<br>  ···<br>}<br><br>.spin {<br>  ···<br>  /* Начальный угол */<br>  transform: rotate(-360deg);<br>  ···<br>}<br><br><br>.spin:after {<br>  ···<br>  /* Размер зазоров */<br>  transform: rotate(65deg);<br>  ···<br>}</pre> </div></div>

    按钮

    该按钮是通过 tag 实现的,通过使用具有进一步样式<label>的属性将其转换为块元素。display: block;

    使用<label>不是偶然的,而是由于在实现这样一个简单的任务时希望放弃特定示例中的脚本。并且还演示了使用此标签的方法之一。

    在此示例中,标签<label>(每个标签)用于“远程”控制元素的状态<input>。那些。标签本身可以位于页面上的任何位置(同时,在<input>与之关联的标签旁边根本没有必要)。标签和与for<input>属性相关联,其值指定托管元素的id :

    <input id="spin"> <label for="spin">
    

    此外,可以有多个标签指向同一个元素,它们可以放置在文档中的任意位置并具有不同的样式:

    label {
      display: block;
      margin: 15px auto;
      box-sizing: border-box;
      text-align: center;
      box-shadow: 0 5px 7px -3px black;
      transition: .3s ease;
    }
    label:hover { box-shadow: 0 2px 4px -2px black; }
    
    .first {
      width: 130px;
      height: 25px;
      border: 2px solid #f00;
      border-radius: 8px;
    }
    .second {
      width: 130px;
      height: 25px;
      border: 2px solid #0f0;
      border-radius: 0 8px 0 8px;
      background-image: linear-gradient(to bottom, lime, gold, lime);
    }
    
    #spin {
      width: 0;
      height: 0;
      border: none;
      position: absolute;
    }
    #spin:hover+.spin { transform: rotate(360deg); }
    
    .spin,
    .spin:after {
      display: block;
      width: 70px;
      height: 70px;
      box-sizing: border-box;
      border: 5px solid grey;
      border-radius: 50%;
      border-color: grey transparent grey transparent;
    }
    .spin {
      position: relative;
      margin: 10px auto;
      transform: rotate(-360deg);
      transition: 1.5s ease;
    }
    .spin:after {
      content: '';
      position: absolute;
      top: -5px;
      left: -5px;
      transform: rotate(65deg);
    }
    <label for="spin" class="first">Наведи на меня!</label>
    <input id="spin"><div class="spin"></div>
    <label for="spin" class="second">... Или на меня!</label>

    重要的!受控元素影响其相邻元素及其状态的唯一条件<input>必须放置在所需元素之前的标记中,并且在 CSS 中您需要使用相邻元素选择器 - +:

    input#spin:hover + div.spin { }
    

    同时,<input>您需要自己隐藏它,例如,通过在样式中指定:

    input#spin {
      width: 0;
      height: 0;
      border: none;
      position: absolute;
    }
    

    为什么不display: none;呢?因为在某些浏览器中,以这种方式隐藏元素的标签链接停止工作。


    选项

    一段

    通过仅更改一个参数 - border-color: grey grey grey transparent;,您可以获得仅一个间隙的旋转:

    .spin,
    .spin:after {
      display: inline-block;
      width: 40px;
      height: 40px;
      vertical-align: middle;
      box-sizing: border-box;
      /* Толщина окружности */
      border: 3px solid grey;
      border-radius: 50%;
      border-color: grey grey grey transparent;
    }
    .spin {
      position: relative;
      margin: 10px 8px;
      /* Начальный угол */
      transform: rotate(0deg);
      transition: 1.5s ease;
    }
    .spin:after {
      content: '';
      position: absolute;
      z-index: 1;
      top: -3px;
      left: -3px;
      /* Размер зазоров */
      transform: rotate(65deg);
    }
    
    #spin {
      width: 0;
      height: 0;
      border: none;
      position: absolute;
    }
    #spin:hover+.spin {
      transform: rotate(720deg);
    }
    
    label {
      display: inline-block;
      height: 38px;
      vertical-align: middle;
      border-radius: 10px;
      font: 20px/40px "Times New Roman";
      text-align: center;
      transition: .3s ease;
      background: grey;
      color: white;
    }
    label:hover {
      background: black;
    }
    <input id="spin">
    <div class="spin"></div><label for="spin">&nbsp;&nbsp;SPECIAL&nbsp;OPERATIONS&nbsp;&nbsp;</label>

    三段

    Чтобы получить три зазора, понадобится добавить ещё один псевдоэлемент .spin:before { }, продублировав для него свойства из .spin:after { }. Затем, у основного блока и псевдоэлементов задать свойство transform: rotate( ); с разницей в 120deg. Также, нужно применить нашу "магию" следующим образом - border-color: grey transparent transparent transparent;:

    .spin,
    .spin:after,
    .spin:before {
      display: inline-block;
      width: 40px;
      height: 40px;
      vertical-align: middle;
      box-sizing: border-box;
      /* Толщина окружности */
      border: 3px solid grey;
      border-radius: 50%;
      border-color: grey transparent transparent transparent;
    }
    .spin {
      position: relative;
      margin: 10px 8px;
      /* Начальный угол */
      transform: rotate(0deg);
      transition: 1.5s ease;
    }
    .spin:after {
      content: '';
      position: absolute;
      z-index: 1;
      top: -3px;
      left: -3px;
      /* Размер зазоров */
      transform: rotate(120deg);
    }
    .spin:before {
      content: '';
      position: absolute;
      z-index: 1;
      top: -3px;
      left: -3px;
      /* Размер зазоров */
      transform: rotate(240deg);
    }
    
    #spin {
      width: 0;
      height: 0;
      border: none;
      position: absolute;
    }
    #spin:hover+.spin {
      transform: rotate(720deg);
    }
    
    label {
      display: inline-block;
      height: 38px;
      vertical-align: middle;
      border-radius: 10px;
      font: 20px/40px "Times New Roman";
      text-align: center;
      transition: .3s ease;
      background: grey;
      color: white;
    }
    label:hover {
      background: black;
    }
    <input id="spin">
    <div class="spin"></div><label for="spin">&nbsp;&nbsp;SPECIAL&nbsp;OPERATIONS&nbsp;&nbsp;</label>

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


    Анимация появления рамки

    Без сомнения, при творческом подходе, возможно создать почти любые эффекты, только средствами CSS. Но, нужно задуматься - "стоит ли овчинка выделки?" Возможно, реализация задумки, где с помощью другой технологии, можно обойтись парой-тройкой строк, не стоит "простыни" кода:

    .anistroke {
      position: relative;
      width: 140px;
      height: 40px;
      border-bottom: 3px solid transparent;
      text-align: center;
      font: 18px/40px 'Arial';
      box-sizing: border-box;
      animation: aniblock 1.5s steps(1, end) forwards;
    }
    
    @keyframes aniblock {
      50%, 100% { border-bottom: 3px solid grey; }
    }
    
    .anistroke::after,
    .anistroke::before {
      content: '';
      position: absolute;
      z-index: 1;
      bottom: -3px;
      width: 0px;
      height: 0px;
      border-top: 0px solid transparent;
      border-bottom: 3px solid grey;
    }
    .anistroke::after {
      left: 50%; border-left: 3px solid grey;
      animation: aniafter 1.5s linear forwards;
    }
    .anistroke::before {
      right: 50%; border-right: 3px solid grey;
      animation: anibefore 1.5s linear forwards;
    }
    
    @keyframes aniafter {
      50% { left: 0%; height: 0px; width: 70px; }
      75% {
        height: 37px; width: 0px;
        border-top: 0px solid transparent;
        border-bottom: 3px solid grey;
      }
      75.01% { border-top: 3px solid grey; border-bottom: 0px solid transparent; }
      100% {
        left: 0%; height: 37px; width: 30px;
        border-top: 3px solid grey;
        border-bottom: 0px solid transparent;
      }
    }
    
    @keyframes anibefore {
      50% { right: 0%; height: 0px; width: 70px; }
      75% {
        height: 37px; width: 0px;
        border-top: 0px solid transparent;
        border-bottom: 3px solid grey;
      }
      75.01% { border-top: 3px solid grey; border-bottom: 0px solid transparent; }
      100% {
        right: 0%; height: 37px; width: 30px;
        border-top: 3px solid grey;
        border-bottom: 0px solid transparent;
      }
    }
    <div class="anistroke">anistroke</div>

    • 21
  2. Alexandr_TT
    2020-02-12T04:13:10Z2020-02-12T04:13:10Z
    • 计算给定半径的周长20px

    C = 2 * 3.1415 * 20 = 125.66

    半圆的长度是62,83如果我们取切割段的长度等于10pxstroke-dasharray 公式,它会是这样的:stroke-dasharray="52.83 10"

    公式中的第一个数字52.83是破折号的长度,第二个10是空格。

    .txt1  {fill:white; pointer-events:none;}
    .rect {fill:gray;}
    .txt1:hover {fill:white;}
    .rect:hover {fill:black; transition:fill 0.5s all;}
    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
       <g id="gr1" >
        
       <rect class="rect"  x="62" y="11" rx="10" width="250" height="40" />
           <text class="txt1" x="75" y="40" font-size="22" > SPECIAL OPERATIONS </text>
     <circle id="crc1" cx="30" cy="30" r="20"   stroke='grey' stroke-width="3" fill='transparent' 
            stroke-dasharray="52.83 10"  stroke-dashoffset="-35.41" >
           </circle>    
      </g>
    </svg>   

    • 添加一个命令来动画圆的旋转。

    实际上,我们不旋转圆,而是使用动画移动线段的开头stroke-dashoffset

    当您将鼠标悬停在光标上时,该事件将起作用, begin="gr1.mouseover" 圆圈将向一个方向旋转。

    当光标离开铭文时,begin="gr1.mouseout"圆圈将向相反方向旋转。

    当您将鼠标悬停在标题上时动画开始

    .txt1  {fill:white; pointer-events:none;}
    .rect {fill:gray;}
    .txt1:hover {fill:white;}
    .rect:hover {fill:black; transition:fill 0.5s all;}
    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
       <g id="gr1" >
        
         <rect class="rect"  x="62" y="11" rx="10" width="250" height="40" />
          <text class="txt1" x="75" y="40" font-size="22" > SPECIAL OPERATIONS </text>
        </g>  
            <circle id="crc1" cx="30" cy="30" r="20"   stroke='grey' stroke-width="3" fill='transparent' 
               stroke-dasharray="52.83 10"  stroke-dashoffset="-4" >
              <animate
                   attributeName="stroke-dashoffset"
                   values="-10;105.66;-10"
                   dur="0.5s"
                   begin="gr1.mouseover"
                   repeatCount="1"
                   restart="whenNotActive" /> 
            <animate
              attributeName="stroke-dashoffset"
              values="105.66;0;105.66"
              dur="0.5s"
              begin="gr1.mouseout"
              repeatCount="1"
              restart="whenNotActive" /> 
           </circle>    
     
    </svg>

    第二个选项

    分段垂直排列

    .txt1  {fill:white; pointer-events:none;}
    .rect {fill:gray;}
    .txt1:hover {fill:white;}
    .rect:hover {fill:black; transition:fill 0.5s all;}
    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
       <g id="gr1" >
        
       <rect class="rect"  x="62" y="11" rx="10" width="250" height="40" />
           <text class="txt1" x="75" y="40" font-size="22" > SPECIAL OPERATIONS </text>
        </g>
     
     <circle id="crc1" cx="30" cy="30" r="20"   stroke='crimson' stroke-width="3" fill='transparent' 
            stroke-dasharray="52.83 10"  stroke-dashoffset="-35.41" >
           <animate attributeName="stroke-dashoffset"  values="-10;105.66;-10"  dur="0.5s"   begin="gr1.mouseover" repeatCount="1" restart="whenNotActive" /> 
            <animate attributeName="stroke-dashoffset"  values="105.66;0;105.66"    dur="0.5s"  begin="gr1.mouseout"   repeatCount="1" restart="whenNotActive" /> -->
      </circle>     
      
    </svg>

    • 17
  3. Alexandr_TT
    2020-02-12T23:56:16Z2020-02-12T23:56:16Z

    Варианты анимаций

    • Вращение одного сегмента
    • Техника создания анимаций фигур с количеством сегментов больше двух
    • Анимация симметричного заполнения фигур из одной точки

    Вращение одного сегмента

    Также используем атрибут stroke-dasharray сначала для вырезания сегмента. При полной длине окружности равной 125,66 и размере вырезаемого сегмента 10px получаем:

    stroke-dasharray="115.66 10"

    Анимация реализуется изменением stroke-dashoffset от максимума до минимума.

    Запуск анимации при наведении курсора

    .txt1  {fill:white; transition: all  1s ease; pointer-events:none;}
    .rect {fill:gray; transition: all  1s ease;}
    .txt1:hover {fill:white; }
    .rect:hover {fill:black; }
    #crc1 
    {
    stroke:#d5d5d5;
    stroke-width:3; 
    fill:transparent;
    }
    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
       <g id="gr1" >
        
       <rect class="rect"  x="62" y="11" rx="10" width="250" height="40" />
           <text class="txt1" x="75" y="40" font-size="22" > SPECIAL OPERATIONS </text>
        </g>
    
     <circle id="crc1" cx="30" cy="30" r="20"   
            stroke-dasharray="115.66 10"  stroke-dashoffset="-35.41" >
    	   <animate
    	     attributeName="stroke-dashoffset"
    		 values="105.66;-10"
    		 dur="0.35s"
    		 begin="gr1.mouseover"
    		 end="gr1.mouseout"
    		 repeatCount="indefinite"
    		 restart="whenNotActive" /> 
    	
      </circle> 	
      
    </svg>

    Второй вариант

    Движение по видимой круговой траектории

    К предыдущему коду добавляется вторая окружность, которая рисует траекторию движения сегмента.

    .txt1  {fill:white; pointer-events:none;}
    .rect {fill:gray;}
    .txt1:hover {fill:white;}
    .rect:hover {fill:black; transition:fill 0.5s all;}
    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
       <g id="gr1" >
        
       <rect class="rect"  x="62" y="11" rx="10" width="250" height="40" />
           <text class="txt1" x="75" y="40" font-size="22" > SPECIAL OPERATIONS </text>
        </g>
      <circle id="crc2" cx="30" cy="30" r="20"   stroke='black' stroke-width="3" fill='transparent'/> 
        <circle id="crc1" cx="30" cy="30" r="20"   stroke='#d5d5d5' stroke-width="3" fill='transparent' 
            stroke-dasharray="115.66 10"  stroke-dashoffset="-35.41" >
    	   <animate
    	     attributeName="stroke-dashoffset"
    		 values="105.66;-10"
    		 dur="0.35s"
    		 begin="gr1.mouseover"
    		 end="gr1.mouseout"
    		 repeatCount="indefinite"
    		 restart="whenNotActive" /> 
    	
      </circle> 	
      
    </svg>	 

    Техника создания анимаций фигур с количеством сегментов больше двух

    Для более углубленного изучения есть топик на нашем сайте, прочитав который, вы в совершенстве будете владеть данной техникой.

    Три сегмента

    Допустим нам необходимо создать три вращающихся сегмента.

    делим полную длину окружности - 125.66 / 3 = 41.88

    В одном сегменте 41,88px должны уместится черта 33.88 + пробел 8px

    Итого получилось - stroke-dasharray="33.88 8"

    .txt1  {fill:white; pointer-events:none;}
    .rect {fill:gray;}
    .txt1:hover {fill:white;}
    .rect:hover {fill:black; transition:fill 0.5s all;}
    #crc1 {fill:transparent; stroke:#777777;}
    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
       <g id="gr1" >
        
       <rect class="rect"  x="62" y="11" rx="10" width="250" height="40" />
           <text class="txt1" x="75" y="40" font-size="22" > SPECIAL OPERATIONS </text>
        </g>
     
     <circle id="crc1" cx="30" cy="30" r="20" stroke-width="3" 
            stroke-dasharray="33.88 8"  stroke-dashoffset="-4" >
    	   <animate
    	     attributeName="stroke-dashoffset"
    		 values="33.88;0"
    		 dur="0.2s"
    		 begin="gr1.mouseover"
    		 end="gr1.mouseout"
    		 repeatCount="indefinite"
    		 restart="whenNotActive" /> 
    	
      </circle> 	
      
    </svg>	 

    Четыре сегмента

    125,66 / 4 = 31,415 stroke-dasharray="23.415 8"

    .txt1  {fill:white; pointer-events:none;}
    .rect {fill:gray;}
    .txt1:hover {fill:white;}
    .rect:hover {fill:black; transition:fill 0.5s all;}
    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
       <g id="gr1" >
        
       <rect class="rect"  x="62" y="11" rx="10" width="250" height="40" />
           <text class="txt1" x="75" y="40" font-size="22" > SPECIAL OPERATIONS </text>
        </g>
      
     <circle id="crc1" cx="30" cy="30" r="20"   stroke='#777777' stroke-width="3" fill='transparent' 
            stroke-dasharray="23.415 8"  stroke-dashoffset="-4" >
    	   <animate attributeName="stroke-dashoffset"  values="54.83;0"	dur="0.2s"   begin="gr1.mouseover"  end="gr1.mouseout" repeatCount="indefinite" restart="whenNotActive" /> 
     </circle> 	
      
    </svg>	 

    Пять сегментов

    125,66 / 5 = 25.13 stroke-dasharray="15.13 10"

    .txt1  {fill:white; pointer-events:none;}
    .rect {fill:gray;}
    .txt1:hover {fill:white;}
    .rect:hover {fill:black; transition:fill 0.5s all;}
    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
       <g id="gr1" >
        
       <rect class="rect"  x="62" y="11" rx="10" width="250" height="40" />
           <text class="txt1" x="75" y="40" font-size="22" > SPECIAL OPERATIONS </text>
        </g>
      
     <circle id="crc1" cx="30" cy="30" r="20"   stroke='#777777' stroke-width="3" fill='transparent' 
            stroke-dasharray="15.13 10"  stroke-dashoffset="-4" >
    	   <animate
    	     attributeName="stroke-dashoffset"
    		 values="54.83;0"
    		 dur="0.2s"
    		 begin="gr1.mouseover"
    		 end="gr1.mouseout"
    		 repeatCount="indefinite"
    		 restart="whenNotActive" /> 
     </circle> 	
      
    </svg>	 

    Анимация симметричного заполнения фигур из одной точки

    В этой технике используется четыре параметра атрибута stroke-dasharray

    Проще понять на отрезке прямой, у которой в отличии от окружности не смыкаются конечные точки.

    Допустим имеем такую запись stroke-dasharray="10 20"
    Она означает, что чередуются на всей длине линии черта 10px и пробел 20px

    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
        
     <polyline points="0,30 350,30" stroke-dasharray="10 20"   stroke='#777777' stroke-width="3" fill='transparent' 
              stroke-dashoffset="0" />
    </svg>	 

    Теперь добавляем ещё два параметра

    stroke-dasharray="10 20 40 40"

    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 340 60" >   
        
     <polyline points="0,30 350,30" stroke-dasharray="10 20 40 40"   stroke='#777777' stroke-width="3" fill='transparent' 
              stroke-dashoffset="0" />
    </svg>

    В этом варианте 10 - черта, 20 - пробел, 40 черта, 40 пробел и снова 10 - черта 20 - пробел и так до конца линии.

    Анимация линии из средней точки

    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
        
     <path id="path" d="M 0 30 L 340 30"    stroke='#777777' stroke-width="3" fill='transparent' 
              stroke-dashoffset="0" >
         <animate
    	   attributeName="stroke-dasharray"
    	   from="0 170 0 170"
    	   to="0 0 340 0"
    	   dur="4s"
    	   begin="0s"
    	   repeatCount="1"
    	   restart="whenNotActive"
    	   fill="freeze"  /> 	
       </path>
    </svg>	 

    Линия длиной 340px, половина линии, средняя точка 170px

    from="0 170 0 170" начало анимации - черта - 0, пробел длиною 170 px, черта - 0, пробел длиною 170 px то есть вся линия спрятана.

    to="0 0 340 0" - черта длиною 0 пробел длиною 0, черта 340px, пробел - ноль. Так как на трех позициях нули, а одна черта имеет максимальную длину равную полной длине линии, то линия будет показана полностью.

    На этом принципе действуют остальные примеры рисования из средней точки

    Анимация рисования бордюра из средней точки

    <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 
       width="320" height="60" viewBox="0 0 350 60">
             <path id="shape" fill="none" stroke-width="3" stroke="#656E76"
                  d="M 38.8 3.35 H 3.15 V 43.65 H 155.75 V 3.35 H 120.2" />
    	<animate xlink:href="#shape" attributeName="stroke-dasharray" from="0 152.2 0 152.2" to="0 0 304.4 0" begin="0s" dur="1.4s" />
    	</g>
    </svg>   

    Анимация вертикального эллипса

    .txt1  {fill:white; pointer-events:none;}
    .rect {fill:gray; transition: 0.8s  all;}
    .txt1:hover {fill:white;}
    .rect:hover {fill:crimson; transition: 0.8s all;}
    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
       <g id="gr1" >
         <rect class="rect"  x="62" y="11" rx="10" width="250" height="40" />
           <text class="txt1" x="75" y="40" font-size="22" > SPECIAL OPERATIONS </text>
       </g>
         <g transform="translate(20 9)">
    	 <path d="m31 22a9 17 0 0 1-9 17 9 17 0 0 1-9-17 9 17 0 0 1 9-17 9 17 0 0 1 9 17z" 
    		  stroke='#d0d0d0' stroke-width="3" fill='transparent' />  
    	 
    	 <path d="m31 22a9 17 0 0 1-9 17 9 17 0 0 1-9-17 9 17 0 0 1 9-17 9 17 0 0 1 9 17z" 
    			 stroke="crimson" stroke-width="3" fill="none" stroke-dasharray="0 42  0 42" stroke-dashoffset="-21" >
    		<animate
    		  attributeName="stroke-dasharray"
    		  from="0 42 0  42"
    		  to="0 0 84 0"
    		  dur="0.4s"
    		  begin="gr1.mouseover"
    		  repeatCount="1"
    		  restart="whenNotActive"
    		  fill="freeze"  /> 
    			<animate
    			  attributeName="stroke-dasharray"
    			  from="0 0 84 0"
    			  to="0 42 0 42"
    			  dur="0.4s"
    			  begin="gr1.mouseout"
    			  repeatCount="1"
    			  restart="whenNotActive"
    			  fill="freeze"  />
    	 </path>
         </g>	 
    </svg>

    Горизонтальный эллипс

    .txt1  {fill:white; pointer-events:none;}
    .rect {fill:gray;}
    .txt1:hover {fill:white;}
    .rect:hover {fill:crimson; transition: 0.5s all;}
    <svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="320" height="60" viewBox="0 0 350 60" >   
       <g id="gr1" >
         <rect class="rect"  x="62" y="11" rx="10" width="250" height="40" />
           <text class="txt1" x="75" y="40" font-size="22" > SPECIAL OPERATIONS </text>
       </g>
         <g transform="translate(10 9)">
    	 <path d="m41 22a19 13 0 0 1-19 13 19 13 0 0 1-19-13 19 13 0 0 1 19-13 19 13 0 0 1 19 13z" 
    		  stroke='#d0d0d0' stroke-width="3" fill='transparent' />  
    	 
    	 <path d="m41 22a19 13 0 0 1-19 13 19 13 0 0 1-19-13 19 13 0 0 1 19-13 19 13 0 0 1 19 13z" 
    			 stroke="crimson" stroke-width="3" fill="none" stroke-dasharray="0 50.5  0 50.5" stroke-dashoffset="-25" >
    		<animate
    		 attributeName="stroke-dasharray"
    		 from="0 50.5 0 50.5"
    		 to="0 0 101 0"
    		 stroke-dashoffset="25"
    		 dur="0.8s"
    		 begin="gr1.mouseover"
    		 repeatCount="1"
    		 restart="whenNotActive"
    		 fill="freeze"  /> 
    		 
    	   <animate
    		 attributeName="stroke-dasharray"
    		 from="0 0 101 0"
    		 to="0 50.5 0 50.5"
    		 stroke-dashoffset="25"
    		 dur="0.8s"
    		 begin="gr1.mouseout"
    		 repeatCount="1"
    		 restart="whenNotActive"
    		 fill="freeze"  /> 
    	 </path>
         </g>	 
    </svg>

    • 8
  4. Stranger in the Q
    2020-02-17T23:01:34Z2020-02-17T23:01:34Z

    От меня, как и в прошлый раз WebGL изврат в 100 строчек кода вместе с разметкой и с небольшим бонусом в виде displacement'a

    введите сюда описание изображения

    Все это математика во фрагментном шейдере и те же самые signed distance fields, о которых я уже писал в посте по ссылке в начале

    Если коротко то вся соль, вот тут:

    vec3 paintCircle (vec2 uv, vec2 center, float rad, float width) {
    
        // координаты пикселя относительно центра "круга"
        vec2 diff = center - uv;
    
        // расстояние до этой точки
        float len = length(diff);
    
        // расстояние до "круга"
        float circle = smoothstep(rad - width, rad, len) - 
                       smoothstep(rad, rad + width, len);
    
        // поворот текстурных координат относительно центра "круга"
        vec2 at = (uv-center) * rotate2d(rotation);
    
        // вырезание 2 частей окружности
        if (at.x - 0.05 < 0. && at.x + 0.05 > 0.)
            circle -= 1.0; 
    
        return vec3(circle);
    }
    

    <!DOCTYPE html>
    <html lang="en">
    <body>
        <script>
            let started = new Date().getTime();
            let canvas = document.createElement('canvas');
            document.body.append(canvas);
            let size = canvas.width = canvas.height = 150;
            let gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
    
            let pid = gl.createProgram();
    
            shader(`
                attribute vec2 coords;
                void main(void) {
                    gl_Position = vec4(coords.xy, 0.0, 1.0);
                }
            `, gl.VERTEX_SHADER);
    
            shader(`
                precision highp float;
    
                uniform float time;
                uniform float rotation;
                uniform float displace;
    
                mat2 rotate2d(float angle) {
                    return mat2(cos(angle),-sin(angle),
                                sin(angle), cos(angle));
                }
    
                float displacement(vec2 v1, vec2 v2, float strength, float speed) {
                    return sin(
                        dot(normalize(v1), normalize(v2)) * strength + time * speed
                    ) / displace;
                }
    
                vec3 paintCircle (vec2 uv, vec2 center, float rad, float width) {
                    vec2 diff = center-uv;
                    float len = length(diff);
                    len += displacement(diff, vec2(0.0, 1.0), 5.0, 2.0);
                    len -= displacement(diff, vec2(1.0, 0.0), 5.0, 2.0);
                    float circle = smoothstep(rad-width, rad, len) - smoothstep(rad, rad+width, len);
                    vec2 at = (uv-center) * rotate2d(rotation);
                    if (at.x - 0.05 < 0. && at.x + 0.05 > 0.)
                        circle -= 1.0;
                    return vec3(circle);
                }
    
                void main(void) {
                    vec2 uv = gl_FragCoord.xy / ${size}.;
                    vec3 color = paintCircle(uv, vec2(0.5), 0.3, 0.1);
                    color *= vec3(uv.x, uv.y, 0.7-uv.y*uv.x);
                    color += paintCircle(uv, vec2(0.5), 0.3, 0.03);
                    gl_FragColor = vec4(1.0-color, color.r+color.g+color.b);
                }
            `, gl.FRAGMENT_SHADER);
    
            gl.linkProgram(pid);
            gl.useProgram(pid);
    
            let array = new Float32Array([-1,  3, -1, -1, 3, -1]);
            gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
            gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
    
            let al = gl.getAttribLocation(pid, "coords");
            gl.vertexAttribPointer(al, 2 /*components per vertex */, gl.FLOAT, false, 0, 0);
            gl.enableVertexAttribArray(al);
    
            let time = gl.getUniformLocation(pid, 'time');
            let rot = gl.getUniformLocation(pid, 'rotation');
            let displacement = gl.getUniformLocation(pid, 'displace');
            gl.uniform1f(displacement, 500);
    
            draw();
            var rotate = 0;
    
            function draw() {
                requestAnimationFrame(draw);
                let dt = new Date().getTime() - started;
                gl.uniform1f(rot, rotate * dt / 300);
                gl.uniform1f(time, dt / 1000);
                gl.viewport(0, 0, size, size);
                gl.clearColor(0, 0, 0, 0);
                gl.drawArrays(gl.TRIANGLES, 0, 3);
            }
    
            function shader(src, type) {
                let sid = gl.createShader(type);
                gl.shaderSource(sid, src);
                gl.compileShader(sid);
                gl.attachShader(pid, sid);
            }
    
            canvas.onmouseenter = function () {rotate = 1;};
            canvas.onmouseleave = function () {rotate = 0;};
        </script>
        <input type="range" min="10" max="1000" value="500" onchange="gl.uniform1f(displacement, this.value)">
    </body>
    </html>

    • 7

相关问题

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