2017-01-31 16 views
2

Я пытаюсь постепенно заполнять эллипс за вращающимся радиусом, действительно, похожим на часы таймером, который заполняется за широкой рукой. Я близок к тому, чтобы это правильно, но дуга заполненной области движется с каждым пересчетом.SVG Draw Path и Fill с эллиптической дугой

версия CodePen является here, но в итоге, я использую следующий HTML для запуска:

<svg version="1.1" baseProfile="full" width="50%" height="50%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 3 3.2"> 
    <path id="pie" stroke="none" stroke-width=".01" fill="rgb(204, 50, 50)" 
      d="M 1.5 1.7 V 1.5 .3 
      A 1.5 1.3 0 0 1 1.5 .2 
      z"/> 
    <line id="hand" stroke="black" stroke-width=".02" 
      x1="1.5" y1="1.7" x2="1.5" y2=".2"/> 
</svg> 

и вращать руку и рисовать/заливкой за ним следующий JavaScript:

var sweep = document.getElementById("hand"), 
    fill = document.getElementById("pie"), 
    degrees = 0; 
const Torads = Math.PI/180; 

function rotateHand() { 
    degrees += 45; 
    sweep.setAttribute("transform", "rotate(" + degrees + " 1.5 1.7)"); 
    if (degrees <= 180) { 
    fill.setAttribute("d", "M 1.5 1.7 V .4 A 1.4 1.3 0 0 1 " + ellipticalXcoords(Math.cos((degrees-90) * Torads)) + " " + ellipticalYcoords(Math.sin((degrees-90) * Torads)) + " z"); 
    } else { 
    fill.setAttribute("d", "M 1.5 1.7 V .4 A 1.4 1.3 0 1 1 " + ellipticalXcoords(Math.cos((degrees - 90) * Torads)) + " " + ellipticalYcoords(Math.sin((degrees - 90) * Torads)) + " z"); 
    } 

ответ

4

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

Вот как я это сделаю. Обратите внимание, что круговая заливка поворачивается на -90 °, чтобы анимация начиналась в верхней части круга, а не сбоку. Соответствующее вращение + 90 ° применяется к маске клипа для объяснения этого.

var sweep = document.getElementById("hand"), 
 
    fill = document.getElementById("apple-fill"), 
 
    degrees = 0; 
 
const Torads = Math.PI/180; 
 
var animating = false; 
 

 
function rotateHand() { 
 
    degrees += 4; 
 
    if (degrees >= 360) { 
 
    clearInterval(animating); 
 
    animating = false; 
 
    degrees = 360; 
 
    } 
 
    sweep.setAttribute("transform", "rotate(" + degrees + " 1.5 1.7)"); 
 
    fill.setAttribute("stroke-dasharray", degrees * 0.01309 + ", 20"); 
 
} 
 

 
function startAnimation() { 
 
    if (!animating) { 
 
    degrees = 0; 
 
    animating = setInterval(rotateHand, 30); 
 
    } 
 
}
<button onclick="startAnimation(); return 0">Animate</button> 
 
<svg width="200" height="200" viewBox="0 0 3 3.2"> 
 
    <defs> 
 
    <clipPath id="apple"> 
 
     <path d="M1.5.5A.2.2 0 0 1 1.7.315A1.4 1.3 0 1 1 1.3.315A.2.2 0 0 1 1.5.5z" transform="rotate(90,1.5,1.7)" /> 
 
    </clipPath> 
 
    </defs> 
 
    <circle cx="1.5" cy="1.7" r=".75" id="apple-fill" fill="none" stroke="rgb(204, 50, 50)" stroke-width="1.5" stroke-dasharray="0,20" transform="rotate(-90,1.5,1.7)" clip-path="url(#apple)" /> 
 
    <path id="pomodoro" stroke-width=".01" fill="none" stroke="#000" d="M1.5.5A.2.2 0 0 1 1.7.315A1.4 1.3 0 1 1 1.3.315A.2.2 0 0 1 1.5.5" /> 
 
    <path id="leaf" stroke-width=".01" stroke-linejoin="arc" fill="green" d="M1.5.6A.4.4 0 0 1 2 .1A.5.5 0 0 1 1.5.6" /> 
 
    <line id="hand" stroke="black" stroke-width=".02" x1="1.5" y1="1.7" x2="1.5" y2=".2" /> 
 
</svg>

+0

В случае, если вам интересно, где коэффициент '0.01309' пришли - это преобразует угол (в градусах) к длине пути по окружности радиусом 0,75 (2 * π * 0.75/360 ≈ 0.01309) –

+0

gotcha: некоторые браузеры (думаю, это старые сафари iOs) не запускают круг под углом 90 градусов. Решение: конвертировать круг в путь. – Ruskin

+0

@squeamishossifrage Похоже, что это сработает. Теперь я помню, что видел описание маскирующего решения, но я думал, что математика не должна быть слишком сложной. Но я думаю, что это будет хорошо работать. Благодарю. –