Skip to content

Commit 37cc400

Browse files
committed
add linked-blocks
1 parent 9dffdee commit 37cc400

File tree

8 files changed

+261
-40
lines changed

8 files changed

+261
-40
lines changed

examples/linked-block.html

Lines changed: 208 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,44 +19,230 @@
1919
</nav>
2020

2121
<main class="h-100 pos-relative pattern-grid-dot">
22-
<div data-role="linked-block, draggable" id="block1">
22+
<div data-role="linked-block, draggable" id="block1" data-on-drag-move="dragBlock1" data-on-drag-stop="dragBlock1">
2323
<div class="north-side"></div>
2424
<div class="east-side">
25-
<div class="link-point"></div>
25+
<div class="link-point" id="block1_a"></div>
26+
</div>
27+
<div class="south-side">
28+
<div class="link-point" id="block1_b"></div>
2629
</div>
27-
<div class="south-side"></div>
2830
<div class="west-side"></div>
2931
</div>
3032

31-
<div data-role="linked-block, draggable" id="block2">
33+
<div data-role="linked-block, draggable" id="block2" data-on-drag-move="dragBlock2" data-on-drag-stop="dragBlock2">
3234
<div class="north-side"></div>
3335
<div class="east-side"></div>
3436
<div class="south-side"></div>
3537
<div class="west-side">
36-
<div class="link-point"></div>
38+
<div class="link-point" id="block2_a"></div>
39+
</div>
40+
</div>
41+
42+
<div data-role="linked-block, draggable" id="block3" data-on-drag-move="dragBlock3" data-on-drag-stop="dragBlock3">
43+
<div class="north-side">
44+
<div class="link-point" id="block3_a"></div>
3745
</div>
46+
<div class="east-side"></div>
47+
<div class="south-side"></div>
48+
<div class="west-side"></div>
3849
</div>
50+
51+
<!-- <svg class="connection-line" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none;">-->
52+
<!-- <line id="connector" stroke="var(&#45;&#45;linked-block-border-color)" stroke-width="1"/>-->
53+
<!-- </svg>-->
54+
55+
<svg id="line-block1-block2" class="connection-line">
56+
<path class="cl-curve" stroke="var(--linked-block-border-color)" stroke-width="2" fill="none"/>
57+
</svg>
58+
59+
<svg id="line-block1-block3" class="connection-line">
60+
<path class="cl-curve" stroke="var(--linked-block-border-color)" stroke-width="2" fill="none"/>
61+
</svg>
3962
</main>
4063

