Как изменить заливку круга на основе цвета фона с помощью javascript?
В основном я хочу, чтобы круг менял цвет, когда ползунок перемещает его по флагу: зеленый на белом фоне, белый на зеленом прямоугольнике.
function move() {
let slider = document.querySelector("#slider");
let circle = document.querySelector("#player");
circle.setAttribute("cx", slider.value);
}
<h1>Flag</h1>
<svg width="375" height="375">
<g id="flag">
<rect x="0" y="0" width="125" height="375" fill="green"/>
<rect x="250" y="0" width="125" height="375" fill="green"/>
</g>
<circle id="player" cx="187.5" cy="187.5" r="10" fill="green" />
</svg><br>
<input id="slider" type="range" min="0" max="375" value="150" style="width:370px" oninput="move()">
Свободный перевод вопроса how to change circle fill based on background color with javascript? от участника @thegoldmolar.
Ответы (2 шт):
Нет простого способа сделать это с помощью SVG-фильтров или режимов наложения и т.д. Вам, вероятно, придется просто переключить цвет самостоятельно в зависимости от позиции круга. См. ниже.
function move() {
let slider = document.querySelector("#slider");
let circle = document.querySelector("#player");
circle.setAttribute("cx", slider.value);
circle.setAttribute('fill', (slider.value >= 125 && slider.value < 250) ? 'green' : 'white');
}
<h1>Flag</h1>
<svg width="375" height="375">
<g id="flag">
<rect x="0" y="0" width="125" height="375" fill="green"/>
<rect x="250" y="0" width="125" height="375" fill="green"/>
</g>
<circle id="player" cx="187.5" cy="187.5" r="10" fill="green"/>
</svg><br>
<input id="slider" type="range" min="0" max="375" value="150" style="width:370px" oninput="move()">
Свободный перевод ответа от участника @Paul LeBeau.
Для такой простой задачи можно использовать SVG-фильтр, а конкретно - <feComposite> со значением xor. Чтобы всё сработало, нужно понимать алгоритм действия фильтров, а он, примерно, таков:
- В памяти вычисляются слои с фигурами, заливками и т.п.;
- Слои растрируются с помощью
<feImage>; - К растрированным слоям применяется нужный фильтр;
- Итог рендерится (выводится на экран).
function move() {
let slider = document.querySelector("#slider");
let circle = document.querySelector("#player");
circle.setAttribute("cx", slider.value);
}
<h1>Flag</h1>
<svg width="375" height="375" viewBox="-37.5 -37.5 375 375">
<defs>
<g id="flag">
<rect x="0" y="0" width="125" height="375" fill="green" />
<rect x="250" y="0" width="125" height="375" fill="green" />
</g>
<circle id="player" cx="187.5" cy="187.5" r="10" fill="green" />
<filter id="imageXor">
<feImage xlink:href="#flag" result="lay1" />
<feImage xlink:href="#player" result="lay2" />
<feComposite operator="xor" in="lay1" in2="lay2" />
</filter>
</defs>
<use xlink:href="#flag" filter="url(#imageXor)"></use>
</svg>
<br>
<input id="slider" type="range" min="0" max="375" value="187.5" style="width:370px" oninput="move()">
Таким образом, необходимо помнить, что очень многие фильтры работают именно с растром. Часто про это забывают и пытаются напрямую использовать векторный (читай, параметрический) объект с растровым (в случае с картинками и градиентами) или таким же вектором.