Highcharts - 使用选定的饼图切片获得 3d 效果
Highcharts - Getting a 3d effect with selected pie chart slices
在 highcharts 中,我试图做到这样,当用户选择或将鼠标悬停在饼图的一个切片上时,该切片会产生在 z 轴(朝向用户)上上升的效果。我试图通过 css 设置阴影过滤器并使切片的边界更宽(填充颜色相同)来实现这一点。然而,我面临的问题是这些切片仍然可以在其他切片下方,因此所选切片及其阴影将位于这些切片的后面,因此看起来仍然在它们下面。进一步说明:
由于最后添加了红色,因此选中时看起来不错 - 它位于其他饼图上方。
但是,蓝色在被选中时会卡在其他切片后面,因为它在数组中排在第一位。
我知道 SVG 会按照 DOM 中的顺序堆叠元素,而不是 css 属性,例如 z-index,所以一个想法是删除选择点,然后再次附加它。然而,这会重新排列整个馅饼,因此它不是替代方案。
有没有其他我没有想到的解决方案?
document.addEventListener('DOMContentLoaded', function() {
const chart = Highcharts.chart('container', getChartOptions())
})
/**
* Gets the highchart options for the pie chart.
* Each data point has event handlers added to them
* To set the correct border widths
*/
function getChartOptions() {
return {
series: [{
type: 'pie',
innerSize: '80%',
allowPointSelect: true,
slicedOffset: 0,
states: {
// Remove default hover settings
hover: {
halo: null,
brightness: 0,
},
},
data: getMockData()
}],
};
}
/**
* Generates mock data for highcharts
* Each data point has event handlers set up in the `events` property
*/
function getMockData() {
return [{
color: '#aaf',
borderColor: '#aaf',
y: 4,
events: getEventHandlers(),
},
{
color: '#afa',
borderColor: '#afa',
y: 3,
events: getEventHandlers(),
},
{
color: '#faa',
borderColor: '#faa',
y: 8,
events: getEventHandlers(),
},
]
}
/**
* Event handlers for highchart data points.
* The border width of the slice is set to 20 for `select` and `mouseOver`
* The border width of the slice is set to 0 for `unselect` and `mouseOut` (except when the event is selected, in which case `mouseOut` shouldn't do anything)
*/
function getEventHandlers() {
return {
select: (obj) => {
obj.target.update({
borderWidth: 20
});
},
unselect: (obj) => {
obj.target.update({
borderWidth: 0
});
},
mouseOver: (obj) => {
obj.target.update({
borderWidth: 20
});
},
mouseOut: (obj) => {
if (!obj.target['selected']) {
obj.target.update({
borderWidth: 0
});
}
},
};
}
/* A drop shadow is the effect I want to accomplish, but it should be above the other slices. */
.highcharts-pie-series .highcharts-point-hover,
.highcharts-pie-series .highcharts-point-select {
filter: drop-shadow(0 0 10px black);
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container" style="width:100%; height:400px;"></div>
要在悬停时获得额外的边框,您可以触发 point.events 并添加 SVG 属性。
plotOptions: {
pie: {
type: 'pie',
innerSize: '80%',
allowPointSelect: true,
slicedOffset: 0,
states: {
hover: {
halo: null,
brightness: 0,
},
},
point: {
events: {
mouseOver: (obj) => {
obj.target.graphic.attr({
'stroke-width': 50,
stroke: obj.target.color,
zIndex: 3,
filter: 'drop-shadow(0 0 10px black)'
}).css({
borderRadius: 20
})
.add();
},
mouseOut: (obj) => {
obj.target.graphic.attr({
'stroke-width': 1,
stroke: obj.target.color,
filter: 'transparent'
}).css({
borderRadius: 0
})
.add();
},
}
}
}
},
现场演示:
https://jsfiddle.net/BlackLabel/u4ypbsrk/
API 参考文献:
https://api.highcharts.com/class-reference/Highcharts.SVGElement#attr,
https://api.highcharts.com/class-reference/Highcharts.CSSObject,
https://api.highcharts.com/highcharts/plotOptions.pie.point.events
显然,您从事件中获得的目标有一个名为 graphic
的 属性,它是切片 Highcharts.SVGElement 的句柄。这样,我们就可以调用 .toFront()
函数来改变 DOM 的顺序,而不改变甜甜圈中切片的顺序。
document.addEventListener('DOMContentLoaded', function() {
const chart = Highcharts.chart('container', getChartOptions())
})
/**
* Gets the highchart options for the pie chart.
* Each data point has event handlers added to them
* To set the correct border widths
*/
function getChartOptions() {
return {
series: [{
type: 'pie',
innerSize: '80%',
allowPointSelect: true,
slicedOffset: 0,
states: {
// Remove default hover settings
hover: {
halo: null,
brightness: 0,
},
},
data: getMockData()
}],
};
}
/**
* Generates mock data for highcharts
* Each data point has event handlers set up in the `events` property
*/
function getMockData() {
return [{
color: '#aaf',
borderColor: '#aaf',
y: 4,
events: getEventHandlers(),
},
{
color: '#afa',
borderColor: '#afa',
y: 3,
events: getEventHandlers(),
},
{
color: '#faa',
borderColor: '#faa',
y: 8,
events: getEventHandlers(),
},
]
}
/**
* Event handlers for highchart data points.
* The border width of the slice is set to 20 for `select` and `mouseOver`
* The border width of the slice is set to 0 for `unselect` and `mouseOut` (except when the event is selected, in which case `mouseOut` shouldn't do anything)
*/
function getEventHandlers() {
return {
select: (obj) => {
obj.target.update({
borderWidth: 20
});
obj.target.graphic.toFront();
},
unselect: (obj) => {
obj.target.update({
borderWidth: 0
});
},
mouseOver: (obj) => {
obj.target.update({
borderWidth: 20
});
obj.target.graphic.toFront();
},
mouseOut: (obj) => {
if (!obj.target['selected']) {
obj.target.update({
borderWidth: 0
});
}
},
};
}
/* A drop shadow is the effect I want to accomplish, but it should be above the other slices. */
.highcharts-pie-series .highcharts-point-hover,
.highcharts-pie-series .highcharts-point-select {
filter: drop-shadow(0 0 10px black);
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container" style="width:100%; height:400px;"></div>
在 highcharts 中,我试图做到这样,当用户选择或将鼠标悬停在饼图的一个切片上时,该切片会产生在 z 轴(朝向用户)上上升的效果。我试图通过 css 设置阴影过滤器并使切片的边界更宽(填充颜色相同)来实现这一点。然而,我面临的问题是这些切片仍然可以在其他切片下方,因此所选切片及其阴影将位于这些切片的后面,因此看起来仍然在它们下面。进一步说明:
由于最后添加了红色,因此选中时看起来不错 - 它位于其他饼图上方。
但是,蓝色在被选中时会卡在其他切片后面,因为它在数组中排在第一位。
我知道 SVG 会按照 DOM 中的顺序堆叠元素,而不是 css 属性,例如 z-index,所以一个想法是删除选择点,然后再次附加它。然而,这会重新排列整个馅饼,因此它不是替代方案。
有没有其他我没有想到的解决方案?
document.addEventListener('DOMContentLoaded', function() {
const chart = Highcharts.chart('container', getChartOptions())
})
/**
* Gets the highchart options for the pie chart.
* Each data point has event handlers added to them
* To set the correct border widths
*/
function getChartOptions() {
return {
series: [{
type: 'pie',
innerSize: '80%',
allowPointSelect: true,
slicedOffset: 0,
states: {
// Remove default hover settings
hover: {
halo: null,
brightness: 0,
},
},
data: getMockData()
}],
};
}
/**
* Generates mock data for highcharts
* Each data point has event handlers set up in the `events` property
*/
function getMockData() {
return [{
color: '#aaf',
borderColor: '#aaf',
y: 4,
events: getEventHandlers(),
},
{
color: '#afa',
borderColor: '#afa',
y: 3,
events: getEventHandlers(),
},
{
color: '#faa',
borderColor: '#faa',
y: 8,
events: getEventHandlers(),
},
]
}
/**
* Event handlers for highchart data points.
* The border width of the slice is set to 20 for `select` and `mouseOver`
* The border width of the slice is set to 0 for `unselect` and `mouseOut` (except when the event is selected, in which case `mouseOut` shouldn't do anything)
*/
function getEventHandlers() {
return {
select: (obj) => {
obj.target.update({
borderWidth: 20
});
},
unselect: (obj) => {
obj.target.update({
borderWidth: 0
});
},
mouseOver: (obj) => {
obj.target.update({
borderWidth: 20
});
},
mouseOut: (obj) => {
if (!obj.target['selected']) {
obj.target.update({
borderWidth: 0
});
}
},
};
}
/* A drop shadow is the effect I want to accomplish, but it should be above the other slices. */
.highcharts-pie-series .highcharts-point-hover,
.highcharts-pie-series .highcharts-point-select {
filter: drop-shadow(0 0 10px black);
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container" style="width:100%; height:400px;"></div>
要在悬停时获得额外的边框,您可以触发 point.events 并添加 SVG 属性。
plotOptions: {
pie: {
type: 'pie',
innerSize: '80%',
allowPointSelect: true,
slicedOffset: 0,
states: {
hover: {
halo: null,
brightness: 0,
},
},
point: {
events: {
mouseOver: (obj) => {
obj.target.graphic.attr({
'stroke-width': 50,
stroke: obj.target.color,
zIndex: 3,
filter: 'drop-shadow(0 0 10px black)'
}).css({
borderRadius: 20
})
.add();
},
mouseOut: (obj) => {
obj.target.graphic.attr({
'stroke-width': 1,
stroke: obj.target.color,
filter: 'transparent'
}).css({
borderRadius: 0
})
.add();
},
}
}
}
},
现场演示:
https://jsfiddle.net/BlackLabel/u4ypbsrk/
API 参考文献:
https://api.highcharts.com/class-reference/Highcharts.SVGElement#attr,
https://api.highcharts.com/class-reference/Highcharts.CSSObject,
https://api.highcharts.com/highcharts/plotOptions.pie.point.events
显然,您从事件中获得的目标有一个名为 graphic
的 属性,它是切片 Highcharts.SVGElement 的句柄。这样,我们就可以调用 .toFront()
函数来改变 DOM 的顺序,而不改变甜甜圈中切片的顺序。
document.addEventListener('DOMContentLoaded', function() {
const chart = Highcharts.chart('container', getChartOptions())
})
/**
* Gets the highchart options for the pie chart.
* Each data point has event handlers added to them
* To set the correct border widths
*/
function getChartOptions() {
return {
series: [{
type: 'pie',
innerSize: '80%',
allowPointSelect: true,
slicedOffset: 0,
states: {
// Remove default hover settings
hover: {
halo: null,
brightness: 0,
},
},
data: getMockData()
}],
};
}
/**
* Generates mock data for highcharts
* Each data point has event handlers set up in the `events` property
*/
function getMockData() {
return [{
color: '#aaf',
borderColor: '#aaf',
y: 4,
events: getEventHandlers(),
},
{
color: '#afa',
borderColor: '#afa',
y: 3,
events: getEventHandlers(),
},
{
color: '#faa',
borderColor: '#faa',
y: 8,
events: getEventHandlers(),
},
]
}
/**
* Event handlers for highchart data points.
* The border width of the slice is set to 20 for `select` and `mouseOver`
* The border width of the slice is set to 0 for `unselect` and `mouseOut` (except when the event is selected, in which case `mouseOut` shouldn't do anything)
*/
function getEventHandlers() {
return {
select: (obj) => {
obj.target.update({
borderWidth: 20
});
obj.target.graphic.toFront();
},
unselect: (obj) => {
obj.target.update({
borderWidth: 0
});
},
mouseOver: (obj) => {
obj.target.update({
borderWidth: 20
});
obj.target.graphic.toFront();
},
mouseOut: (obj) => {
if (!obj.target['selected']) {
obj.target.update({
borderWidth: 0
});
}
},
};
}
/* A drop shadow is the effect I want to accomplish, but it should be above the other slices. */
.highcharts-pie-series .highcharts-point-hover,
.highcharts-pie-series .highcharts-point-select {
filter: drop-shadow(0 0 10px black);
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container" style="width:100%; height:400px;"></div>