我可以在編輯器視窗中看到“投影”我的文本,但無法將其顯示在圖表或餅形楔形區域中。任何幫助將不勝感激。我需要標簽文本向右對齊或顯示在頂部。我將其他影像堆疊在圖表的頂部,所以我嘗試使用 z-index 來完成它。這是我的代碼。
/* SHOW LABEL ON HOVER */
jQuery(".group_path").hover(
function() {
jQuery(this).find(".text_toggle").css("display", "block");
},
function() {
jQuery(this).find(".text_toggle").css("display", "none");
}
);
/* Trying to get text to show as labels - also Jquery code in script file */
.text_toggle {
display: none;
fill: transparent;
}
.group_path:hover .text_toggle {
display: block;
font-size: 1em;
text-align: right;
z-index: 5;
}
<!-- Jquery 3.6 -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj 3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<!-- Body -->
<svg viewBox='-1 -1 2 2' style='transform: scale(1.0); rotate(-90deg)'>
<g id="4" >
<g id="4.01" class="group_path" fill='rgb(84,161,229)' >
<path stroke='white' stroke-width='.0125px' d='M 1.000000 0.000000 A 1 1 0 0 1 0.873262 0.487250 L 0 0 '></path>
<text class="text_toggle" d='M 1.000000 0.000000 A 1 1 0 0 1 0.873262 0.487250 L 0 0 ' ><tspan >Project</tspan></text>
</g>
<g id="4.02" class="group_path" fill='rgb(242,162,84)'>
<path stroke='white' stroke-width='.0125px' d='M 0.873262 0.487250 A 1 1 0 0 1 -0.147119 0.989119 L 0 0 '></path>
</g>
<g id="4.03" class="group_path" fill='rgb(237,110,133)' >
<path stroke='white' stroke-width='.0125px' d='M -0.147119 0.989119 A 1 1 0 0 1 -0.689114 0.724653 L 0 0 '></path>
</g>
<g id="4.04" class="group_path" fill='rgb(173,205,225)' >
<path stroke='white' stroke-width='.0125px' d='M -0.689114 0.724653 A 1 1 0 0 1 -0.915241 0.402907 L 0 0 '></path>
</g>
<g id="4.05" class="group_path" fill='rgb(187,221,147)' >
<path stroke='white' stroke-width='.0125px' d='M -0.915241 0.402907 A 1 1 0 0 1 -0.946085 0.323917 L 0 0 '></path>
</g>
<g id="4.06" class="group_path" fill='rgb(238,158,155)' >
<path stroke='white' stroke-width='.0125px' d='M -0.946085 0.323917 A 1 1 0 0 1 -0.978581 -0.205863 L 0 0 '></path>
</g>
<g id="4.07" class="group_path" fill='rgb(84,161,229)' >
<path stroke='white' stroke-width='.0125px' d='M -0.978581 -0.205863 A 1 1 0 0 1 -0.879316 -0.476238 L 0 0 '></path>
</g>
<g id="4.08" class="group_path" fill='rgb(108,190,191)'>
<path stroke='white' stroke-width='.0125px' d='M -0.879316 -0.476238 A 1 1 0 0 1 -0.527846 -0.849340 L 0 0 '></path>
</g>
<g id="4.09" class="group_path" fill='rgb(242,162,84)' >
<path stroke='white' stroke-width='.0125px' d='M -0.527846 -0.849340 A 1 1 0 0 1 0.056518 -0.998402 L 0 0 '></path>
</g>
<g id="4.10" class="group_path" fill='rgb(237,110,133)'>
<path stroke='white' stroke-width='.0125px' d='M 0.056518 -0.998402 A 1 1 0 0 1 0.543760 -0.839241 L 0 0 '></path>
</g>
<g id="4.11" class="group_path" fill='rgb(173,205,225)'>
<path stroke='white' stroke-width='.0125px' d='M 0.543760 -0.839241 A 1 1 0 0 1 0.711535 -0.702650 L 0 0 '></path>
</g>
<g id="4.12" class="group_path" fill='rgb(187,221,147)'>
<path stroke='white' stroke-width='.0125px' d='M 0.711535 -0.702650 A 1 1 0 0 1 0.724653 -0.689114 L 0 0 '></path>
</g>
<g id="4.13" class="group_path" fill='rgb(42,228,229)'>
<path stroke='white' stroke-width='.00625px' d='M 0.724653 -0.689114 A 1 1 0 0 1 1.000000 -0.000000 L 0 0 '></path>
</g>
<circle fill='#fff' cx='0' cy='0' r='0.80'/>
</g>
</svg>
如果可以避免的話,我不想使用 jquery
uj5u.com熱心網友回復:
你面臨幾個問題:
- 文本元素不能使用任何 d 屬性(為路徑元素保留)
- css 屬性z-index 不會對 svg 元素產生任何影響——您需要在餅圖段的頂部添加標簽
- 你需要為你的標簽
<text>元素獲取 x/y 坐標 - js 來拯救! - id 不理想(以數字開頭,包含句點)——這些元素在 css 或 js 中是不可選擇的(除非你將它們轉義)
- (最好通過 z 命令關閉段的路徑)
如何獲得正確的文本錨坐標

