我在一个.Net Core应用程序中使用HighCharts。我有一个散点图,我使用抖动来分离点。我需要显示指向点标记的数据标签,但它们重叠了。下面是我的代码:
@using Highsoft.Web.Mvc.Charts;
@using Highsoft.Web.Mvc.Charts.Rendering;
<script src="~/lib/highcharts/js/v10/highcharts.js"></script>
<script src="~/lib/highcharts/js/v10/highcharts-more.js"></script>
<script src="~/lib/highcharts/js/v10/annotations.js"></script>
<link rel="stylesheet" type="text/css" href="~/lib/highcharts/highcharts.css" />
<script type="text/javascript">
$(function () {
$('#container1').highcharts({
chart: {
type: 'scatter',
zoomType: 'xy',
width: 1500,
height: 1000,
events: {
load: function () {
StaggerDataLabels(this.series);
},
redraw: function () {
var series = this.series;
setTimeout(function () {
StaggerDataLabels(series);
}, 1000);
}
},
},
credits: {
enabled: false
},
legend: {
enabled: false
},
title: {
text: 'Impact vs Life Cycle Root Cause',
style: {
fontSize: '24px',
color: 'black'
},
},
xAxis: {
gridLineWidth: 1,
title: {
text: 'Impact',
style: {
fontSize: '20px',
color: 'black'
},
},
tickInterval: 1,
min: 0,
max: 6,
showFirstLabel: false,
showLastLabel: false,
labels: {
formatter: function () {
return bcxAxislabelFormatter(this.value);
},
}
},
yAxis: {
title: {
text: 'Life Cycle Root Cause',
style: {
fontSize: '20px',
color: 'black'
},
},
tickInterval: 1,
min: 0,
max: 6,
showFirstLabel: false,
showLastLabel: false,
labels: {
formatter: function () {
return bcyAxislabelFormatter(this.value);
},
rotation: -45,
}
},
tooltip: {
formatter: formatB1ToolTip,
},
plotOptions: {
series: {
dataLabels: {
allowOverlap: true,
shape: 'connector',
enabled: true,
formatter: function () {
return (this.point.label);
}
}
},
scatter: {
jitter: {
x: 0.24,
y: 0.24
},
marker: {
radius: 5,
states: {
hover: {
enabled: true,
lineColor: 'rgb(100,100,100)'
}
}
},
states: {
hover: {
marker: {
enabled: false
}
}
},
tooltip: {
pointFormat: '{point.x} , {point.y} '
}
}
},
series: [{
data:@Html.Raw(Newtonsoft.Json.JsonConvert.DeserializeObject(ViewData["scatter1"].ToString()))
}]
});
});
function handleClick(e) {
var url = '@Url.Action("GetIssueData", "Chart")' + "?X=" + e.point.x + "&Y=" + e.point.y;
$.get(url).done(function (data) {
$('#DisplayDetailedContent').find('#modal-content2').html(data);
});
$(this).attr('data-target', '#modal-container2');
$(this).attr('data-toggle', 'modal');
$('#DisplayDetailedContent').find('#modal-container2').modal('show');
}
function formatB1ToolTip() {
var ptx = bcxAxislabelFormatter(this.point.x);
var pty = bcyAxislabelFormatter(this.point.y);
return '<b>' + ptx + '/' + pty + '</b><br/>Total Issues: ' + this.point.z ;
}
function bcxAxislabelFormatter(x) {
var label = "";
if (x == '1') {
label = "Minimal";
} else if (x == '2') {
label = "Minor";
} else if (x == '3') {
label = "Moderate";
} else if (x == '4') {
label = "Significant";
} else {
label = "Critical";
}
return label;
}
function bcyAxislabelFormatter(x) {
var label = "";
if (x == '1') {
label = "Test & Ops";
} else if (x == '2') {
label = "Manufacturing";
} else if (x == '3') {
label = "Process & Review";
} else if (x == '4') {
label = "Design & Process";
} else {
label = "Requirements";
}
return label;
}
function StaggerDataLabels(series) {
sc = series[0].points.length;
for (x = 1; x < 6; x++) {
for (y = 1; y < 6; y++) {
for (z = 1; z < 6; z++) {
var arr = [];
for (s = 1; s < sc; s++) {
if (series[0].points[s - 1].dataLabels[0].element.point.x == x && series[0].points[s - 1].dataLabels[0].element.point.y == y) {
arr.push(series[0].points[s - 1]);
}
}
var ac = arr.length;
if (ac > 1) {
for (s = 1; s < ac; s++) {
var s1 = arr[s - 1],
s2 = arr[s],
diffx,
diff, h;
if (s1.dataLabel && s2.dataLabel) {
diff = s1.dataLabel.y - s2.dataLabel.y;
h = s1.dataLabel.height + 1;
if (isLabelOnLabel(s1.dataLabel, s2.dataLabel)) {
if (diff < 0) s1.dataLabel.translate(s1.dataLabel.translateX, s1.dataLabel.translateY - (h + diff));
else s2.dataLabel.translate(s2.dataLabel.translateX, s2.dataLabel.translateY - (h - diff));
}
}
}
}
}
}
}
}
//compares two datalabels and returns true if they overlap
function isLabelOnLabel(a, b) {
var al = a.x - (a.width / 2);
var ar = a.x + (a.width / 2);
var bl = b.x - (b.width / 2);
var br = b.x + (b.width / 2);
var at = a.y;
var ab = a.y + a.height;
var bt = b.y;
var bb = b.y + b.height;
if (bl > ar || br < al) {
return false;
} //overlap not possible
if (bt > ab || bb < at) {
return false;
} //overlap not possible
if (bl > al && bl < ar) {
return true;
}
if (br > al && br < ar) {
return true;
}
if (bt > at && bt < ab) {
return true;
}
if (bb > at && bb < ab) {
return true;
}
return false;
}
</script>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
.table1 .highcharts-background {
stroke: black;
stroke-width: 2px;
}
.table1 .highcharts-plot-border {
stroke-width: 1px;
stroke: gray;
}
.table1 .highcharts-plot-background {
fill: url(#MyGradient)
}
.table1 .highcharts-axis-title {
font-size: 14px;
}
</style>
<defs>
<linearGradient id="MyGradient" x1="0%" y1="100%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#02f512" />
<stop offset="30%" stop-color="#F2E95D" />
<stop offset="70%" stop-color="#F2E95D" />
<stop offset="100%" stop-color="#f50202" />
</linearGradient>
</defs>
</svg>
@{
ViewData["Title"] = "Privacy Policy";
}
<div id="DisplayDataContent">
<div id="DisplayDetailedContent">
<div id="modal-container2" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div id="modal-content2" class="modal-content">
</div>
</div>
</div>
</div>
</div>
<div>
<table class="table1" style="margin:auto">
<tr>
<td>
Container
<!--Bubble Chart-->
<div id="container"></div>
</td>
</tr>
<tr>
<td>
container 1
<!--Bubble Chart-->
<div id="container1"></div>
</td>
</tr>
</table>
</div>
@section Scripts {
}
<script>
$(function () {
$('body').on('click', '.close_issues', function (e) {
e.preventDefault();
$('#DisplayDetailedContent').find('#modal-container2').modal('hide');
})
});
</script>
以下是我的数据集:
[
{"x":1,"y":2,"label":"Second Issue Title","id":null},
{"x":1,"y":2,"label":"Test Not Admin","id":null},
{"x":1,"y":2,"label":"Commit Quarter Test","id":null},
{"x":1,"y":2,"label":"this is a test 1","id":null},
{"x":1,"y":2,"label":"Security Marking Test 2","id":null},
{"x":1,"y":3,"label":"Create Commit Quarter History 3","id":null},
{"x":1,"y":3,"label":"Test of TinyMCE","id":null},
{"x":1,"y":4,"label":"TPPI Test","id":null},
{"x":2,"y":2,"label":"Test LMPI #2","id":null},
{"x":2,"y":2,"label":"Test TinyMCE Changes","id":null},
{"x":2,"y":2,"label":"Test Affected programs #1","id":null},
{"x":2,"y":2,"label":"Test Edge","id":null},
{"x":2,"y":3,"label":"Testing IssueID Loading","id":null},
{"x":2,"y":3,"label":"Third Test of Issue ID Creation","id":null},
{"x":2,"y":3,"label":"This is the title of the 1st issue which is a little longer than normal","id":null},
{"x":2,"y":3,"label":"This is a test","id":null},
{"x":2,"y":3,"label":"DELETED","id":null},
{"x":2,"y":3,"label":"Test","id":null},
{"x":2,"y":4,"label":"Yet another issue yup","id":null},
{"x":2,"y":4,"label":"Testing of Create an Issue page","id":null},
{"x":3,"y":1,"label":"Second test of IssueID Creation","id":null},
{"x":3,"y":2,"label":"New Issue on 10/19","id":null},
{"x":3,"y":3,"label":"this is a test ","id":null},
{"x":3,"y":3,"label":"Testing New IssueID Creation","id":null},
{"x":3,"y":3,"label":"Testing Root Cause Issues","id":null},
{"x":3,"y":4,"label":"DELETED","id":null},
{"x":3,"y":4,"label":"DELETED","id":null},
{"x":3,"y":4,"label":"test","id":null},
{"x":3,"y":5,"label":"DELETED","id":null},
{"x":3,"y":5,"label":"Security Marking Test 3","id":null},
{"x":4,"y":1,"label":"Testing of Issue ID4","id":null},
{"x":4,"y":2,"label":"Create Commit Quarter History 2","id":null},
{"x":4,"y":2,"label":"Lifecycle and Impact test","id":null},
{"x":4,"y":3,"label":"This is a test","id":null},
{"x":4,"y":3,"label":"New Functional Area Test","id":null},
{"x":4,"y":3,"label":"this is a test 1","id":null},
{"x":4,"y":3,"label":"DELETED","id":null},
{"x":4,"y":3,"label":"Test4","id":null},
{"x":4,"y":5,"label":"Name Test","id":null},
{"x":4,"y":5,"label":"Test of LMPI","id":null},
{"x":5,"y":2,"label":"test1","id":null},
{"x":5,"y":3,"label":"Edge Test 2","id":null},
{"x":5,"y":3,"label":"TPPI Test","id":null},
{"x":5,"y":3,"label":"Security Marking Test","id":null},
{"x":5,"y":5,"label":"Test2","id":null}
]
我看过以下帖子:how-to-render-a-line-from-datalabels-to-marker-on-graph-in-highcharts,但我不知道如何使用/调用以下函数:
Highcharts.SVGRenderer.prototype.symbols.connector = function(x, y, w, h, options) {
var anchorX = options && options.anchorX,
anchorY = options && options.anchorY,
path,
yOffset,
lateral = w / 2,
H = Highcharts;
if (H.isNumber(anchorX) && H.isNumber(anchorY)) {
path = ['M', anchorX, anchorY];
// Prefer 45 deg connectors
yOffset = y - anchorY;
if (yOffset < 0) {
yOffset = -h - yOffset;
}
if (yOffset < w) {
lateral = anchorX < x + (w / 2) ? yOffset : w - yOffset;
}
// Anchor below label
if (anchorY > y + h) {
path.push('L', x + lateral, y + h);
// Anchor above label
} else if (anchorY < y) {
path.push('L', x + lateral, y);
// Anchor left of label
} else if (anchorX < x) {
path.push('L', x, y + h / 2);
// Anchor right of label
} else if (anchorX > x + w) {
path.push('L', x + w, y + h / 2);
}
}
return path || [];
};
如何绘制从标签到点的线?
1条答案
按热度按时间dtcbnfnu1#
您可以使用添加另一个散点序列,并对其进行一些修改以显示连接和dataLabels。
用于设置行为的选项图表,其中
enableMouseTracking: false
用于关闭鼠标跟踪,lineWidth: 1
用于绘制线条(与点的连接),showInLegend: false
用于隐藏图例中的系列。实时演示:http://jsfiddle.net/BlackLabel/hpds8f0x/2/