Создание повторяющегося шаблона из 9-ти кругов. Один круг в центре, и по четыре круга в каждой вершине и по середине сторон

У меня есть задача, когда я пытаюсь создать 9 кругов в каждом прямоугольнике (4 в каждом углу, 4 по бокам и 1 в центре), одновременно после создания прямоугольника. В моем решении создается 4 круга вне прямоугольника, что нежелательно!

Каждый прямоугольник должен содержать 9 кругов (4 в каждом углу, 4 по бокам и 1 посередине) одновременно с тем, когда прямоугольник будет создан.

Я использовал библиотеку snap.svg для создания кругов и прямоугольников.

Вы можете использовать следующий фрагмент кода:

const svgId = 'campus_map';
const width = document.getElementById(svgId).viewBox.baseVal.width;
const height = document.getElementById(svgId).viewBox.baseVal.height;
let draw = Snap("#tiles");
let c = 0;
let size = Math.round(0.05 * width);
let circleSize = 25;
let circleColor = ["#ff0000", "#000000", "#00ffe1", "#0051ff"];
let svg = document.getElementById(svgId);
for (let i = 0; i <= width; i = i + size) {
    for (let j = 0; j <= height; j = j + size) {
        c += 1;
        let rect = draw.rect(i, j, size, size);
        let circle1 = draw.circle(i, j, circleSize);
        let circle2 = draw.circle(i + (size / 2), j, circleSize);
        let circle3 = draw.circle(i, j + (size / 2), circleSize);
        let circle4 = draw.circle(i + (size / 2), j + (size / 2), circleSize);

        rect.attr({
            fill: "#d00bf3",
            "fill-opacity": 0.2,
            stroke: "#000",
            "stroke-width": "1px",
            id: "rect_" + c,
            name: "rect" + c
        });
        circle1.attr({
            fill: circleColor[0],
            "fill-opacity": 1,
            stroke: "#000",
            "stroke-width": "1px",
            id: "circle1_" + c,
            name: "circle1_" + c
        });
        circle2.attr({
            fill: circleColor[1],
            "fill-opacity": 1,
            stroke: "#000",
            "stroke-width": "1px",
            id: "circle2_" + c,
            name: "circle2_" + c
        });
        circle3.attr({
            fill: circleColor[2],
            "fill-opacity": 1,
            stroke: "#000",
            "stroke-width": "1px",
            id: "circle3_" + c,
            name: "circle3_" + c
        });
        circle4.attr({
            fill: circleColor[3],
            "fill-opacity": 1,
            stroke: "#000",
            "stroke-width": "1px",
            id: "circle4_" + c,
            name: "circle4_" + c
        });
    }
}
<script src="https://unpkg.com/[email protected]"></script>

<svg viewBox="0 0 8204.08 6413.17" version="1.1" id="campus_map"
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"
    xmlns:svg="http://www.w3.org/2000/svg">

    <g id="tiles"></g>
</svg>

Свободный перевод вопроса Creating 9 circles in each rectangle (4 in each corner, 4 on the sides and 1 in the middle) at the same time/after immediately creating a rectangle от участника @Arif Ahmed.


Ответы (2 шт):

Автор решения: Alexandr_TT

В вашем цикле вы создаете только четыре круга на плитку. Если вы добавите еще пять, ваш код будет работать. Что вам мешает?

Похоже, вы хотите, чтобы круги были внутри квадрата. Для этого вам нужно переместить круги на один радиус круга.

Вот модифицированный код, в котором я вычисляю это смещение и использую цикл для позиционирования девяти кругов:

const svgId = 'campus_map';
const width = document.getElementById(svgId).viewBox.baseVal.width;
const height = document.getElementById(svgId).viewBox.baseVal.height;
let draw = Snap("#tiles");
let c = 0;
let size = Math.round(0.05 * width);
let circleSize = 25;
let circleColor = ["#ff0000", "#000000", "#00ffe1", "#0051ff"];
let svg = document.getElementById(svgId);
for (let i = 0; i <= width; i = i + size) {
    for (let j = 0; j <= height; j = j + size) {
        c += 1;
        let rect = draw.rect(i, j, size, size);
        rect.attr({
            fill: "#d00bf3",
            "fill-opacity": 0.2,
            stroke: "#000",
            "stroke-width": "1px",
            id: "rect_" + c,
            name: "rect" + c
        });
        
        // Теперь сделайте еще один цикл, чтобы создать девять кругов
        // Похоже, вы хотите, чтобы круги был ВНУТРИ прямоугольника
        // поэтому вам нужно отодвинуть от углов прямоугольника на
         // радиус.
        
        // Расстояние между кругами равно размеру квадрата - два радиуса.
        // затем разделить пополам
        let circleSpacing = (size - circleSize * 2) / 2;
        // Верхний левый круг - это один радиус внутри верхнего левого квадратного угла.
        let circleStartX = i + circleSize;
        let circleStartY = j + circleSize;
        for (let i2 = 0; i2 < 3; i2++) {
            for (let j2 = 0; j2 < 3; j2++) {
                c += 1;
                let circle = draw.circle(circleStartX + i2 * circleSpacing, circleStartY + j2 * circleSpacing, circleSize);
                circle.attr({
                    fill: circleColor[0],
                    "fill-opacity": 1,
                    stroke: "#000",
                    "stroke-width": "1px",
                    id: "circle1_" + c,
                    name: "circle1_" + c
                });
            }
        }
    }
}
<script src="https://unpkg.com/[email protected]"></script>

