【问题标题】:SVG Gradient like Canvas Gradient?SVG渐变像画布渐变?
【发布时间】:2019-01-18 23:48:44
【问题描述】:

Here 是我构建的。您可以拖动图像来探索整个图像。

<?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 中做类似的事情?

想到的一个想法类似于以下任一图像,其中将使用多个渐变,但对于可以在画布中轻松完成的事情似乎需要做很多工作。

【问题讨论】:

  • 您的 codepen 在 FireFox 中不起作用。
  • @KoshVery 是图片。由于某种原因,图像似乎没有加载:/ 为什么会这样?
  • @KoshVery 我发布了another Q here,如果你有兴趣的话
  • 您必须在 svg1 中设置 width 和 height 属性。 FF仍然不支持svg2的这部分

标签: javascript svg canvas gradient mask


【解决方案1】:

你想要的是&lt;mask&gt;

在此蒙版中,您将附加黑色填充的小圆形 &lt;rect&gt;,并在其上应用 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>

但请注意,通过 CSS 设置 svg 元素的尺寸是 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>

这里是interactive version,只有一张图片。

【讨论】:

  • 在你的第一个演示中,被白色覆盖的地图部分是一个image元素,而不是白色的部分是另一个image,对吗?另一个需要注意的是,我将在“眼睛”/矩形边缘周围设置其他元素的动画
  • &lt;mask&gt; 中的白色部分将在被遮罩的元素中保持为不透明。黑色的东西变得透明。所以我首先用黑色画了一个完整的矩形(它的大小在 CSS 中设置),你的#rectangle 是白色的。然后我们将这个遮罩应用到前景图像上。但实际上,使用灰色矩形作为背景,我们甚至可以用一个 &lt;image&gt;:jsfiddle.net/1gfx7jrL 来完成所有这些操作。对于动画,我不确定是否会得到它,但你可以在里面添加任何你想要的东西掩码:jsfiddle.net/1gfx7jrL/1
  • 我尚未深入或逐字阅读您的评论,但我远离面具并使用 2 张图片的原因是因为一张图片上会显示图标(被剪裁的图像)我不希望在图像的白色部分或“眼睛”窗口之外可见
  • 好吧,事实证明我的方法甚至无法让我做我想做的事,因此使用面具代替是最实用的。但是,我似乎无法让附加图像(您在示例中使用骰子图像)也具有相同级别的透明度??? here is what i'm working with right now 知道这里发生了什么吗???
  • 您需要将您的蒙版视为一个独立的图像,它将应用于目标。目标上的每个黑色像素都将被删除,而每个白色和透明像素都将保持不变。所以如果需要统一掩码,需要将this image统一。这应该通过更改您的图像来完成,以便当前的黑色实际上与#background (#999) 相同的灰色,即使it is technically possible 应用过滤器来做到这一点,它也是一个性能杀手(在我的FF,Chrome 在这里很好)。
猜你喜欢
  • 1970-01-01
  • 2011-04-29
  • 1970-01-01
  • 2022-01-19
  • 2019-07-30
  • 1970-01-01
  • 1970-01-01
  • 2014-02-18
  • 2011-09-19
相关资源
最近更新 更多