4164
<script src="../lib/metro.js"></script>
4265
<script>
43-
(() => {
44-
setTimeout(() => {
45-
const block1 = $("#block1")
46-
const block2 = $("#block2")
47-
const parent = $("main")
48-
49-
block1.css({
50-
top: parent.height() / 2 - block1.height() / 2,
51-
left: parent.width() / 2 - block1.width() / 2 - 200,
52-
})
53-
54-
block2.css({
55-
top: parent.height() / 2 - block2.height() / 2,
56-
left: parent.width() / 2 - block2.width() / 2 + 200,
57-
})
58-
}, 100)
59-
})()
66+
// line
67+
// function updateConnection () {
68+
// const point1 = $('#block1_a')
69+
// const point2 = $('#block2_a')
70+
// const line = $('#connector')
71+
// const svg = $('.connection-line')
72+
//
73+
// // Отримуємо позиції точок відносно документа
74+
// const rect1 = point1.offset()
75+
// const rect2 = point2.offset()
76+
//
77+
// // Отримуємо позицію SVG контейнера відносно документа
78+
// const svgRect = svg.offset()
79+
//
80+
// // Отримуємо розміри точок для центрування
81+
// const point1Width = point1.outerWidth()
82+
// const point1Height = point1.outerHeight()
83+
// const point2Width = point2.outerWidth()
84+
// const point2Height = point2.outerHeight()
85+
//
86+
// // Розраховуємо координати відносно SVG контейнера і центруємо точки
87+
// const x1 = rect1.left - svgRect.left + point1Width / 2
88+
// const y1 = rect1.top - svgRect.top + point1Height / 2
89+
// const x2 = rect2.left - svgRect.left + point2Width / 2
90+
// const y2 = rect2.top - svgRect.top + point2Height / 2
91+
//
92+
// line.attr({
93+
// x1: x1,
94+
// y1: y1,
95+
// x2: x2,
96+
// y2: y2
97+
// })
98+
// }
99+
100+
// curve z
101+
// function updateConnection () {
102+
// const point1 = $('#block1_a')
103+
// const point2 = $('#block2_a')
104+
// const path = $('#connector')
105+
// const svg = $('.connection-line')
106+
//
107+
// const rect1 = point1.offset()
108+
// const rect2 = point2.offset()
109+
// const svgRect = svg.offset()
110+
//
111+
// const point1Width = point1.outerWidth()
112+
// const point1Height = point1.outerHeight()
113+
// const point2Width = point2.outerWidth()
114+
// const point2Height = point2.outerHeight()
115+
//
116+
// const x1 = rect1.left - svgRect.left + point1Width / 2
117+
// const y1 = rect1.top - svgRect.top + point1Height / 2
118+
// const x2 = rect2.left - svgRect.left + point2Width / 2
119+
// const y2 = rect2.top - svgRect.top + point2Height / 2
120+
//
121+
// let pathData = ''
122+
//
123+
// const tolerance = 5 // допуск для визначення "однакової" висоти
124+
// const horizontalDistance = Math.abs(x2 - x1)
125+
// const cornerRadius = Math.min(20, horizontalDistance / 6) // радіус заокруглення кутів
126+
//
127+
// if (Math.abs(y1 - y2) <= tolerance) {
128+
// // 1. Якщо y1 === y2 - пряма лінія
129+
// pathData = `M ${x1} ${y1} L ${x2} ${y2}`
130+
// } else {
131+
// // Точки для створення сходинки
132+
// const midX = x1 + horizontalDistance / 2
133+
//
134+
// if (y1 < y2) {
135+
// // 2. y1 < y2 - починається прямо, потім вниз, потім прямо
136+
// pathData = `M ${x1} ${y1}
137+
// L ${midX - cornerRadius} ${y1}
138+
// Q ${midX} ${y1} ${midX} ${y1 + cornerRadius}
139+
// L ${midX} ${y2 - cornerRadius}
140+
// Q ${midX} ${y2} ${midX + cornerRadius} ${y2}
141+
// L ${x2} ${y2}`
142+
// } else {
143+
// // 3. y1 > y2 - починається прямо, потім вверх, потім прямо
144+
// pathData = `M ${x1} ${y1}
145+
// L ${midX - cornerRadius} ${y1}
146+
// Q ${midX} ${y1} ${midX} ${y1 - cornerRadius}
147+
// L ${midX} ${y2 + cornerRadius}
148+
// Q ${midX} ${y2} ${midX + cornerRadius} ${y2}
149+
// L ${x2} ${y2}`
150+
// }
151+
// }
152+
//
153+
// path.attr('d', pathData)
154+
// }
155+
156+
// curve
157+
function updateConnection (a, b, c) {
158+
const point1 = $(a)
159+
const point2 = $(b)
160+
const parent1 = point1.parent()
161+
const parent2 = point2.parent()
162+
const svg = $(c)
163+
const path = svg.find('.cl-curve')
164+
let direction = 'horizontal'
165+
166+
if (parent1.hasClass('east-side') && parent2.hasClass('west-side')) {
167+
direction = 'horizontal'
168+
} else if (parent1.hasClass('south-side') && parent2.hasClass('north-side')) {
169+
direction = 'vertical'
170+
}
171+
172+
const rect1 = point1.offset()
173+
const rect2 = point2.offset()
174+
const svgRect = svg.offset()
175+
176+
const point1Width = point1.outerWidth()
177+
const point1Height = point1.outerHeight()
178+
const point2Width = point2.outerWidth()
179+
const point2Height = point2.outerHeight()
180+
181+
const x1 = rect1.left - svgRect.left + point1Width / 2
182+
const y1 = rect1.top - svgRect.top + point1Height / 2
183+
const x2 = rect2.left - svgRect.left + point2Width / 2
184+
const y2 = rect2.top - svgRect.top + point2Height / 2
185+
186+
// Створюємо плавну криву для горизонтального та вертикального з'єднання
187+
const dx = x2 - x1
188+
const dy = y2 - y1
189+
190+
let cp1x, cp1y, cp2x, cp2y
191+
192+
// Визначаємо, чи з'єднання більш горизонтальне або вертикальне
193+
if (direction === 'horizontal') {
194+
// Горизонтальне з'єднання - контрольні точки по X
195+
const controlDistance = Math.abs(dx) * 0.4
196+
cp1x = x1 + (dx > 0 ? controlDistance : -controlDistance)
197+
cp1y = y1
198+
cp2x = x2 - (dx > 0 ? controlDistance : -controlDistance)
199+
cp2y = y2
200+
} else {
201+
// Вертикальне з'єднання - контрольні точки по Y
202+
const controlDistance = Math.abs(dy) * 0.4
203+
cp1x = x1
204+
cp1y = y1 + (dy > 0 ? controlDistance : -controlDistance)
205+
cp2x = x2
206+
cp2y = y2 - (dy > 0 ? controlDistance : -controlDistance)
207+
}
208+
209+
// Створюємо кубічну криву Безьє
210+
const pathData = `M ${x1} ${y1} C ${cp1x} ${cp1y} ${cp2x} ${cp2y} ${x2} ${y2}`
211+
212+
path.attr('d', pathData)
213+
}
214+
215+
function dragBlock1(){
216+
updateConnection("#block1_a", "#block2_a", "#line-block1-block2")
217+
updateConnection("#block1_b", "#block3_a", "#line-block1-block3")
218+
}
219+
220+
function dragBlock2(){
221+
updateConnection("#block1_a", "#block2_a", "#line-block1-block2")
222+
}
223+
224+
function dragBlock3(){
225+
updateConnection("#block1_b", "#block3_a", "#line-block1-block3")
226+
}
227+
228+
setTimeout(() => {
229+
const block1 = $('#block1')
230+
const block2 = $('#block2')
231+
const parent = $('main')
232+
233+
block1.css({
234+
top: parent.height() / 2 - block1.height() / 2,
235+
left: parent.width() / 2 - block1.width() / 2 - 200,
236+
})
237+
238+
block2.css({
239+
top: parent.height() / 2 - block2.height() / 2,
240+
left: parent.width() / 2 - block2.width() / 2 + 200,
241+
})
242+
243+
updateConnection("#block1_a", "#block2_a", "#line-block1-block2")
244+
updateConnection("#block1_b", "#block3_a", "#line-block1-block3")
245+
}, 100)
60246
</script>
61247
</body>
62248
</html>

