SVG Градиент, как Canvas Gradient? - PullRequest
0 голосов
/ 19 января 2019

Здесь - это то, что я построил.Вы можете перетаскивать изображение, чтобы исследовать все изображение.

<?xml version='1.0' standalone='no'?>
<svg version='1.1'>
  <image xlink:href='https://i.postimg.cc/hvH4yn2Q/map.jpg'
    id='background-image' />
  <clipPath>
    <rect />
  </clipPath>
  <image xlink:href='https://i.postimg.cc/hvH4yn2Q/map.jpg'
    id='main-image'/>
</svg>

Вместо того, чтобы обрезанный прямоугольник имел сплошные края, я хотел бы сделать что-то вроде this, за исключением SVG. Предостережение заключается в том, что он должен быть отзывчивым, поскольку ограниченный прямоугольник является отзывчивым.

Возможно ли сделать что-то подобное в SVG?

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

enter image description here

enter image description here

1 Ответ

0 голосов
/ 19 января 2019

То, что вы хотите, это <mask>.

В этой маске вы добавите маленькую округленную <rect>, заполненную черным, с нанесенным на нее feGaussianBlur.

const
  bdy = document.body,
  svg = document.getElementById('svg'),
  crc = document.getElementById('circle'),
  rec = document.getElementById('rectangle')
let
  mousednX = 0,
  mousednY = 0

window.addEventListener('load', position)
bdy.addEventListener('mousedown', mousedown)
window.addEventListener('mouseup', mouseup)
bdy.addEventListener('mousemove', moveEye)

function position(){
  const
    box = svg.getBoundingClientRect()
  svg.style.left = -(box.width - innerWidth) / 2 + 'px'
  svg.style.top = -(box.height - innerHeight) / 2 + 'px'
}

function mousedown(e){
  e.preventDefault()
  mousednX = e.clientX
  mousednY = e.clientY
  bdy.addEventListener('mousemove', mousemove)
}

function mouseup(){
  bdy.removeEventListener('mousemove', mousemove)
}

function mousemove(e){
  adjustX = e.clientX - mousednX
  adjustY = e.clientY - mousednY
  if (svg.getBoundingClientRect().left + adjustX < 0 && svg.getBoundingClientRect().right + adjustX > innerWidth){
    svg.style.left = svg.getBoundingClientRect().left + adjustX + 'px'
  } else if (svg.getBoundingClientRect().left + adjustX >= 0){
    svg.style.left = 0 + 'px'
  } else {
    svg.style.left = -(svg.getBoundingClientRect().width - innerWidth)
  }
  if (svg.getBoundingClientRect().top + adjustY < 0 && svg.getBoundingClientRect().bottom + adjustY > innerHeight){
    svg.style.top = svg.getBoundingClientRect().top + adjustY + 'px'
  } else if (svg.getBoundingClientRect().top + adjustY >= 0){
    svg.style.top = 0 + 'px'
  } else {
    svg.style.top = -(svg.getBoundingClientRect().height - innerHeight)
  }
  mousednX = e.clientX
  mousednY = e.clientY
}

function moveEye(e){
  rec.setAttribute('x', -(svg.getBoundingClientRect().left) + e.clientX - rec.getBoundingClientRect().width / 2)
  rec.setAttribute('y', -(svg.getBoundingClientRect().top) + e.clientY - rec.getBoundingClientRect().height / 2)
}
body {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

#svg {
  width: 6144px;
  height: 4608px;
  position: absolute;
  left: -3072px; /* set with JS */
  top: -2304px; /* set with JS */
}

#background-image {
  width: 6144px;
  height: 4608px;
  opacity: 0.25;
}

#rectangle {
  width: 35vw;
  height: 75vh;
}

#main-image {
  width: 6144px;
  height: 4608px;
  mask: url(#myMask);
}
#myMask .bg {
  width: 100%;
  height: 100%;
}
<svg id='svg' viewBox='0 0 6144 4608' version='1.1'>
  <defs>
    <filter id="blurMe">
      <feGaussianBlur in="SourceGraphic" stdDeviation="5" />
    </filter>
    <mask id="myMask">
      <rect class='bg'/>
      <rect id='rectangle' x='3172' y='2404' rx='10' ry='10' fill="white" filter="url(#blurMe)"/>
    </mask>
  </defs>
  <image x='0' y='0' preserveAspectRatio='none'
    xlink:href='https://i.postimg.cc/hvH4yn2Q/map.jpg'
    id='background-image' />
  <image x='0' y='0' preserveAspectRatio='none'
    xlink:href='https://i.postimg.cc/hvH4yn2Q/map.jpg'
    id='main-image'/>
</svg>

Но обратите внимание, что установка размеров ваших элементов SVG с помощью CSS является новой функцией SVG2, и что все браузеры до сих пор не реализовали ее (например, Firefox). Итак, вот версия, совместимая с SVG1, но единицы vw / vh не будут работать.

<svg width="500" height="500" viewBox="0 0 500 500">
  <defs>
    <filter id="blurMe">
      <feGaussianBlur in="SourceGraphic" stdDeviation="5" />
    </filter>
    <mask id="myMask">
      <rect width="500" height="500" fill="black"/>
      <rect y="100" fill="white" width="50" height="50" x="35" y="35" rx="5" ry="5" filter="url(#blurMe)"/>
    </mask>
  </defs>  
  <image xlink:href='https://i.postimg.cc/hvH4yn2Q/map.jpg'
    id='background-image' width="500" height="500" style="opacity:0.3"/>
  <image xlink:href='https://i.postimg.cc/hvH4yn2Q/map.jpg'
    id='main-image' width="500" height="500" mask="url(#myMask)"/>
</svg>

И вы могли бы сделать все это с одним изображением, установив цвет заливки фона на некоторый оттенок серого:

<svg width="500" height="500" viewBox="0 0 500 500">
  <defs>
    <filter id="blurMe">
      <feGaussianBlur in="SourceGraphic" stdDeviation="5" />
    </filter>
    <mask id="myMask">
      <rect width="500" height="500" fill="#333"/>
      <rect y="100" fill="white" width="50" height="50" x="35" y="35" rx="5" ry="5" filter="url(#blurMe)"/>
    </mask>
  </defs>  
  <image xlink:href='https://i.postimg.cc/hvH4yn2Q/map.jpg'
    id='main-image' width="500" height="500" mask="url(#myMask)"/>
</svg>

Вот интерактивная версия с одним изображением.

...