Javascript math "рисовать" прямоугольники вокруг нескольких других прямоугольников для достижения фонового эффекта
Примечание. Я буду использовать слово overlay взаимозаменяемо с фоном.
В настоящее время я работаю над режимом руководства и выделяю элементы, чтобы они выделялись из более темного полупрозрачного фона.
Итак, в основном у меня есть селектор для элемента, который я не хочу накладывать, а затем окружаю его полупрозрачными темными divs, имитируя наложение с исключенным элементом.
Мое решение отлично подходит для одного выделенного элемента, но когда это число становится 2+, становится сложно рассчитать, как разместить черные div вокруг этих элементов. И дело в следующем: потребности подсветки будут значительно различаться от страницы к странице - это не так, как эти несколько элементов будут статическими.
Итак, чтобы проиллюстрировать мою проблему:
![введите описание изображения здесь]()
Здесь вы можете увидеть различные поля, которые нужно поместить на страницу, чтобы окружить Box2 и Box2 полупрозрачными темными div, в основном имитируя эффект наложения с выделенными элементами. Для одного случая, подобного этому, я могу жестко запрограммировать вычисления, и все будет хорошо, но что, если Box1 был выше, чем Box2? Тогда что, если они больше не пересекаются друг с другом по горизонтали? Что делать, если в Box3 требуется подсветка?
В любом случае я не знаю, сколько темных ящиков нужно разместить и где их разместить.
Есть ли какая-нибудь математическая формула, которая помогла бы мне в этом случае? Использование jQuery также возможно, поскольку оно включено в мой проект.
Как мне подойти к этой проблеме и сделать ее расширяемой (несколько ящиков, разные позиции)?
Ответы
Ответ 1
Ты слишком задумываешься!
То, что вы ищете, может быть достигнуто с помощью определенного HTML и CSS-макета.
Вы должны использовать макет, подобный этому:
.container
.overlay
.box
.box
.box
.box
Фокус в том, чтобы использовать полноразмерную, полупрозрачную накладку и приносить элементы, которые необходимо выделить впереди. Очень важно назначить pointer-events: none
наложение, чтобы вы могли щелкнуть его!
Сделайте .box
значение z-index
, скажем, 1
и .overlay
, имеет значение z-index
100
. Чтобы выделить определенный .box
, установите его z-index
на 101
. Таким образом, он будет выделен.
Сейчас я на мобильный, но я поставил базовую концепцию концепции Codepen. Щелкните по ячейкам, чтобы выделить их, нажмите еще раз, чтобы отменить. Работает с несколькими ящиками!
Ответ 2
Вы можете легко решить эту проблему с помощью тени.
Затем вам нужно всего лишь сегментировать экран в 2 частях
body, html {
height: 100%;
}
body {
background-image: linear-gradient(45deg, yellow, tomato);
}
.mask {
overflow: hidden;
width: 50%;
height: 100%;
display: inline-block;
position: relative;
}
#mask1 {
left: 0px;
}
#mask2 {
right: 0px;
}
.hole {
width: 150px;
height: 90px;
position: absolute;
box-shadow: 0px 0px 0px 2000px rgba(0,0,0,0.5);
}
#mask1 .hole {
left: 40px;
top: 40px;
}
#mask2 .hole {
left: 140px;
top: 20px;
}
<div class="mask" id="mask1">
<div class="hole"></div>
</div><div class="mask" id="mask2">
<div class="hole"></div>
</div>
Ответ 3
Рассмотрим использование регионов
В то время как здесь есть несколько хороших ответов, и вы можете подумать о перемещении элементов, таких как @WearyAdventurer, ни один из других ответов не отвечает на исходный вопрос:
Как создать элементы таким образом, чтобы они окружали другие элементы?
Ответ на этот вопрос лучше всего решать с использованием типа данных, называемого Region. Регионы позволяют легко выполнять операции набора с использованием фрагментов двумерного экрана: объедините эту область с этой областью, а затем вычтите другую область, а затем превратите результат в набор прямоугольников, которые я могу отобразить. Регионы существуют в большинстве оконных систем (MS Windows, X Windows, классический MacOS и другие) и используются в большинстве внутренних систем браузеров для рендеринга элементов, но они неожиданно отсутствуют в JavaScript.
Или они отсутствовали, пока я не написал библиотеку, чтобы сделать это.
Основная логика регионов несколько сложна. Есть много угловых случаев, и обработка всех сценариев, которые могут возникнуть, может быть сложной задачей. Моя реализация, Region2D, использует непересекающиеся строки (полосы) непересекающихся прямоугольников (1-мерные области), что аналогично тому, как многие X серверы Windows делают это. В других реализациях используются пространственные алгоритмы разбиения, а третьи (например, современные MacOS) используют методы переноса или полигональной рендеринга вместо областей вообще.
Основная идея
Независимо от того, какую реализацию вы используете, основная идея остается прежней. В вашем случае вы начинаете с большого прямоугольника, который покрывает экран, а затем просто вычитают два (или три, или четыре или любые) прямоугольники, которые вы хотите, а затем задаете область, прямоугольники которой являются результатом этих операций. В JavaScript, используя мою библиотеку Region2D, он выглядит следующим образом:
var screenRegion = new Region([0, 0, viewportWidth, viewportHeight]);
var elemRegion1 = new Region(element1);
var elemRegion2 = new Region(element2);
var coverRegion = screenRegion.subtract(elemRegion1).subtract(elemRegion2);
var coverRectangles = coverRegion.getRects();
Результирующий массив прямоугольников - это простые объекты, которые имеют координаты x
/y
/width
/height
/top
/left
/right
/bottom
, поэтому вы просто создаете <div>
элементов из каждого, и все готово.
Рабочая реализация
Итак, вот рабочая реализация решения актуальной проблемы, представленной, используя мою библиотеку Region2D для выполнения тяжелого алгоритмического подъема:
// Generate regions for each of the objects.
var containerRegion = new Region2D($(".container")[0]);
var target1Region = new Region2D($(".target1")[0]);
var target2Region = new Region2D($(".target2")[0]);
// Subtract the targets from the container, and make an array of rectangles from it.
var coverRegion = containerRegion.subtract(target1Region).subtract(target2Region);
var coverRects = coverRegion.getRects();
// Create gray <div> elements for each rectangle.
for (var i = 0, l = coverRects.length; i < l; i++) {
var coverRect = coverRects[i];
var coverElement = $("<div class='cover'>");
coverElement.css({
left: (coverRect.x - 1) + "px", top: (coverRect.y - 1) + "px",
width: coverRect.width + "px", height: coverRect.height + "px"
});
coverElement.appendTo($(".container"));
}
.container, .target1, .target2, .cover { position: absolute; top: 0; left: 0; box-sizing: border-box; }
.target1, .target2 { border: 1px solid red; }
.container { width: 330px; height: 230px; border: 1px solid blue; }
.target1 { top: 40px; left: 40px; width: 100px; height: 80px; }
.target2 { top: 100px; left: 180px; width: 100px; height: 80px; }
.cover { background: rgba(0, 0, 0, 0.5); border: 1px solid #000; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://unpkg.com/[email protected]/plain/region2d.min.js"></script>
<div class="container">
<div class="target1"></div>
<div class="target2"></div>
</div>