對于正確對齊的文本標簽,我們需要獲取每個段的半弧的 x/y 坐標。
(用紅色圓圈表示)
主要概念是檢查餅圖楔形與“中心線”圓相交的位置:我們需要添加這個半徑在外半徑=1 和內半徑=0.8 之間的輔助圓元素 - 所以我們的中心線圓需要半徑為0.9。
示例 1:預處理(查找文本標簽的 x/y)
顯示代碼片段
let pie = document.querySelector("svg");
let segments = pie.querySelectorAll(".group_path");
let labelGroupHtml = "";
let textanchors = "";
// auxiliary circle element to get label coordinates
let circleIntersect = document.querySelector(".circleIntersect");
let circleLength = circleIntersect.getTotalLength();
// define precision for intersection checking
let steps = circleLength / 180;
let circlePoints = [];
for (let i = 0; i < circleLength; i = steps) {
let point = circleIntersect.getPointAtLength(i);
circlePoints.push(point);
}
// find intersections beween each piechart slices and auxiliary circle
function getIntersect(path) {
let intersects = [];
let middlePoint = 0;
for (let i = 0; i < circlePoints.length; i ) {
let point = circlePoints[i];
let isIntersect = path.isPointInFill(point);
if (isIntersect) {
intersects.push({
x: point.x.toFixed(2),
y: point.y.toFixed(2)
});
}
}
if (intersects.length) {
// get segment's middle coordinates
let midIndex = Math.ceil((intersects.length - 1) / 2);
middlePoint = intersects[midIndex];
}
return middlePoint;
}
segments.forEach(function(el, i) {
let segementId = "label_" i;
let path = el.querySelector("path");
let labelText = path.getAttribute("data-label");
// add generic labels if not defined
labelText = labelText ? labelText : "Segment" (i 1);
path.setAttribute("data-target", segementId);
let intersect = getIntersect(path);
if (intersect) {
let midX = intersect["x"];
let midY = intersect["y"];
textanchors =
'<circle fill="red" cx="'
midX
'" '
'cy="'
midY
'" r="0.02" />';
let label =
'<text dy="2%" id="'
segementId
'" x="'
midX
'" y="'
midY
'" transform="rotate(90 '
midX
" "
midY
')" ><tspan >'
labelText
"</tspan></text>";
labelGroupHtml = label;
}
});
pie.insertAdjacentHTML(
"beforeend",
'<g >' labelGroupHtml "</g>"
);
// just for illustrating the retrieved text anchors
pie
.querySelector(".preprocessing")
.insertAdjacentHTML(
"beforeend",
'<g >' textanchors "</g>"
);
// event listeners
let pieSegemts = pie.querySelectorAll("path");
if (pieSegemts.length) {
pieSegemts.forEach(function(segment, i) {
segment.addEventListener("click", function(e) {
/**
* uncomment the closelabels call and
* mouseleave event listener if you need only one segemnt to be active
*/
/*
closeLabels();
*/
let labelSelector = e.currentTarget.getAttribute("data-target");
let label = pie.querySelector("#" labelSelector);
label.classList.toggle("label_active");
segment.classList.toggle("segment_active");
});
/*
segment.addEventListener("mouseleave", function (e) {
closeLabels();
});
*/
});
}
// hide other labels
function closeLabels() {
let opened = pie.querySelectorAll(".label_active, .segment_active");
opened.forEach(function(el, i) {
el.classList.remove("label_active");
el.classList.remove("segment_active");
});
}
// ungroup elements – inherit properties
ungroup(".group_path");
function ungroup(selector) {
let groups = document.querySelectorAll(selector);
groups.forEach(function(group, i) {
let attributes = [...group.attributes];
let children = [...group.children];
children.forEach(function(el, i) {
attributes.forEach(function(att, i) {
el.setAttribute(att["name"], att["nodeValue"]);
el.classList.add("segment");
});
group.parentNode.insertBefore(el, group.nextElementSibling);
group.remove();
});
});
}
// replace ids containing numbers
cleanNumIds();
function cleanNumIds() {
let idEls = document.querySelectorAll("[id]");
idEls.forEach(function(el, i) {
let id = el.id;
let idNum = ( id).toString();
if (idNum === id) {
el.setAttribute("data-id", id);
el.id = "seg_" id.replaceAll(".", "-");
}
});
}
body {
font-family: "Sogoe UI", "Open Sans", Arial;
}
svg {
display: inline-block;
width: 20em;
overflow: visible;
border: 1px solid #ccc;
}
.segment {
stroke: #fff;
stroke-width: 0.0125;
}
.segment_active {
opacity: 0.5;
}
.text_label {
font-size: 0.1px;
fill: #000;
text-anchor: start;
visibility: hidden;
}
.text_label,
.notSelectable {
user-select: none;
pointer-events: none;
}
.label_active {
visibility: visible;
}
<!-- Body -->
<svg viewBox='-1 -1 2 2' style='transform:rotate(-90deg)'>
<g id="4">
<g id="4.01" class="group_path" fill='rgb(84,161,229)'>
<path d='M 1.000000 0.000000 A 1 1 0 0 1 0.873262 0.487250 L 0 0z' data-label="Project"></path>
</g>
<g id="4.02" class="group_path" fill='rgb(242,162,84)'>
<path d='M 0.873262 0.487250 A 1 1 0 0 1 -0.147119 0.989119 L 0 0z' data-label="Segment 2"></path>
</g>
<g id="4.03" class="group_path" fill='rgb(237,110,133)'>
<path d='M -0.147119 0.989119 A 1 1 0 0 1 -0.689114 0.724653 L 0 0z'></path>
</g>
<g id="4.04" class="group_path" fill='rgb(173,205,225)'>
<path d='M -0.689114 0.724653 A 1 1 0 0 1 -0.915241 0.402907 L 0 0z'></path>
</g>
<g id="4.05" class="group_path" fill='rgb(187,221,147)'>
<path d='M -0.915241 0.402907 A 1 1 0 0 1 -0.946085 0.323917 L 0 0z'></path>
</g>
<g id="4.06" class="group_path" fill='rgb(238,158,155)'>
<path d='M -0.946085 0.323917 A 1 1 0 0 1 -0.978581 -0.205863 L 0 0z'></path>
</g>
<g id="4.07" class="group_path" fill='rgb(84,161,229)'>
<path d='M -0.978581 -0.205863 A 1 1 0 0 1 -0.879316 -0.476238 L 0 0z'></path>
</g>
<g id="4.08" class="group_path" fill='rgb(108,190,191)'>
<path d='M -0.879316 -0.476238 A 1 1 0 0 1 -0.527846 -0.849340 L 0 0z'></path>
</g>
<g id="4.09" class="group_path" fill='rgb(242,162,84)'>
<path d='M -0.527846 -0.849340 A 1 1 0 0 1 0.056518 -0.998402 L 0 0z'></path>
</g>
<g id="4.10" class="group_path" fill='rgb(237,110,133)'>
<path d='M 0.056518 -0.998402 A 1 1 0 0 1 0.543760 -0.839241 L 0 0z'></path>
</g>
<g id="4.11" class="group_path" fill='rgb(173,205,225)'>
<path d='M 0.543760 -0.839241 A 1 1 0 0 1 0.711535 -0.702650 L 0 0z'></path>
</g>
<g id="4.12" class="group_path" fill='rgb(187,221,147)'>
<path d='M 0.711535 -0.702650 A 1 1 0 0 1 0.724653 -0.689114 L 0 0z'></path>
</g>
<g id="4.13" class="group_path" fill='rgb(42,228,229)'>
<path d='M 0.724653 -0.689114 A 1 1 0 0 1 1.000000 -0.000000 L 0 0z'></path>
</g>
<circle fill='#fff' cx='0' cy='0' r='0.80' />
</g>
<!-- pseudo donut hole -->
<circle fill="#fff" cx='0' cy='0' r='0.80' />
<!-- circle for text x/y analyzing -->
<g class="preprocessing">
<circle class="circleIntersect notSelectable" stroke-width="0.01" stroke='red' fill="none" stroke-width="0.1" cx='0' cy='0' r='0.9' />
</g>
</svg>
它是如何作業的:
我們需要沿著上述中心線圓“旅行”并檢查線段何時相交:
首先我們需要得到這個圓的路徑長度
- 通過
getTotalLength()(好吧,我們也可以使用 pathLength 屬性......) - 然后我們將圓周分割成段,得到路徑長度位置的陣列
getPointAtLength()。在此示例中,180 個分割/分割可在為分割標簽找到理想文本 x/y 時提供足夠的精度(使用 100 個分割,我們可能不會得到非常薄的餅形楔形)。 - 然后,我們可以檢查每個路徑(餅圖段)是否有與中心線圓相交的點
path.isPointInFill(point),并將它們保存到包含 x/y 坐標的 DOMPoints 陣列中(讓相交) - 我們得到多個相交點——我們感興趣的是中間點 (
let midIndex = Math.ceil((intersects.length - 1) / 2)) - 現在我們可以
<text>使用正確的 x/y 坐標將元素附加到餅圖 svg(標簽文本是從資料屬性中檢索的)
... 相當多的js?
餅圖的 svg 優化和轉換后,您可以將其保存為靜態資產(例如,通過在開發工具中檢查它)并洗掉預處理功能,如下所示:
顯示代碼片段
let pie = document.querySelector("svg");
let segments = pie.querySelectorAll(".group_path");
// event listeners
// event listeners
let pieSegemts = pie.querySelectorAll("path");
if (pieSegemts.length) {
pieSegemts.forEach(function (segment, i) {
segment.addEventListener("mouseenter", function (e) {
/**
* uncomment the closelabels call and
* mouseleave event listener if you need only one segemnt to be active
*/
closeLabels();
let labelSelector = e.currentTarget.getAttribute("data-target");
let label = pie.querySelector("#" labelSelector);
label.classList.toggle("label_active");
segment.classList.toggle("segment_active");
});
segment.addEventListener("mouseleave", function (e) {
closeLabels();
});
});
}
function closeLabels() {
let opened = pie.querySelectorAll(".label_active, .segment_active");
opened.forEach(function (el, i) {
el.classList.remove("segment_active");
el.classList.remove("label_active");
});
}
body {
font-family: "Sogoe UI", "Open Sans", Arial;
}
svg {
display: inline-block;
width: 20em;
overflow: visible;
border: 1px solid #ccc;
}
.segment {
stroke: #fff;
stroke-width: 0.0125;
}
.segment_active {
opacity: 0.5;
}
.text_label {
font-size: 0.1px;
fill: #000;
text-anchor: start;
visibility: hidden;
}
.text_label,
.notSelectable {
user-select: none;
pointer-events: none;
}
.label_active {
visibility: visible;
}
<svg viewBox="-1 -1 2 2" style="transform:rotate(-90deg)">
<g id="seg_4" data-id="4">
<path d="M 1.000000 0.000000 A 1 1 0 0 1 0.873262 0.487250 L 0 0z" data-label="Project" data-target="label_0" id="seg_4-01" class="group_path segment" fill="rgb(84,161,229)" data-id="4.01"></path>
<path d="M 0.873262 0.487250 A 1 1 0 0 1 -0.147119 0.989119 L 0 0z" data-label="Segment 2" data-target="label_1" id="seg_4-02" class="group_path segment" fill="rgb(242,162,84)" data-id="4.02"></path>
<path d="M -0.147119 0.989119 A 1 1 0 0 1 -0.689114 0.724653 L 0 0z" data-target="label_2" id="seg_4-03" class="group_path segment" fill="rgb(237,110,133)" data-id="4.03"></path>
<path d="M -0.689114 0.724653 A 1 1 0 0 1 -0.915241 0.402907 L 0 0z" data-target="label_3" id="seg_4-04" class="group_path segment" fill="rgb(173,205,225)" data-id="4.04"></path>
<path d="M -0.915241 0.402907 A 1 1 0 0 1 -0.946085 0.323917 L 0 0z" data-target="label_4" id="seg_4-05" class="group_path segment" fill="rgb(187,221,147)" data-id="4.05"></path>
<path d="M -0.946085 0.323917 A 1 1 0 0 1 -0.978581 -0.205863 L 0 0z" data-target="label_5" id="seg_4-06" class="group_path segment" fill="rgb(238,158,155)" data-id="4.06"></path>
<path d="M -0.978581 -0.205863 A 1 1 0 0 1 -0.879316 -0.476238 L 0 0z" data-target="label_6" id="seg_4-07" class="group_path segment" fill="rgb(84,161,229)" data-id="4.07"></path>
<path d="M -0.879316 -0.476238 A 1 1 0 0 1 -0.527846 -0.849340 L 0 0z" data-target="label_7" id="seg_4-08" class="group_path segment" fill="rgb(108,190,191)" data-id="4.08"></path>
<path d="M -0.527846 -0.849340 A 1 1 0 0 1 0.056518 -0.998402 L 0 0z" data-target="label_8" id="seg_4-09" class="group_path segment" fill="rgb(242,162,84)" data-id="4.09"></path>
<path d="M 0.056518 -0.998402 A 1 1 0 0 1 0.543760 -0.839241 L 0 0z" data-target="label_9" id="4.10" class="group_path segment" fill="rgb(237,110,133)"></path>
<path d="M 0.543760 -0.839241 A 1 1 0 0 1 0.711535 -0.702650 L 0 0z" data-target="label_10" id="seg_4-11" class="group_path segment" fill="rgb(173,205,225)" data-id="4.11"></path>
<path d="M 0.711535 -0.702650 A 1 1 0 0 1 0.724653 -0.689114 L 0 0z" data-target="label_11" id="seg_4-12" class="group_path segment" fill="rgb(187,221,147)" data-id="4.12"></path>
<path d="M 0.724653 -0.689114 A 1 1 0 0 1 1.000000 -0.000000 L 0 0z" data-target="label_12" id="seg_4-13" class="group_path segment" fill="rgb(42,228,229)" data-id="4.13"></path>
<circle fill="#fff" cx="0" cy="0" r="0.80"></circle>
</g>
<!-- pseudo donut hole -->
<circle fill="#fff" cx="0" cy="0" r="0.80"></circle>
<g class="labels"><text dy="2%" id="label_0" x="0.87" y="0.23" transform="rotate(90 0.87 0.23)" class="text_label">
<tspan>Project</tspan>
</text><text dy="2%" id="label_1" x="0.38" y="0.81" transform="rotate(90 0.38 0.81)" class="text_label">
<tspan>Segment 2</tspan>
</text><text dy="2%" id="label_2" x="-0.38" y="0.81" transform="rotate(90 -0.38 0.81)" class="text_label">
<tspan>Segment3</tspan>
</text><text dy="2%" id="label_3" x="-0.73" y="0.52" transform="rotate(90 -0.73 0.52)" class="text_label">
<tspan>Segment4</tspan>
</text><text dy="2%" id="label_4" x="-0.84" y="0.32" transform="rotate(90 -0.84 0.32)" class="text_label">
<tspan>Segment5</tspan>
</text><text dy="2%" id="label_5" x="-0.9" y="0.03" transform="rotate(90 -0.9 0.03)" class="text_label">
<tspan>Segment6</tspan>
</text><text dy="2%" id="label_6" x="-0.84" y="-0.32" transform="rotate(90 -0.84 -0.32)" class="text_label">
<tspan>Segment7</tspan>
</text><text dy="2%" id="label_7" x="-0.65" y="-0.62" transform="rotate(90 -0.65 -0.62)" class="text_label">
<tspan>Segment8</tspan>
</text><text dy="2%" id="label_8" x="-0.2" y="-0.88" transform="rotate(90 -0.2 -0.88)" class="text_label">
<tspan>Segment9</tspan>
</text><text dy="2%" id="label_9" x="0.26" y="-0.86" transform="rotate(90 0.26 -0.86)" class="text_label">
<tspan>Segment10</tspan>
</text><text dy="2%" id="label_10" x="0.58" y="-0.69" transform="rotate(90 0.58 -0.69)" class="text_label">
<tspan>Segment11</tspan>
</text><text dy="2%" id="label_11" x="0.65" y="-0.62" transform="rotate(90 0.65 -0.62)" class="text_label">
<tspan>Segment12</tspan>
</text><text dy="2%" id="label_12" x="0.84" y="-0.32" transform="rotate(90 0.84 -0.32)" class="text_label">
<tspan>Segment13</tspan>
</text></g>
</svg>
剩下的唯一 js 函式負責事件系結(單擊、滑鼠懸停等)和切換。
編輯:查找標簽坐標
您還應該查看 Paul LeBeau 更優雅的方法(純 svg 餅圖,文本對齊中心)
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/432809.html
