【问题标题】:Highcharts - Getting a 3d effect with selected pie chart slicesHighcharts - 使用选定的饼图切片获得 3d 效果
【发布时间】:2022-01-11 23:21:06
【问题描述】:

在 highcharts 中,我试图使当用户选择或悬停在饼图的一个切片上时,该切片会产生沿 z 轴(朝向用户)向上的效果。我试图通过通过css设置阴影过滤器并使切片的边框更宽(填充颜色相同)来实现这一点。但是,我面临的问题是切片仍然可以位于其他切片下方,因此所选切片及其阴影将位于这些切片的后面,因此似乎仍在它们之下。进一步说明:

由于红色是最后添加的,因此选中时看起来不错 - 它位于其他饼图的上方。

但是,蓝色在被选中时会卡在其他切片的后面,因为它是数组中的第一个。

我知道 SVG 会按照元素在 DOM 中的顺序堆叠元素,而不是使用诸如 z-index 之类的 css 属性,所以一个想法是删除选定的点,然后再次附加它。然而,这会重新排列整个派,因此它不是替代方案。

还有其他我没有想到的解决方案吗?

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>

【问题讨论】:

  • 我更新了问题以非常清楚地了解该问题,并包含了我拥有的代码(已经在 stackblitz 中)。任何有足够代表分数的人,请重新打开这个问题。
  • @T.J.Crowder 感谢您的反馈。我会尝试只用 Highcharts 做一个堆栈 sn-p,但我从来没有在没有 Angular 的情况下做过。
  • 是的,我真的希望我对 Angular 有足够的了解,可以用它做一个 Stack Snippet(或者其他人已经为 Angular 写了一篇文章likethese) . :-(
  • @T.J.Crowder 没问题! sn-p 编辑器不包含 Angular (2+) 的轻松插入,但包含已达到 EOL 的 AngularJS,这有点愚蠢。无论如何,我只用 highcharts 进行了更新。
  • 不错!! ....

标签: javascript css svg dom highcharts


【解决方案1】:

要在悬停时获得额外边框,您可以触发 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 属性(Point API 中没有记录),然后你使用 .add() 放置 svg 元素如果已经添加,则在前面(DOM 兄弟的最后一个)。我改用.toFront(),但两者都有效。
  • 添加更多关于它的描述的好主意,但我注意到plotOptions.pie.point作为增强。
【解决方案2】:

显然,您从事件中获得的目标有一个名为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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多