Просвечивающий изображение блок

96
26 марта 2021, 12:00

Подобных вещей еще не приходилось реализовывать, по этому нуждаюсь в помощи выбора оптимального способа реализации.
Постараюсь максимально понятно объяснить, что нужно сделать.
Есть блок с изображением, при попадании курсора в область этого блока, курсор заменяется на прямоугольный блок (возможно прозрачное изображение с рамкой), под которым начинает просвечиваться блок с изображением, а под ним в свою очередь, находится другое изображение часть которого становится видна. Получается что-то вроде clip-path как здесь http://www.cssplant.com/clip-path-generator только вместо белого фона другое изображение и желательно иметь возможно как-то стилизовать просвечиваемую область, возможно даже размещать в ней какие-то еще элементы. Также на заднем фоне, есть активные области и если они попадают в область просмотра под курсором, нужно это отлавливать.
Предполагаю, что нужно смотреть в сторону canvas'a. Если вдруг кто-то реализовывал подобное или имеет понятие как это можно осуществить, возможно знаете готовые библиотеки для подобных решений, буду рад любой помощи.

Answer 1

Что-то подобное соорудил на svg + js

Эффект достигается за счет clip-path и подсчета расстояния от курсора до активных зон.

// точка, для пересчета координат мыши в координаты svg холста 
var pt = svg.createSVGPoint(); 
 
// активные зоны 
var zones = document.querySelectorAll('.zone'); 
 
addEventListener('mousemove', e => { 
 
  // так получаем координаты мыши относительно холста 
  pt.x = e.clientX;  
  pt.y = e.clientY;  
  let p = pt.matrixTransform(svg.getScreenCTM().inverse()); 
 
  // позиционируем clip-path 
  clipRect.setAttribute('x', p.x - 7.5); 
  clipRect.setAttribute('y', p.y - 17); 
   
  // позиционируем телефон 
  phone.setAttribute('x', p.x - 12.5); 
  phone.setAttribute('y', p.y - 25); 
  text.setAttribute('x', p.x); 
  text.setAttribute('y', p.y + 13); 
  text.innerHTML = ''; 
   
  // перебираем все зоны 
  zones.forEach(z => { 
 
    // текущая прозрачность активной зоны 
    let o = z.style.opacity; 
     
    // новое значение прозрачности на основании теста попадания круга в прямоугольник 
    z.style.opacity = test(z, clipRect) ? 1 : 0; 
     
    +z.style.opacity && (text.innerHTML = z.id); 
     
    // если значение прозрачности изменилось с 0 на 1 вызываем callback 
    +z.style.opacity - o === 1 && callback(z.id); 
       
  }) 
   
}) 
 
function test(zone, rect) { 
    var zx = +zone.getAttribute('cx'); 
    var zy = +zone.getAttribute('cy'); 
    var zr = +zone.getAttribute('r'); 
    var rx = +rect.getAttribute('x'); 
    var ry = +rect.getAttribute('y'); 
    var rw = +rect.getAttribute('width'); 
    var rh = +rect.getAttribute('height'); 
    return zx - zr > rx && zx + zr < rx + rw && 
           zy - zr > ry && zy + zr < ry + rh; 
} 
 
function callback(id) { 
  console.log(id) 
}
<body style="margin:0;overflow:hidden;"> 
  <svg viewBox="0 0 200 100" height="100vh" id="svg" style="cursor:none;"> 
    <defs> 
      <pattern id="img1" patternUnits="userSpaceOnUse" width="200" height="100"> 
        <image xlink:href="https://picsum.photos/id/1/800/400" width="200" height="100"/> 
      </pattern> 
      <pattern id="img2" patternUnits="userSpaceOnUse" width="200" height="100"> 
        <image xlink:href="https://picsum.photos/id/2/800/400" width="200" height="100"/> 
      </pattern> 
      <clipPath id="clip"> 
        <rect id="clipRect" width="15" height="34"></rect> 
      </clipPath> 
    </defs> 
    <rect width="200" height="100" fill="url(#img1)"></rect> 
    <rect width="200" height="100" fill="url(#img2)" clip-path="url(#clip)"></rect> 
    <circle id="zone1" class="zone" cx="20" cy="20" r="2"></circle> 
    <circle id="zone2" class="zone" cx="50" cy="70" r="4"></circle> 
    <circle id="zone3" class="zone" cx="120" cy="30" r="5"></circle> 
    <circle id="zone4" class="zone" cx="150" cy="80" r="3"></circle> 
    <image id="phone" width="25" height="50"  
           xlink:href="https://www.searchpng.com/wp-content/uploads/2018/12/Apple-iPhone-XR-715x1090.png"></image> 
    <text id="text" text-anchor="middle" alignment-baseline="middle" font-size="5" fill="white"></text> 
    <style> 
      .zone { 
        fill:red; 
        opacity:0; 
      } 
    </style> 
  </svg> 
</body>

READ ALSO
Меняющаяся разметка в css

Меняющаяся разметка в css

Почему при копировании CSS кода из одного файла и его вставке в другой CSS файл разметка выглядит по-другому? Я разметил каркас, который нужен...

121
Polygon и path (Svg паттерны)

Polygon и path (Svg паттерны)

В чем отличие path от polygon?

140
Как выровнять grid-блок по ширине размера окна?

Как выровнять grid-блок по ширине размера окна?

У меня есть 8 элементов расположеных в два ряда по горизонталиДля позиционирования, я использовал CSS Grid Layout

120
Обобщённый Query в Mediatr

Обобщённый Query в Mediatr

Столкнулся с вот какой проблемой переделывая репозиторий на CQS

137