SVG蒙版的一部分不透明且颜色反转

时间:2019-01-22 01:11:35

标签: html css xml svg mask

我要尝试的是在SVG蒙版中添加带纹理的框架或边框。

  1. Here是我想要实现的工作演示。

  2. 我正在使用
  3. Here

请注意,在第二个演示中,遮罩中使用的图像#frame似乎没有任何透明度,并且颜色反转了(因此实际上黑色显示为纯白色),与工作演示中的遮罩图像#rectangle > image

但是,我可以在两个演示之间发现的唯一区别是,第一个有效的演示将feGaussianBlur应用于g元素。我已经尝试在第二个演示中将#eye#frame进行分组,但这似乎没有任何效果。

我想念什么?

2 个答案:

答案 0 :(得分:3)

您需要将<mask>视为独立的灰度图像,并将其应用于目标元素。
在那里,每个黑色像素都会从目标上移除,而每个白色和透明像素都不会被触摸,换句话说,遮罩中的像素越暗,目标上的透明度就越高。

这是两个面具

.bg {
  width: 100%;
  height: 100%;
  fill: #666;
}
#background {
  fill: #999;
}
#eye {
  fill: #fff;
}
.fake-mask {
  filter: grayscale(100%);
}
svg{width: 40vw; display: inline-block}
<svg  viewBox='0 0 800 800'>
<defs>
    <filter id="blurMe">
      <feGaussianBlur in="SourceGraphic" stdDeviation="2" />
    </filter>
</defs>
<!--    <mask id="myMask"> -->
    <g class="fake-mask">
      <rect class='bg' width="800" height="800"/>
      <g id="rectangle" filter="url(#blurMe)">
        <rect  width="300" height="400" x="120" rx='10' ry='10' fill="white" />
        <image
        xlink:href='https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png'
        width="200" height="200"/>
      </g>
    </g>
<!--    </mask> -->
</svg><svg  viewBox='0 0 800 800'>
<!--  <mask id='mask'> -->
  <g class="fake-mask">
    <rect id='background' x='0' y='0' width='6144' height='4608' />
    <rect id='eye' x='0' y='0' width='500' height='500' />
    <image id='frame' xlink:href='https://newvitruvian.com/images/speckled-vector-distress.png' x='0' y='0' width='500' height='500' preserveAspectRatio='none' />
   </g>
<!--  </mask> -->
</svg>

如您所见,图像的边界比背景矩形更暗,这意味着目标在该图像的边界处比在背景处更加透明。

要解决此问题,您必须使图像的黑色像素变成与背景相同的灰色阴影,以便目标能够获得统一的不透明度。

虽然可以使用过滤器来做,但是请注意,它可能会破坏表演。

const
  bdy = document.body,
  svg = document.getElementById('svg'),
  bkg = document.getElementById('background'),
  eye = document.getElementById('eye'),
  frm = document.getElementById('frame')
let
  eyeW = 0.35,
  eyeH = 0.75,
  mousednX = 0,
  mousednY = 0


// position maps on load
//
window.addEventListener('load', position)

function position(){
  const
    box = svg.getBoundingClientRect()
  svg.style.left = -(box.width - innerWidth) / 2 + 'px'
  svg.style.top = -(box.height - innerHeight) / 2 + 'px'
  
  const
    x = -(svg.getBoundingClientRect().left) + innerWidth * (1 - eyeW) / 2,
    y = -(svg.getBoundingClientRect().top) + innerHeight * (1 - eyeH) / 2
  eye.setAttribute('width', innerWidth * eyeW)
  eye.setAttribute('height', innerHeight * eyeH)
  eye.setAttribute('x', x)
  eye.setAttribute('y', y)
  frm.setAttribute('width', innerWidth * eyeW)
  frm.setAttribute('height', innerHeight * eyeH)
  frm.setAttribute('x', x)
  frm.setAttribute('y', y)
}

// drag functionality to explore map
//
bdy.addEventListener('mousedown', mousedown)
window.addEventListener('mouseup', mouseup)

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
}

// center eye on cursor position
//
bdy.addEventListener('mousemove', moveEye)

function moveEye(e){
  const
    x = -(svg.getBoundingClientRect().left) + e.clientX - eyeW * innerWidth / 2,
    y = -(svg.getBoundingClientRect().top) + e.clientY - eyeH * innerHeight / 2
  eye.setAttribute('x', x)
  eye.setAttribute('y', y)
  frm.setAttribute('x', x)
  frm.setAttribute('y', y)
}
body {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  margin: 0;
}

#svg {
  width: 6144px;
  height: 4608px;
  position: absolute;
  left: -3072px;
  top: -2304px;
}



#eye {
  fill: #FFF;
}

#map {
  width: 6144px;
  height: 4608px;
  mask: url('#mask');
}
<svg id='svg' viewBox='0 0 6144 4608' version='1.1'>
  <filter id="contrast">
    <feComponentTransfer>
      <feFuncR type="linear" slope="0.4" intercept="0.2"/>
      <feFuncG type="linear" slope="0.4" intercept="0.2"/>
      <feFuncB type="linear" slope="0.4" intercept="0.2"/>
    </feComponentTransfer>
  </filter>
  <mask id='mask'>
    <g filter="url(#contrast)">
    <rect id='background' x='0' y='0' width='6144' height='4608' fill="#000"/>
    <rect id='eye' x='0' y='0' width='0' height='0' />
    <image id='frame' xlink:href='https://newvitruvian.com/images/speckled-vector-distress.png' x='0' y='0' width='0' height='0' preserveAspectRatio='none'/>
  </g>
  </mask>
  <image id='map' xlink:href='https://i.postimg.cc/hvH4yn2Q/map.jpg' x='0' y='0' width='6144' height='4608' mask="url(#myMask)"/>
</svg>

答案 1 :(得分:0)

在使用CodePen进行工作时,我注意到#frame图像中出现的白色,外部背景来自默认的SVG文档背景颜色,该颜色未定义并且看起来是白色。

如果您为background-color元素定义了#svg样式,例如说#f00(红色),则背景和#frame图像都将显示为红色。 / p>

最后,我发现将opacity图像的#frame调整为0.4可以更好地融合蒙版框架和背景。您可以重新绘制#frame图像,以更好地匹配图像矩形边框处的背景。

我刚刚在您的CodePen中添加了background-color(白色)和opacity(0.4),如下所示:

#svg {
  width: 6144px;
  height: 4608px;
  position: absolute;
  left: -3072px;
  top: -2304px;
  background-color: #fff;
}

#frame {
  opacity: .4;
}