lib/icons.css

Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/metro.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66475,6 +66475,14 @@ label:has(input) {
6647566475
background-color: var(--linked-block-border-color);
6647666476
flex: 0 0 var(--linked-block-point-size);
6647766477
}
66478+
.connection-line {
66479+
position: absolute;
66480+
top: 0;
66481+
left: 0;
66482+
width: 100%;
66483+
height: 100%;
66484+
pointer-events: none;
66485+
}
6647866486

6647966487
/* source/components/list/list.less */
6648066488

lib/metro.css.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/metro.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝
99

1010
* Metro UI v5.1.16 Components Library (https://metroui.org.ua)
11-
* Build: 13.08.2025, 18:18:40
11+
* Build: 14.08.2025, 21:50:22
1212
* Copyright 2012-2025 by Serhii Pimenov
1313
* Licensed under MIT
1414
*/
@@ -11308,7 +11308,7 @@
1130811308
(($7) => {
1130911309
"use strict";
1131011310
globalThis["__version__"] = "5.1.16";
11311-
globalThis["__build_time__"] = "13.08.2025, 18:18:40";
11311+
globalThis["__build_time__"] = "14.08.2025, 21:50:22";
1131211312
const meta_init = $7.meta("metro:init").attr("content");
1131311313
const meta_cloak = $7.meta("metro:cloak").attr("content");
1131411314
const meta_cloak_duration = $7.meta("metro:cloak_duration").attr("content");
@@ -11657,7 +11657,7 @@
1165711657
const normalizeComponentName2 = (name2) => typeof name2 !== "string" ? void 0 : name2.replace(/-/g, "").toLowerCase();
1165811658
const Metro2 = {
1165911659
version: "5.1.16",
11660-
build_time: "13.08.2025, 18:18:40",
11660+
build_time: "14.08.2025, 21:50:22",
1166111661
buildNumber: 0,
1166211662
isTouchable: isTouch3,
1166311663
fullScreenEnabled: document.fullscreenEnabled,
@@ -44539,6 +44539,7 @@
4453944539
minHeight: 0,
4454044540
maxWidth: 0,
4454144541
maxHeight: 0,
44542+
zIndex: null,
4454244543
onDragStart: Metro2.noop,
4454344544
onDragStop: Metro2.noop,
4454444545
onDragMove: Metro2.noop,
@@ -44726,6 +44727,9 @@
4472644727
let width = o2.width;
4472744728
let height = o2.height;
4472844729
win = $7("<div>").addClass("window");
44730+
if (o2.zIndex !== null) {
44731+
win.css("z-index", o2.zIndex);
44732+
}
4472944733
if (o2.modal === true) {
4473044734
win.addClass("modal");
4473144735
}
@@ -45091,6 +45095,14 @@
4509145095
});
4509245096
return this;
4509345097
},
45098+
zIndex: function(v5) {
45099+
if (Metro2.utils.isNull(v5) === false) {
45100+
this.win.css({
45101+
zIndex: +v5
45102+
});
45103+
}
45104+
return this.win.style("zIndex");
45105+
},
4509445106
changeAttribute: function(attr, value) {
4509545107
const changePos = function(a2, v5) {
4509645108
const win = this.win;

lib/metro.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

source/components/linked-block/linked-block.less

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
color: var(--linked-block-color);
2323
border: 1px solid var(--linked-block-border-color);
2424
border-radius: var(--linked-block-border-radius);
25-
25+
2626
.north-side, .east-side, .south-side, .west-side {
2727
position: absolute;
2828
display: flex;
@@ -31,35 +31,35 @@
3131
overflow: visible;
3232
gap: 2px;
3333
}
34-
34+
3535
.north-side, .south-side {
3636
width: 100%;
3737
height: 1px;
3838
flex-flow: row nowrap;
3939
}
40-
40+
4141
.east-side, .west-side {
4242
width: 1px;
4343
height: 100%;
4444
flex-flow: column nowrap;
4545
}
46-
46+
4747
.north-side {
4848
top: -1px;
4949
}
50-
50+
5151
.east-side {
5252
right: -1px;
5353
}
54-
54+
5555
.south-side {
5656
bottom: -1px;
5757
}
58-
58+
5959
.west-side {
6060
left: -1px;
6161
}
62-
62+
6363
.link-point {
6464
display: block;
6565
position: relative;
@@ -69,4 +69,13 @@
6969
background-color: var(--linked-block-border-color);
7070
flex: 0 0 var(--linked-block-point-size);
7171
}
72+
}
73+
74+
.connection-line {
75+
position: absolute;
76+
top: 0;
77+
left: 0;
78+
width: 100%;
79+
height: 100%;
80+
pointer-events: none;
7281
}

temp/img.png

74.8 KB
Loading

0 commit comments

Comments
 (0)