Как сделать адаптивную координатную сетку
Часто вижу в ответах использование координатной сетки
Она используется, как фон для различных элементов. Но эта сетка нарисована видимо в растровом редакторе и сохранена в растровом формате.
На мой взгляд, для адаптивности, видимо нужно сделать координатную сетку в формате SVG.
Рисовать с помощью line, polline, path не вариант.
Попробовал сделать с помощью pattern, где каждая ячейка имеет размеры 10Х10px
<svg width="100%" height="100%" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="p10" width="10" height="10" patternUnits="userSpaceOnUse">
<path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" stroke-width="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#p10)" />
</svg>
Но как сделать, чтобы были ещё деления через каждые 100px?
Ответы (4 шт):
Но как сделать, чтобы были ещё деления через каждые 100px?
Можно использовать вложенные pattern.
Внешний pattern будет иметь размеры 100Х100px, внутренний паттерн 10X10px
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<defs>
<pattern id="p10" width="10" height="10" patternUnits="userSpaceOnUse">
<path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" stroke-width="0.5"/>
</pattern>
<pattern id="p100" width="100" height="100" patternUnits="userSpaceOnUse">
<rect width="100" height="100" fill="url(#p10)"/>
<path d="M 100 0 L 0 0 0 100" fill="none" stroke="gray" stroke-width="1"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#p100)" />
</svg>
Добавляем цифры с помощью
<text x="-20" y="100" >100</text>рамку, чтобы было видно границы холста SVG
style="border:solid">Добавим поверх сетки, SVG изображение, например ракету
Добавим небольшой скрипт, который позволит изменять ширину SVG
function changeHight() {
itr.addEventListener("input",()=>{svg.setAttribute("height",itr.value)});
var x = document.getElementById("itr").value;
document.getElementById("info").innerHTML = "SVG height: " + x +"px";
}
<style>
text {
font-size:20px;
fill:black;
}
p {font-weight:bold;}
</style>
<p id="info" ></p>
<div><input id="itr" type="range" min="10" max="1000" value="1000" oninput="changeHight()"/></div>
<svg id="svg" width="1000" height="1000" viewBox="-20 -20 1050 1050" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" style="border:3px solid purple">
<defs>
<pattern id="p10" width="10" height="10" patternUnits="userSpaceOnUse">
<path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" stroke-width="0.5"/>
</pattern>
<pattern id="p100" width="100" height="100" patternUnits="userSpaceOnUse">
<rect width="100" height="100" fill="url(#p10)"/>
<path d="M 100 0 L 0 0 0 100" fill="none" stroke="gray" stroke-width="1"/>
</pattern>
</defs>
<rect width="1000" height="1000" fill="url(#p100)" />
<circle cx="500" cy="500" r="5" fill="black" />
<!-- Вертикальный блок цифр -->
<text x="-15" y="0">0,0</text>
<text x="-20" y="100" >100</text>
<text x="-20" y="200">200</text>
<text x="-20" y="300">300</text>
<text x="-20" y="400">400</text>
<text x="-20" y="500">500</text>
<text x="-20" y="600">600</text>
<text x="-20" y="700">700</text>
<text x="-20" y="800">800</text>
<text x="-20" y="900">900</text>
<text x="-20" y="1000">1000</text>
<!-- Горизонтальный блок -->
<text x="100" y="-5" >100</text>
<text x="200" y="-5" >200</text>
<text x="300" y="-5">300</text>
<text x="400" y="-5">400</text>
<text x="500" y="-5">500</text>
<text x="600" y="-5">600</text>
<text x="700" y="-5">700</text>
<text x="800" y="-5">800</text>
<text x="900" y="-5">900</text>
<text x="990" y="-5">1000</text>
<!-- Ракета -->
<g transform="scale(1)" fill="purple">
<path d="m308.167 241.52c0-28.766-23.403-52.169-52.17-52.169s-52.17 23.403-52.17 52.169c0 28.767 23.403 52.17 52.17 52.17s52.17-23.404 52.17-52.17zm-52.169 22.169c-12.225 0-22.17-9.945-22.17-22.17 0-12.224 9.945-22.169 22.17-22.169s22.17 9.945 22.17 22.169c-.001 12.225-9.946 22.17-22.17 22.17z"/>
<path d="m425.684 424.352v-132.322l-51.65-32.948c.615-14.332.261-28.762-1.117-43.191-7.162-74.973-41.384-144.771-96.362-196.535l-20.557-19.356-20.558 19.356c-54.978 51.765-89.2 121.563-96.362 196.535-1.378 14.429-1.732 28.859-1.117 43.191l-51.65 32.948v132.321l90.003-28.282c3.744 6.784 7.752 13.436 12.017 19.945v62.315h30v-48.333h22.667v23.252h30v-23.252h22.667v48.333h30v-62.315c4.265-6.508 8.273-13.161 12.017-19.945zm-30-115.874v75.001l-46.66-14.662c10.468-24.35 17.778-49.975 21.762-76.222zm-139.694-267.28c27.301 25.706 48.392 55.971 63.081 88.684h-126.153c14.687-32.713 35.775-62.979 63.072-88.684zm-139.679 342.281v-75.001l24.898-15.883c3.983 26.247 11.293 51.872 21.762 76.222zm124.687-10.983v27.499h-27.316c-47.563-72.299-57.394-161.126-32.242-240.114h149.112c25.156 78.987 15.325 167.815-32.238 240.114h-27.316v-27.499z"/>
<path d="m240.998 483.495h30v28.5h-30z"/>
</g>
</svg>
Вариант с возможностью изменять width и height SVG
function changeHeight() {
itrX.addEventListener("input",()=>{svg.setAttribute("height",itrX.value)});
var x = document.getElementById("itrX").value;
document.getElementById("infoX").innerHTML = "SVG height: " + x +"px";
}
function changeWidth() {
itrY.addEventListener("input",()=>{svg.setAttribute("width",itrY.value)});
var x = document.getElementById("itrY").value;
document.getElementById("infoY").innerHTML = "SVG width: " + x +"px";
}
<style>
text {
font-size:20px;
fill:black;
}
p {
display:inline-block;
font-weight:bold;
margin: 1em ;
}
</style>
<p id="infoX" ></p>
<p id="infoY" ></p>
<div>
<span><input id="itrX" type="range" min="10" max="1000" value="1000" oninput="changeHeight()"/></span>
<span><input id="itrY" type="range" min="10" max="1000" value="1000" oninput="changeWidth()"/></span>
</div>
<svg id="svg" width="1000" height="1000" viewBox="-20 -20 1050 1050" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" style="border:2px solid purple">
<defs>
<pattern id="p10" width="10" height="10" patternUnits="userSpaceOnUse">
<path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" stroke-width="0.5"/>
</pattern>
<pattern id="p100" width="100" height="100" patternUnits="userSpaceOnUse">
<rect width="100" height="100" fill="url(#p10)"/>
<path d="M 100 0 L 0 0 0 100" fill="none" stroke="gray" stroke-width="1"/>
</pattern>
</defs>
<rect width="1000" height="1000" fill="url(#p100)" />
<circle cx="500" cy="500" r="5" fill="black" />
<!-- Вертикальный блок цифр -->
<text x="-15" y="0">0,0</text>
<text x="-20" y="100" >100</text>
<text x="-20" y="200">200</text>
<text x="-20" y="300">300</text>
<text x="-20" y="400">400</text>
<text x="-20" y="500">500</text>
<text x="-20" y="600">600</text>
<text x="-20" y="700">700</text>
<text x="-20" y="800">800</text>
<text x="-20" y="900">900</text>
<text x="-20" y="1000">1000</text>
<!-- Горизонтальный блок -->
<text x="100" y="-5" >100</text>
<text x="200" y="-5" >200</text>
<text x="300" y="-5">300</text>
<text x="400" y="-5">400</text>
<text x="500" y="-5">500</text>
<text x="600" y="-5">600</text>
<text x="700" y="-5">700</text>
<text x="800" y="-5">800</text>
<text x="900" y="-5">900</text>
<text x="990" y="-5">1000</text>
<!-- Ракета -->
<g transform="scale(1)" fill="purple">
<path d="m308.167 241.52c0-28.766-23.403-52.169-52.17-52.169s-52.17 23.403-52.17 52.169c0 28.767 23.403 52.17 52.17 52.17s52.17-23.404 52.17-52.17zm-52.169 22.169c-12.225 0-22.17-9.945-22.17-22.17 0-12.224 9.945-22.169 22.17-22.169s22.17 9.945 22.17 22.169c-.001 12.225-9.946 22.17-22.17 22.17z"/>
<path d="m425.684 424.352v-132.322l-51.65-32.948c.615-14.332.261-28.762-1.117-43.191-7.162-74.973-41.384-144.771-96.362-196.535l-20.557-19.356-20.558 19.356c-54.978 51.765-89.2 121.563-96.362 196.535-1.378 14.429-1.732 28.859-1.117 43.191l-51.65 32.948v132.321l90.003-28.282c3.744 6.784 7.752 13.436 12.017 19.945v62.315h30v-48.333h22.667v23.252h30v-23.252h22.667v48.333h30v-62.315c4.265-6.508 8.273-13.161 12.017-19.945zm-30-115.874v75.001l-46.66-14.662c10.468-24.35 17.778-49.975 21.762-76.222zm-139.694-267.28c27.301 25.706 48.392 55.971 63.081 88.684h-126.153c14.687-32.713 35.775-62.979 63.072-88.684zm-139.679 342.281v-75.001l24.898-15.883c3.983 26.247 11.293 51.872 21.762 76.222zm124.687-10.983v27.499h-27.316c-47.563-72.299-57.394-161.126-32.242-240.114h149.112c25.156 78.987 15.325 167.815-32.238 240.114h-27.316v-27.499z"/>
<path d="m240.998 483.495h30v28.5h-30z"/>
</g>
</svg>
Вариант на CSS
Использование абсолютных единиц измерения (px - в примере)
body {
--wM: 1px; /* Толщина линии */
--xM: 10px; /* Отступ по ширине */
--yM: 10px; /* Отступ по высоте */
--cM: #ccc; /* Цвет линии */
--wB: 1px; /* Толщина линии */
--xB: 100px; /* Отступ по ширине */
--yB: 100px; /* Отступ по высоте */
--cB: #333; /* Цвет линии */
background-position: -1px 0;
background-image:
linear-gradient(90deg, var(--cB) var(--wB), transparent var(--wB)),
linear-gradient(0deg, var(--cB) var(--wB), transparent var(--wB)),
linear-gradient(90deg, var(--cM) var(--wM), transparent var(--wM)),
linear-gradient(0deg, var(--cM) var(--wM), transparent var(--wM));
background-size:
var(--xB) 100%, 100% var(--yB),
var(--xM) 100%, 100% var(--yM);
}
#block {
width: 150px;
height: 150px;
border: 1px solid red;
box-sizing: border-box;
position: absolute;
left: 100px;
top: 50px;
}
<div id="block"></div> <!-- Для примера -->
Использование относительных единиц измерения (vw - в примере)
body {
--wM: 1px; /* Толщина линии */
--xM: calc(100vw / 60); /* Отступ по ширине */
--yM: calc(100vw / 60); /* Отступ по высоте */
--cM: #ccc; /* Цвет линии */
--wB: 1px; /* Толщина линии */
--xB: calc(100vw / 12); /* Отступ по ширине */
--yB: calc(100vw / 12); /* Отступ по высоте */
--cB: #333; /* Цвет линии */
background-image:
linear-gradient(90deg, var(--cB) var(--wB), transparent var(--wB)),
linear-gradient(0deg, var(--cB) var(--wB), transparent var(--wB)),
linear-gradient(90deg, var(--cM) var(--wM), transparent var(--wM)),
linear-gradient(0deg, var(--cM) var(--wM), transparent var(--wM));
background-size:
var(--xB) 100%, 100% var(--yB),
var(--xM) 100%, 100% var(--yM);
image-rendering: pixelated;
}
Конечно, проще всего это реализовать с помощью линейного градиента, как это уже реализовал @CbIPoK2513, и как ваш покорный слуга планировал это сделать, но опоздал с ответом. Значит, будет другой вариант - с помощью HTML, CSS и чуть-чуть JavaScript. Такую реализацию я называю - "Кричи караул!" Почему? Не скажу. Если кто понял почему, то можете написать в комментариях.
document.getElementById('div100').innerHTML = ("<div class='div100'><div class='div10'></div></div>").repeat(100);
var els = document.getElementsByClassName('div10'); for (var i in els) {els[i].innerHTML = ("<div></div>").repeat(100);}
* {box-sizing: border-box; margin: 0; padding: 0;}
#div100 {
display: grid; grid-template-columns: repeat(10, 1fr);
width: 100%; border-top: 1px solid gray; border-left: 1px solid gray;
}
.div100 {
display: grid; grid-template-columns: repeat(10, 1fr);
position: relative; width: 100%; padding-top: calc(100% - 1px); border-right: 1px solid gray; border-bottom: 1px solid gray;
}
.div10 {
display: grid; grid-template-columns: repeat(10, 1fr);
position: absolute; top: -100%; left: 0; width: 100%; padding-top: 100%;
}
.div10>div {width: 100%; padding-top: calc(100% - 1px); border-right: 1px solid lightgray; border-bottom: 1px solid lightgray;}
.div10>div:nth-child(10n+10) {border-right: none;}
.div10>div:nth-child(n+91) {border-bottom: none;}
<div id="div100"></div>
Следующим шагом добавим:
- цифры для разметки
- рамку, чтобы было видно границы холста
document.getElementById('div100').innerHTML = ("<div class='div100'><div class='div10'></div></div>").repeat(100);
var els = document.getElementsByClassName('div10'); for (var i in els) {els[i].innerHTML = ("<div></div>").repeat(100);}
* {box-sizing: border-box; margin: 0; padding: 0;}
.pixel {min-width: 1066px; margin: 10px; padding: 30px; border: 3px solid purple;}
#div100 {
display: grid; grid-template-columns: repeat(10, 1fr); position: relative;
width: 100%; border-top: 1px solid gray; border-left: 1px solid gray;
}
.div100 {
display: grid; grid-template-columns: repeat(10, 1fr);
position: relative; width: 100%; padding-top: calc(100% - 1px); border-right: 1px solid gray; border-bottom: 1px solid gray;
}
.div10 {
display: grid; grid-template-columns: repeat(10, 1fr);
position: absolute; top: -100%; left: 0; width: 100%; padding-top: 100%;
}
.div10>div {position: relative; width: 100%; padding-top: calc(100% - 1px); border-right: 1px solid lightgray; border-bottom: 1px solid lightgray;}
.div10>div:nth-child(10n+10) {border-right: none;}
.div10>div:nth-child(n+91) {border-bottom: none;}
#div100::after, .div100::before, .div100::after {position: absolute; font-size: 1rem; font-weight: bold; font-family: monospace;}
#div100::after {top: -1rem; left: -0.8rem; content: "0";}
.div100::before {top: -1.1rem; left: calc(100% - 0.2rem);}
.div100::after {bottom: -0.8rem; left: -1.6rem;}
.div100:nth-child(1)::before, .div100:nth-child(1)::after {content: "100";}
.div100:nth-child(2)::before, .div100:nth-child(11)::after {content: "200";}
.div100:nth-child(3)::before, .div100:nth-child(21)::after {content: "300";}
.div100:nth-child(4)::before, .div100:nth-child(31)::after {content: "400";}
.div100:nth-child(5)::before, .div100:nth-child(41)::after {content: "500";}
.div100:nth-child(6)::before, .div100:nth-child(51)::after {content: "600";}
.div100:nth-child(7)::before, .div100:nth-child(61)::after {content: "700";}
.div100:nth-child(8)::before, .div100:nth-child(71)::after {content: "800";}
.div100:nth-child(9)::before, .div100:nth-child(81)::after {content: "900";}
.div100:nth-child(10)::before, .div100:nth-child(91)::after {content: "1000";}
.div100:nth-child(91)::after {left: -1.85rem;}
#div100::before {content: ""; display: block; position: absolute; top: calc(50% - 7px); left: calc(50% - 7px); width: 12px; height: 12px; border-radius: 100%; background: black; z-index: 1;}
<div class="pixel"><div id="div100"></div></div>
P.S. Заинтересовавшись первым вариантом ответа участника @CbIPoK2513, где он создал координатную сетку с помощью технологии CSS, используя абсолютную единицу измерения - пиксель(px), мною был задан вопрос и приведен один из вариантов такого решения.
Для примера приведу - я обычно использую javascript для генерации сетки и рисую точно по ней...
Выглядит это так
let svg = document.querySelector("svg#svg"),
height = svg.getBoundingClientRect().height,
width = svg.getBoundingClientRect().width,
html = "";
for (let i = 0; i < 30; i++)
html += `<path class="vertical" d="M ${i * 10}, 0 ${i * 10} ${height}" />`;
for (let i = 0; i < 15; i++)
html += `<path class="gorizontal" d="M0,${i * 10} ${width} ${i * 10}" />`;
svg.innerHTML = html;
body {
margin: 0;
padding: 0;
}
svg#svg {
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
svg#svg path {
stroke: #000;
stroke-width: 0.2px;
}
#canvas {
width: 500px;
height: 250px;
position: relative;
z-ndex: 1;
}
<svg id="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 150"></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 150">
<path d="M20,10 30,100"
stroke="red"
stroke-width="1"
fill="none"/>
<circle cx="200" cy="70" r="50" fill="none" stroke="blue"/>
</svg>
Получается что я рисую новый SVG по верх сетки и что бы сетка не мешала самому рисунку я сетку распологаю абсолютно с отрицательным z-index
Вот к примеру я делал некий sin
let width = document.getElementById("svg").getBoundingClientRect().width;
let height = document.getElementById("svg").getBoundingClientRect().height;
let html = "";
for (let i = 0; i < width / 5; i++) {
html += `<path d="M ${i * 10}, 0 ${i * 10} ${height}" />`;
html += `<path class="gorizontal" d="M0,${i * 10} ${width} ${i * 10}" />`;
}
document.getElementById("svg").innerHTML = html
* {
margin: 0;
padding: 0;
}
#svg {
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
#svg path {
fill: none;
stroke: red;
stroke-width: 0.5px;
}
<svg id="svg" viewBox="0 0 300 150"></svg>
<svg viewBox="0 0 300 150">
<path d="M20,50
c0,0 25,25 50,0
c0,0 25,-25 50,0
c0,0 25,25 50,0
c0,0 25,-25 50,0"
fill="none"
stroke="blue"
stroke-width="1"/>
</svg>
Вот так будет выглядеть сетка 5x5
let width = document.getElementById("svg").getBoundingClientRect().width;
let height = document.getElementById("svg").getBoundingClientRect().height;
let conf = 5;
let html = "";
for (let i = 0; i < width; i++) {
html += `<path d="M ${i * conf}, 0 ${i * conf} ${height}" />`;
html += `<path d="M0,${i * conf} ${width} ${i * conf}" />`;
}
document.getElementById("svg").innerHTML = html;