<svg viewBox="0 0 8204.08 6413.17" version="1.1" id="campus_map"
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"
    xmlns:svg="http://www.w3.org/2000/svg">

    <g id="tiles"></g>
</svg>

Свободный перевод ответа от участника @Paul LeBeau.

→ Ссылка
Автор решения: Alexandr_TT

Обдумайте возможность использования svg pattern

Это самый лёгкий путь решения вашей задачи
В любой момент вы сможете легко менять его наполнение, количество и формы элементов.

Также вы сможете заполнять контейнеры любой формы и сделать их адаптивными.

Читайте комментарии в коде, чтобы лучше понять, как позиционируются круги в одной плитке паттерна. Подробнее о принципах создания и примеры паттернов - здесь

<svg width="100%" height="100%" version="1.1"  viewBox="0 0 800 800" 
      xmlns="http://www.w3.org/2000/svg" >
       <defs>
      <pattern id="myPattern"
             x="0" y="0" width="40" height="40"
             patternUnits="userSpaceOnUse" >
                 <rect x="0" y="0" width="40" height="40" fill="#F6CEFD" stroke-width="0.5" stroke="black" />
             <g stroke="none"  > 
                   <!-- Центральный круг -->
               <circle cx="20" cy="20" r="3" fill="#0051FF"/>
                        <!-- Верх середина -->
                <circle cx="20" cy="0.5" r="3" fill="#000"/>
                        <!-- Низ середина -->
                <circle cx="20" cy="40" r="3" fill="#000"/>
                        <!-- слева середина -->
                <circle cx="0" cy="20" r="3" fill="#00FFE1"/> 
                        <!-- справа середина -->
                <circle cx="40" cy="20" r="3" fill="#00FFE1"/>  
                         <!-- левый верхний угол -->
                <circle cx="0" cy="0" r="3" fill="#FF0000"/>
                         <!-- левый нижний  угол -->
                <circle cx="0" cy="40" r="3" fill="#FF0000"/>
                         <!-- правый верхний  угол -->
                <circle cx="40" cy="0" r="3" fill="#FF0000"/>
                         <!-- правый нижний  угол -->
                <circle cx="40" cy="40" r="3" fill="#FF0000"/>
             </g>
         </pattern>
              
  </defs>  
               <!-- Заполнение прямоугольника паттерном -->
      <rect x="0" y="0" width="100%" height="100%"
         style="stroke: #000000; fill: url(#myPattern);" /> 
 </svg>

Пример наполнения силуэта, например Новогодней ёлочки:

<svg width="100%" height="100%" version="1.1"  viewBox="0 0 800 800" 
      xmlns="http://www.w3.org/2000/svg" >
       <defs>
      <pattern id="myPattern"
             x="0" y="0" width="40" height="40"
             patternUnits="userSpaceOnUse" >
                 <rect x="0" y="0" width="40" height="40" fill="green" stroke-width="0.5" stroke="black" />
             <g stroke="none"  > 
                   <!-- Центральный круг -->
               <circle cx="20" cy="20" r="3" fill="#0051FF"/>
                        <!-- Верх середина -->
                <circle cx="20" cy="0.5" r="3" fill="yellow"/>
                        <!-- Низ середина -->
                <circle cx="20" cy="40" r="3" fill="yellow"/>
                        <!-- слева середина -->
                <circle cx="0" cy="20" r="3" fill="#00FFE1"/> 
                        <!-- справа середина -->
                <circle cx="40" cy="20" r="3" fill="#00FFE1"/>  
                         <!-- левый верхний угол -->
                <circle cx="0" cy="0" r="3" fill="#FF0000"/>
                         <!-- левый нижний  угол -->
                <circle cx="0" cy="40" r="3" fill="#FF0000"/>
                         <!-- правый верхний  угол -->
                <circle cx="40" cy="0" r="3" fill="#FF0000"/>
                         <!-- правый нижний  угол -->
                <circle cx="40" cy="40" r="3" fill="#FF0000"/>
             </g>
         </pattern>
              
  </defs>  
               <!-- Заполнение паттерном силуэта ёлочки -->
      <path  d="m119 262 28 0 0 86-28-2z" fill="brown" />
  <path id="tree" fill="url(#myPattern)" d="M261 327 169 244c16 9 103 34 76 15-25-18-81-74-81-74 8 5 94 45 71 27-24-19-78-88-78-88 7 5 42 11 42 11-24-13-47-73-47-73 11 8 21 7 21 7C149 51 133 0 133 0c0 0-15 51-39 69 0 0 9 1 21-7 0 0-23 60-47 73 0 0 35-7 42-12 0 0-38 58-78 89-20 15 61-23 69-28 0 0-25 38-75 85-14 14 63-13 72-25 0 0-70 64-88 86-6 7 123-56 123-56 0 0 133 70 129 52z" id="path4" fill="#008000"/>
</svg>
 </svg>

введите сюда описание изображения

→ Ссылка