Как вставить прямоугольник SVG в html холст? Это сложно объяснить, но понять легче, поэтому я оставлю фрагмент для просмотра.
Я использую библиотеку tree-maker .
Я хотел поместить эту систему внутри холста, чтобы иметь возможность управлять масштабированием и возможностью перетаскивания.
По порядку:
- древовидная диаграмма. js ,
- древовидная система. js,
- древовидный стиль. css,
- index. html
//The structure of your tree
let tree = {
1: {
2: {
3: '',
4: '',
},
},
};
//The parameters of your tree
let treeParams = {
1: {trad: 'Card 1'},
2: {trad: 'Card 2'},
3: {trad: 'Card 3'},
4: {trad: 'Card 4'},
};
//The function which will build the tree
treeMaker(tree, {
id: 'tree', card_click: function (element) {
console.log(element);
},
treeParams: treeParams,
'link_width': '4px',
'link_color': '#10375c',
});
let pathNumber = 1;
let allLinks = [];
let treeParamas;
//scg path params
let strokeWidth = '5px';
let strokeColor = '#000000';
function treeMaker(tree, params) {
let container = document.getElementById(params.id);
treeParamas = params.treeParams === undefined ? {} : params.treeParams;
if (params.link_width !== undefined) strokeWidth = params.link_width;
if (params.link_color !== undefined) strokeColor = params.link_color;
//svg part
let svgDiv = document.createElement('div');
svgDiv.id = 'tree__svg-container';
container.appendChild(svgDiv);
let svgContainer = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svgContainer.id = 'tree__svg-container__svg';
svgDiv.appendChild(svgContainer);
//html part
let treeContainer = document.createElement('div');
treeContainer.id = 'tree__container';
container.appendChild(treeContainer);
let card = document.createElement('div');
card.classList = 'tree__container__step__card';
card.id = 'tree__container__step__card__first';
treeContainer.appendChild(card);
let trad = treeParamas[Object.keys(tree)[0]] !== undefined && treeParamas[Object.keys(tree)[0]].trad !== undefined ? treeParamas[Object.keys(tree)[0]].trad : Object.keys(tree)[0].trad;
card.innerHTML = '<p class="tree__container__step__card__p" id="card_' + Object.keys(tree)[0] + '">' + trad + '</p>';
addStyleToCard(treeParamas[Object.keys(tree)[0]], Object.keys(tree)[0]);
iterate(tree[Object.keys(tree)[0]], true, 'tree__container__step__card__first');
connectCard();
let allCards = document.querySelectorAll('.tree__container__step__card__p');
for (let i = 0; allCards.length > i; i++) {
allCards[i].addEventListener('click', function (event) {
params.card_click(event.target);
})
}
window.onresize = function () {
svgDiv.setAttribute('height', '0');
svgDiv.setAttribute('width', '0');
connectCard();
};
}
function connectCard() {
//magic
let svg = document.getElementById('tree__svg-container__svg');
for (let i = 0; allLinks.length > i; i++) {
connectElements(svg, document.getElementById(allLinks[i][0]), document.getElementById(allLinks[i][1]), document.getElementById(allLinks[i][2]));
}
}
function iterate(tree, start = false, from = '') {
let svgContainer = document.getElementById('tree__svg-container__svg');
let treeContainer = document.createElement('div');
treeContainer.id = 'from_' + from;
treeContainer.classList.add('tree__container__branch');
document.getElementById(from).after(treeContainer);
for (const key in tree) {
let textCard = treeParamas[key] !== undefined && treeParamas[key].trad !== undefined ? treeParamas[key].trad : key;
treeContainer.innerHTML += '<div class="tree__container__step"><div class="tree__container__step__card" id="' + key + '"><p id="card_' + key + '" class="tree__container__step__card__p">' + textCard + '</p></div></div>';
addStyleToCard(treeParamas[key], key);
if ('' !== from && !start) {
let newpath = document.createElementNS("http://www.w3.org/2000/svg", "path");
newpath.id = "path" + pathNumber;
newpath.setAttribute('stroke', strokeColor);
newpath.setAttribute('fill', 'none');
newpath.setAttribute('stroke-width', strokeWidth);
svgContainer.appendChild(newpath);
allLinks.push(['path' + pathNumber, from, key]);
pathNumber++;
}
if (start) {
// svgContainer.innerHTML = svgContainer.innerHTML + '<path id="path' + pathNumber + '" d="M0 0" stroke="#2199e8" fill="none" stroke-width="5";/>';
let newpath = document.createElementNS("http://www.w3.org/2000/svg", "path");
newpath.id = "path" + pathNumber;
newpath.setAttribute('stroke', strokeColor);
newpath.setAttribute('fill', 'none');
newpath.setAttribute('stroke-width', strokeWidth);
svgContainer.appendChild(newpath);
allLinks.push(['path' + pathNumber, 'tree__container__step__card__first', key]);
pathNumber++;
}
if (Object.keys(tree[key]).length > 0) {
iterate(tree[key], false, key);
}
}
}
function addStyleToCard(card, key) {
if (card !== undefined && card.styles !== undefined) {
let lastCard = document.getElementById('card_' + key);
for (const cssRules in treeParamas[key].styles) {
lastCard.style[cssRules] = card.styles[cssRules];
}
}
}
function signum(x) {
return (x < 0)
? -1
: 1;
}
function absolute(x) {
return (x < 0)
? -x
: x;
}
function drawPath(svg, path, startX, startY, endX, endY) {
// get the path's stroke width (if one wanted to be really precize, one could use half the stroke size)
let stroke = parseFloat(path.getAttribute("stroke-width"));
// check if the svg is big enough to draw the path, if not, set height/width
if (svg.getAttribute("height") < endY) svg.setAttribute("height", endY);
if (svg.getAttribute("width") < (startX + stroke)) svg.setAttribute("width", (startX + stroke));
if (svg.getAttribute("width") < (endX + stroke)) svg.setAttribute("width", (endX + stroke));
let deltaX = (endX - startX) * 0.15;
let deltaY = (endY - startY) * 0.15;
// for further calculations which ever is the shortest distance
let delta = deltaY < absolute(deltaX)
? deltaY
: absolute(deltaX);
// set sweep-flag (counter/clock-wise)
// if start element is closer to the left edge,
// draw the first arc counter-clockwise, and the second one clock-wise
let arc1 = 0;
let arc2 = 1;
if (startX > endX) {
arc1 = 1;
arc2 = 0;
}
// draw tha pipe-like path
// 1. move a bit down, 2. arch, 3. move a bit to the right, 4.arch, 5. move down to the end
path.setAttribute("d", "M" + startX + " " + startY + " V" + (startY + delta) + " A" + delta + " " + delta + " 0 0 " + arc1 + " " + (startX + delta * signum(deltaX)) + " " + (startY + 2 * delta) + " H" + (endX - delta * signum(deltaX)) + " A" + delta + " " + delta + " 0 0 " + arc2 + " " + endX + " " + (startY + 3 * delta) + " V" + endY);
}
function connectElements(svg, path, startElem, endElem) {
let svgContainer = document.getElementById('tree__svg-container');
// if first element is lower than the second, swap!
if (startElem.offsetTop > endElem.offsetTop) {
let temp = startElem;
startElem = endElem;
endElem = temp;
}
// get (top, left) corner coordinates of the svg container
let svgTop = svgContainer.offsetTop;
let svgLeft = svgContainer.offsetLeft;
// calculate path's start (x,y) coords
// we want the x coordinate to visually result in the element's mid point
let startX = startElem.offsetLeft + 0.5 * startElem.offsetWidth - svgLeft; // x = left offset + 0.5*width - svg's left offset
let startY = startElem.offsetTop + startElem.offsetHeight - svgTop; // y = top offset + height - svg's top offset
// calculate path's end (x,y) coords
let endX = endElem.offsetLeft + 0.5 * endElem.offsetWidth - svgLeft;
let endY = endElem.offsetTop - svgTop;
// call function for drawing the path
drawPath(svg, path, startX, startY, endX, endY);
}
.tree__container, #from_tree__container__step__card__first, .tree__container__branch {
display: flex;
flex-direction: row;
justify-content: center;
}
.tree__container__step__card {
text-align: center;
margin: 20px;
}
.tree__container__step__card p {
padding: 10px;
box-shadow: 0 0 4px 1px rgba(121, 121, 121, 0.3);
border-radius: 4px;
text-align: center;
width: 150px;
display: inline-block;
margin: 0 !important;
font-family: sans-serif;
font-weight: bold;
color: #faf4ff;
}
#tree__svg-container {
z-index: -1;
position: absolute;
}
.tree__container__step {
flex: 1 1 0px;
width: auto;
padding: 0;
}
.tree__container__step__card__p {
cursor: pointer;
transition: transform .2s ease;
background-color: rgba(77, 76, 125, 1);;
}
.tree__container__step__card__p:hover {
transform: translateX(3px);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="tree-style.css">
<script type="text/javascript" src="tree-system.js"></script>
</head>
<body>
<div id="tree"></div>
</body>
<script type="text/javascript" src="tree-chart.js"></script>
</html>