Override Data Tip Circle

2019-07-18 14:01发布

问题:

In flex charting you can customize the box which displays datatip information, but is there any easy way of changing the little circle which is displayed next to the datatip box?

http://help.adobe.com/en_US/flex/using/images/chd_SimpleDataTip.png

I've found the method positionDataTips() in ChartBase which appears to do the drawing of the circle. I was going to subclass LineChart and override the method with my modified version of it. However, this method needs access to a lot of private instance variables which are only accessible to ChartBase.

Thoughts?

回答1:

I spent a very long week dealing with this and other issues relating to chart datatips. I have an answer to a similar question at similar question that you can look at. I will post here a modified version of that answer, since it was never marked as the answer to the question :-(


There isn't any good documentation on how exactly to work with overriding the two massive functions, ChartBase.positionDataTips and ChartBase.positionAllDataTips. I spent many days digging through mx charting code to determine the best way to override these functions in order to bend the flex charts to my will :-P

Here is some (hard-earned) code to customize the data tip targets, the default bulls-eye circles that show upon mouse hover over a series.

  1. Create a new chart class that extends ChartBase or a child of that.
  2. Set the ChartBase style, showDataTipTargets, to false.
  3. Create a new Style, showCustomDataTipTargets, on your custom chart class.
    • you might even want to create a Style for a dataTipTargetRenderer to do the custom rendering. This would be a much more elegant solution.
  4. Override positionDataTips and positionAllDatatips
    • I have written code to draw a square, but to make a larger circle, simply use your own values in place of TOOLTIP_TARGET_RADIUS and TOOLTIP_TARGET_INNER_RADIUS.

The new overridden functions would look something like this:

override protected function positionDataTips():void
{
  // Setting the showDataTipTargets to false will prevent 
  // super.positionDataTips() from drawing the default bulls-eyes.
  // By setting this style, we allow super.positionDataTips() to do all 
  // the "heavy-lifting" involved with dataTip positioning and dataTip box rendering
  // before we do our customization of the dataTipTargets
  this.setStyle("showDataTipTargets", false);

  // this will do all the normal rendering of the datatips and callout
  // but it will not draw the dataTipTarget because that is dependent upon
  // the style, showDataTipTargets
  super.positionDataTips();

  // now here you draw your custom datatip target. 
  // Use the code from ChartBase.positionDataTips as a guide, 
  // I have written code to simply draw a square instead of circle.
  // You can do much more complex things here as needed.
  if (len > 1)
  {
    // calloutStroke code is copied verbatim from super function
    // However, you can customize the calloutStroke rendering just as easily
    // by modifying the following code!
    if (calloutStroke)
    {
      calloutStroke.apply(g,null,null);

      if (tipData.isRight)
      {                   
        g.moveTo(chartLocalPts.x,
                chartLocalPts.y + tipData.height /  2);
        g.lineTo(tipData.x,
                chartLocalPts.y + tipData.height / 2);
        g.lineTo(tipData.x, tipData.y);
      }
      else
      {
        if(layoutDirection == LayoutDirection.RTL)
        {
        g.moveTo(chartLocalPts.x - tipData.width,
        chartLocalPts.y + tipData.height / 2);
        }
        else
        {
        g.moveTo(chartLocalPts.x + tipData.width,
        chartLocalPts.y + tipData.height / 2);
        }
          g.lineTo(tipData.x,
                  chartLocalPts.y + tipData.height / 2);
          g.lineTo(tipData.x, tipData.y);
        }
    }
  }

  // Here is custom dataTipTarget code!!
  // It draws a 5x5 square around the point on the series
  var tipColor:uint = tipData.hd.contextColor;
  g.lineStyle(1, tipColor, 100);
  g.moveTo(tipData.x, tipData.y);
  g.beginFill(0xFFFFFF, 1);
  g.drawRect(tipData.x, tipData.y, 5, 5);
  g.endFill();

}

Below is the code copied from ChartBase.positionDataTip() for reference:

  if (len > 1)
  {
    if (calloutStroke)
    {
      calloutStroke.apply(g,null,null);

      if (tipData.isRight)
      {                   
        g.moveTo(chartLocalPts.x,
                chartLocalPts.y + tipData.height /  2);
        g.lineTo(tipData.x,
                chartLocalPts.y + tipData.height / 2);
        g.lineTo(tipData.x, tipData.y);
      }
      else
      {
        if(layoutDirection == LayoutDirection.RTL)
        {
        g.moveTo(chartLocalPts.x - tipData.width,
        chartLocalPts.y + tipData.height / 2);
        }
        else
        {
        g.moveTo(chartLocalPts.x + tipData.width,
        chartLocalPts.y + tipData.height / 2);
        }
          g.lineTo(tipData.x,
                  chartLocalPts.y + tipData.height / 2);
          g.lineTo(tipData.x, tipData.y);
        }
    }
  }

  var tipColor:uint = tipData.hd.contextColor;
  g.lineStyle(1, tipColor, 100);
  g.moveTo(tipData.x, tipData.y);
  g.beginFill(0xFFFFFF, 1);
  g.drawCircle(tipData.x, tipData.y, TOOLTIP_TARGET_RADIUS);
  g.endFill();

  g.beginFill(tipColor, 1);
  g.drawCircle(tipData.x, tipData.y,
            TOOLTIP_TARGET_INNER_RADIUS);
  g.endFill();