Частично закрасить границу фигуры цветом

Я пытаюсь создать эффект прогресса, при котором цвет заполняет границу объекта DOM (или, возможно, фон). Прикрепленное изображение должно дать вам лучшее представление о том, для чего я иду. Я достиг текущего результата, добавив объект со сплошным фоновым цветом поверх серых линий и установив его высоту. Этот объект имеет mix-blend-mode: color-burn; применяется к нему, поэтому он окрашивает только серые линии под ним.

Это работает хорошо, но разрушает сглаживание по кругу, а также полученный цвет непредсказуем (меняется в зависимости от цвета линий).

Я чувствую, что должен быть лучший способ достичь этого, возможно, с помощью элемента canvas. Может ли кто-нибудь указать мне правильное направление, пожалуйста?

Заранее спасибо!

пример

1 ответ

Решение

Это должно быть возможно с Canvas и даже с самим CSS, играя с несколькими элементами и т. Д., Но я определенно рекомендую вам использовать SVG. SVG предлагает множество преимуществ с точки зрения того, насколько легко кодировать, поддерживать, а также создавать адаптивные выходные данные (в отличие от Canvas, который имеет тенденцию к пикселизации при масштабировании).

Ниже приведены компоненты:

  • rect элемент того же размера, что и родитель svg и имеет linear-gradient заполнить. Градиент имеет два цвета: один - базовый (светло-серый), а другой - прогресс (голубой).
  • mask который применяется на rect элемент. Маска имеет path которая не что иное, как линия и круг. Когда mask применяется к rect, только это path будет показывать через фактический фон (или заполнить) rect остальная часть области будет замаскирована другим rect который добавляется внутри mask,
  • mask также имеет text элемент для отображения значения прогресса.
  • linear-gradient имеет stop offset установить таким образом, чтобы он равнялся прогрессу. Изменяя offset мы всегда можем убедиться, что path показывает ход выполнения только для необходимой длины и базы (светло-серый) для остальных.

window.onload = function() {
  var progress = document.querySelector('#progress'),
    base = document.querySelector('#base'),
    prgText = document.querySelector('#prg-text'),
    prgInput = document.querySelector('#prg-input');
  prgInput.addEventListener('change', function() {
    prgText.textContent = this.value + '%';
    progress.setAttribute('offset', this.value + '%');
    base.setAttribute('offset', this.value + '%');
  });
}
svg {
  width: 200px;
  height: 300px;
}
path {
  stroke-width: 4;
}
#rect {
  fill: url(#grad);
  mask: url(#path);
}

/* just for demo */
.controls {
  position: absolute;
  top: 0;
  right: 0;
  height: 100px;
  line-height: 100px;
  border: 1px solid;
}
.controls * {
  vertical-align: middle;
}

body {
  background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<svg viewBox='0 0 200 300' id='shape-container'>
  <linearGradient id='grad' gradientTransform='rotate(90 0 0)'>
    <stop offset='50%' stop-color='rgb(0,218,235)' id='progress' />
    <stop offset='50%' stop-color='rgb(238,238,238)' id='base' />
  </linearGradient>
  <mask id='path' maskUnits='userSpaceOnUse' x='0' y='0' width='200' height='300'>
    <rect x='0' y='0' width='200' height='300' fill='black' />
    <path d='M100,0 100,100 A50,50 0 0,0 100,200 L100,300 M100,200 A50,50 0 1,0 100,100' stroke='white' />
    <text id='prg-text' x='100' y='155' font-size='20' text-anchor='middle' fill='white'>50%</text>
  </mask>
  <rect id='rect' x='0' y='0' width='200' height='300' />
</svg>

<!-- just for demo -->
<div class='controls'>
  <label>Set Progress:</label>
  <input type='range' id='prg-input' min='0' max='100' value='50' />
</div>


Если вы новичок в SVG, вы можете обратиться к MDN Docs (ссылки приведены ниже) для получения дополнительной информации об элементах, их атрибутах и ​​значениях.

Другие вопросы по тегам