Подскажите программу для position:absolute верстки
Существуют ли какие-то программы, расширения в ide, конструкторы, sketch/ps/figma to html или лайфхаки для того, чтобы сверстать приведенную в пример конструкцию на posiiton:absolute блоках. Я хочу сделать интерактивную иллюстрацию из более 100 SVG/PNG запчастей и не хотелось бы вручную координаты прописывать (zeplin конечно да, но это все-таки только наполовину решает задачу)
Ответы (1 шт):
Нарисовал один квадратик, остальное пошло по инерции)) Откройте в полноэкранном*
При каждом клике z-index тупо увеличивается на 1, но перед копированием идет сортировка по индексу и z-index везде удаляется, т.к. блоки и так перекрывают один-другого, в зависимости от последовательности в HTML.
UPD: Добавлена возможность ввести массив картинок.
const id = (str) => document.getElementById(str);
addBlockOnClick();
setDragAndDrop();
setResize();
setColorFeatures();
setDeleteFeatures();
insertImageArray();
setCopyFeature();
/***/
function addBlockOnClick() {
id('add').addEventListener('click', function() {
let showDelBtns = id('delete-mode').dataset.showState || "";
let div = (
'<div class="item" style="background-color: RGB(0, 0, 0);">' +
'<div class="delete' + showDelBtns + '">X</div>' +
'<div class="resize"></div>' +
'</div>\n\n'
);
id('mama').insertAdjacentHTML('beforeEnd', div);
});
}
function setDragAndDrop() {
let zIndex = 0;
let drag = {
start: false,
elem: null,
mouseOffset: {
x: null,
y: null,
}
};
id('mama').addEventListener('mousedown', function(e) {
if (drag.elem) drag.elem.classList.remove('active');
if (!e.target.matches('.item')) return;
let rect = e.target.getBoundingClientRect();
drag.start = true;
drag.elem = e.target;
drag.mouseOffset = {
x: e.pageX - rect.left,
y: e.pageY - rect.top,
};
e.target.classList.add('active');
e.target.style.zIndex = zIndex++;
});
document.addEventListener('mouseup', function() {
drag.start = false;
});
document.addEventListener('mousemove', function(e) {
if (!drag.start) return;
let x = e.pageX - drag.mouseOffset.x;
let y = e.pageY - drag.mouseOffset.y;
drag.elem.style.left = x + 'px';
drag.elem.style.top = y + 'px';
});
}
function setResize() {
let resize = {
elem: null,
elemRect: {
x: null,
y: null,
}
};
id('mama').addEventListener('mousedown', function(e) {
if (!e.target.matches('.resize')) return;
let elem = e.target.parentNode;
let rect = elem.getBoundingClientRect();
resize.start = true;
resize.elem = elem;
resize.elemRect = {
x: rect.left,
y: rect.top,
};
elem.classList.add('active');
});
document.addEventListener('mouseup', function() {
resize.start = false;
resize.elem = null;
});
document.addEventListener('mousemove', function(e) {
if (!resize.start) return;
let width = e.pageX - resize.elemRect.x + 4;
let height = e.pageY - resize.elemRect.y + 4;
if (width * height < 100) return;
resize.elem.style.width = width + 'px';
resize.elem.style.height = height + 'px';
resize.elem.dataset.size = width + ' x ' + height;
});
}
function setColorFeatures() {
(function updateInputFromDiv() {
id('mama').addEventListener('click', function(e) {
let item = e.target.closest('.item');
if (!item) return;
let rgb = item.style.backgroundColor.match(/rgb\((\d+),\s?(\d+),\s?(\d+)\)/i);
updateUserInput(rgb);
/***/
function updateUserInput(rgb) {
rgb = rgb || ["full-match", 0, 0, 0];
let input = document.querySelectorAll('input[type="range"]');
input.forEach((el, i) => {
el.nextElementSibling.textContent = el.value = rgb[i+1];
});
}
});
})();
(function updateDivFromInput() {
document.querySelectorAll('input[type="range"]').forEach(function(inp) {
inp.addEventListener('input', function() {
let info = this.nextElementSibling;
let active = document.querySelector('.item.active');
if (!active) {
info.textContent = "Блок не выбран!";
return setTimeout(() => {
if (info.textContent === "Блок не выбран!") {
info.textContent = "";
}
}, 2000);
}
info.textContent = this.value;
active.style.backgroundColor = getInputRGB();
/***/
function getInputRGB() {
let input = document.querySelectorAll('input[type="range"]');
let rgb = [...input].map(e => e.value).join(", ");
return "RGB(" + rgb + ")";
}
});
});
})();
}
function setDeleteFeatures() {
id('delete-mode').addEventListener('click', function() {
document.querySelectorAll('#mama .delete').forEach(el => {
el.classList.toggle('show');
});
this.dataset.showState = this.dataset.showState === " show" ? "" : " show";
});
id('mama').addEventListener('click', function(e) {
if (e.target.matches('.delete')) {
e.target.parentNode.remove();
}
});
}
function setCopyFeature() {
id('copy').addEventListener('click', autoCopy);
function autoCopy() {
let div = document.createElement('div');
div.innerHTML = id('mama').innerHTML;
let active = div.querySelector('.item.active');
if( active ) active.classList.remove('active');
let items = div.querySelectorAll('.item');
items.forEach(item => item.innerHTML = "");
items = [...items].sort((a,b) => {
return parseInt(a.style.zIndex) - parseInt(b.style.zIndex);
}).map(item => {
return item.outerHTML.replace(/data-size=".*?"\s?|z-index:.*?(;\s?|(?="))/g, "");
});
copy.call(this, items.join("\n\n"));
/***/
function copy(str) {
let area = document.createElement('textarea');
document.body.appendChild(area);
area.value = str;
area.select();
document.execCommand('copy');
let save = this.textContent;
this.textContent = "Скопирован!";
setTimeout(_ => this.textContent = save, 2000);
area.remove();
}
}
}
function insertImageArray() {
id('images').addEventListener('click', function() {
let images = prompt("Введите адреса картинок через запятые или пробелы:");
if(!images) return;
let showDelBtns = id('delete-mode').dataset.showState || "";
images = images.split(/,\s?|\s/).map(img => {
return (
`<div class="item" style="background-image: url('` + img + `');">` +
'<div class="delete' + showDelBtns + '">X</div>' +
'<div class="resize"></div>' +
'</div>\n\n'
);
});
id('mama').insertAdjacentHTML('beforeEnd', images.join(""));
});
}
div {
background-size: 100% 100%;
/* Это важно для background-image, остальное ниже - декорация */
}
#mama {
width: 100%;
height: 85vh;
border: 1px solid red;
user-select: none;
}
.item {
position: absolute;
width: 50px;
height: 50px;
cursor: move;
overflow: hidden;
}
.item::after {
content: attr(data-size);
color: white;
}
.resize {
position: absolute;
bottom: -11px;
right: -11px;
transform: rotate(45deg);
width: 20px;
height: 20px;
background-color: #f70;
border: 1px solid black;
cursor: nw-resize;
}
.delete {
display: none;
position: absolute;
right: 0;
top: 0;
background-color: red;
color: white;
width: 16px;
height: 16px;
font-family: 'Verdana';
font-size: 14px;
line-height: 0;
text-align: center;
padding-top: 8px;
box-sizing: border-box;
cursor: pointer;
}
.delete.show {
display: block;
}
.active {
box-shadow: 0 0 0 2px #f70, 2px 2px 5px #000;
}
<button id="add">+ Блок</button>
<button id="images">>> Массив картинок</button>
<button id="delete-mode">Режим Удаления</button>
<div style="display: inline-block; vertical-align: top;">
R <input type="range" min="0" max="255" value="0"><span></span><br>
G <input type="range" min="0" max="255" value="0"><span></span><br>
B <input type="range" min="0" max="255" value="0"><span></span>
</div>
<button id="copy">Скопирвать код</button>
<div id="mama"></div>
