核心情节:如何从用户选择的栏呈现弹出框

Posted

技术标签:

【中文标题】核心情节:如何从用户选择的栏呈现弹出框【英文标题】:Core Plot: How to present popover from a bar selected by the user 【发布时间】:2012-12-01 09:41:53 【问题描述】:

我想完成什么

我正在使用 Core Plot (1.1) 绘制条形图,我想在用户选择(点击)的条形下方显示一个带有更多详细信息的弹出框。

代码

我的代码如下所示:

- (void)barPlot:(CPTBarPlot *)plot barWasSelectedAtRecordIndex:(NSUInteger)idx 

    NSNumber *yValue = self.values[idx];
    NSLog(@"barWasSelectedAtRecordIndex x: %i, y: %@",idx,yValue);

    NSDecimal plotPoint[2];
    NSNumber *plotXvalue = [self numberForPlot:plot
                                         field:CPTScatterPlotFieldX
                                   recordIndex:idx];
    plotPoint[CPTCoordinateX] =
        CPTDecimalFromFloat(plotXvalue.floatValue);

    NSNumber *plotYvalue = [self numberForPlot:plot
                                         field:CPTScatterPlotFieldY
                                   recordIndex:idx];

    plotPoint[CPTCoordinateY] =
        CPTDecimalFromFloat(plotYvalue.floatValue); 

    CPTXYPlotSpace *plotSpace =
        (CPTXYPlotSpace *)graph.defaultPlotSpace;
    CGPoint dataPoint =
        [plotSpace plotAreaViewPointForPlotPoint:plotPoint];
    NSLog(@"datapoint (CGPoint) coordinates tapped: %@",
          NSStringFromCGPoint(dataPoint));

    GrowthChartInfoTableViewController *infoViewController =
        [self.storyboard instantiateViewControllerWithIdentifier:
         @"GrowthChartInfo"];

    self.popover = [[UIPopoverController alloc]
                    initWithContentViewController:infoViewController];
    self.popover.popoverContentSize = CGSizeMake(320, 300);
    self.popover.delegate = self;
    CGRect popoverAnchor =
            CGRectMake(dataPoint.x + graph.paddingLeft,
                       dataPoint.y - graph.paddingTop + graph.paddingBottom,
                       (CGFloat)1.0f, (CGFloat)1.0f);

    [self.popover presentPopoverFromRect:popoverAnchor
                                  inView:self.view
                permittedArrowDirections:UIPopoverArrowDirectionAny
                                animated:YES];

我的问题

popover view controller 的 y 位置不正确,每个 bar 和第一个 bar 都有不同的 y 值,它显示在 bar 的上限而不是下限和隐藏栏。 x 位置似乎是正确的。

请帮忙

关于为什么我的代码不能按预期工作的任何想法?

谢谢!

编辑

根据 Eric 的回答,我已将代码更新如下:

- (void)barPlot:(CPTBarPlot *)plot barWasSelectedAtRecordIndex:(NSUInteger)idx 

    NSNumber *plotXvalue = [self numberForPlot:plot
                                         field:CPTScatterPlotFieldX
                                   recordIndex:idx];
    NSNumber *plotYvalue = [self numberForPlot:plot
                                         field:CPTScatterPlotFieldY
                                   recordIndex:idx];

    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;

    CGPoint cgPlotPoint =
        CGPointMake(plotXvalue.floatValue,
                    plotYvalue.floatValue);
    CGPoint cgPlotAreaPoint =
        [graph convertPoint:cgPlotPoint toLayer:graph.plotAreaFrame.plotArea];

    NSDecimal plotAreaPoint[2];
    plotAreaPoint[CPTCoordinateX] =
        CPTDecimalFromFloat(cgPlotAreaPoint.x);
    plotAreaPoint[CPTCoordinateY] =
        CPTDecimalFromFloat(cgPlotAreaPoint.y);

    CGPoint dataPoint = [plotSpace


           plotAreaViewPointForPlotPoint:plotAreaPoint];
        NSLog(@"datapoint (CGPoint) coordinates tapped: %@",NSStringFromCGPoint(dataPoint));

GrowthChartInfoTableViewController *infoViewController = [self.storyboard 
   instantiateViewControllerWithIdentifier:@"GrowthChartInfo"];



    self.popover = nil;
        self.popover = [[UIPopoverController alloc]


      initWithContentViewController:infoViewController];
    self.popover.popoverContentSize = CGSizeMake(250, 200);
    self.popover.delegate = self;
    CGRect popoverAnchor =
        CGRectMake(dataPoint.x + graph.paddingLeft,
                   dataPoint.y - graph.paddingTop + graph.paddingBottom,
                   (CGFloat)1.0f, (CGFloat)1.0f);

    [self.popover presentPopoverFromRect:popoverAnchor
        inView:self.view
        permittedArrowDirections:UIPopoverArrowDirectionUp
        animated:YES];

但是,我得到的结果比以前更错误。我相信我一定误会了什么。以下是 NSLog 命令的一些结果:

barWasSelectedAtRecordIndex x: 0, y: -0.03920931548773198848
datapoint (CGPoint) coordinates tapped: -6388.88, -67024.8

barWasSelectedAtRecordIndex x: 2, y: 0.174494288286651392
datapoint (CGPoint) coordinates tapped: -6073.38, -66790

barWasSelectedAtRecordIndex x: 2, y: 0.174494288286651392
datapoint (CGPoint) coordinates tapped: -6073.38, -66790

barWasSelectedAtRecordIndex x: 0, y: -0.03920931548773198848
datapoint (CGPoint) coordinates tapped: -6388.88, -67024.8

在我的代码中,从条形坐标到视图坐标的转换似乎是完全错误的。

编辑 2

再次感谢您的代码示例,Eric!

我已经更新了我的代码并使用以下选项对其进行了测试(y 值 = 0:plotPoint[CPTCoordinateY] = CPTDecimalFromFloat(0.0f),这会导致弹出框的锚点,其 y 值似乎不正确(请参阅以下屏幕截图). 锚点的y值应该等于0在y轴上的位置。

然后我尝试将锚点的 y 值设置为数据的当前 y 值。 (plotPoint[CPTCoordinateY] = plotYvalue.decimalValue)。这会导致锚点靠近 y 轴的 0 值,而不是靠近条形的顶部。但是,每家公司的 y 值(x 值)都有一点变化,这表明 y 值的偏移可能存在问题:

我还尝试了 Eric 建议 dataPoint = [self.view convertPoint:dataPoint fromView:graph.hostingView] 的额外转换,但这并没有改变结果。此外,我尝试将- graph.paddingTop + graph.paddingBottom 添加到最终的y 值,但没有成功。

对于我的错误可能是什么,我将不胜感激。

谢谢!

【问题讨论】:

Bar 不是 UIComponent 。它只是一张图。因此,当您为每个条绘制条并存储在数组中时,您需要创建一个 CGRect 点,并且您需要在 touchesBegan: 方法中检查数组中任何矩形中的用户触摸。我也可能错了。但这只是一个想法。 我正在使用- barPlot:barWasSelectedAtRecordIndex: 来获取所选柱的索引及其y值。 【参考方案1】:

-plotAreaViewPointForPlotPoint: 方法返回绘图区域坐标系中的一个点。您需要将其转换为图形的坐标系:

[graph convertPoint:dataPoint fromLayer:graph.plotAreaFrame.plotArea];

图表和它的宿主视图共享一个坐标系。如果self.view 不是宿主视图,则需要将坐标从宿主视图转换为其坐标系。


更完整的代码示例:

NSDecimal plotPoint[2];
NSNumber *plotXvalue = [self numberForPlot:plot
                                     field:CPTScatterPlotFieldX
                               recordIndex:idx];
plotPoint[CPTCoordinateX] = plotXvalue.decimalValue;

NSNumber *plotYvalue = [self numberForPlot:plot
                                     field:CPTScatterPlotFieldY
                               recordIndex:idx];
plotPoint[CPTCoordinateY] = plotYvalue.decimalValue; 

CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;

// convert from data coordinates to plot area coordinates
CGPoint dataPoint = [plotSpace plotAreaViewPointForPlotPoint:plotPoint];

// convert from plot area coordinates to graph (and hosting view) coordinates
dataPoint = [graph convertPoint:dataPoint fromLayer:graph.plotAreaFrame.plotArea];

// convert from hosting view coordinates to self.view coordinates (if needed)
dataPoint = [self.view convertPoint:dataPoint fromView:hostingView];

NSLog(@"barWasSelectedAtRecordIndex x: %@, y: %@", plotXvalue, plotYvalue);
NSLog(@"datapoint coordinates tapped: %@", NSStringFromCGPoint(dataPoint));

【讨论】:

我必须先使用-plotAreaViewPointForPlotPoint:转换点,然后再使用[graph convertPoint:dataPoint fromLayer:graph.plotAreaFrame.plotArea]再转换吗?当我链接这两种方法时,我得到了错误的 x 值结果。但是,当我不使用 [graph convertPoint:dataPoint fromLayer:graph.plotAreaFrame.plotArea]时,我会得到正确的 x 值。这怎么可能? 需要-plotAreaViewPointForPlotPoint: 转换。它采用数据坐标中的值(条形位置和提示)并将它们转换为绘图区域中的视图坐标。 Eric,感谢您提供的代码示例,我已经对其进行了广泛的测试。但是,我仍然对 y 坐标有疑问:似乎 y 值的偏移存在问题。当我将 y 值设置为 0 时,锚点会粘在条形的顶部。对于改变 y 值(例如 0.15 和 0.17),锚点也会改变,但仍然接近 y 轴的 0 值。关于我的代码可能有什么问题的任何想法?谢谢! Core Plot 将翻转变换应用于 ios 上的托管视图。弹出框锚点的 y 坐标位于翻转坐标系中。您在某处缺少另一个坐标空间转换。 是的,似乎是翻转坐标系导致了这个问题。但是,我完全不知道我应该在哪里需要额外的空间转换(以及我应该如何添加它)。不幸的是,这个坐标空间转换主题对我来说是全新的。您对我如何解决此问题或我应该在哪里查找错误有任何提示吗?非常感谢!

以上是关于核心情节:如何从用户选择的栏呈现弹出框的主要内容,如果未能解决你的问题,请参考以下文章

在表格视图中选择项目后无法关闭弹出框

如何使用情节提要从自定义 uitableviewcell 正确启动弹出框转场

试图关闭故事板呈现的弹出框

Web自动化测试10:Selenium下拉选择框弹出框滚动条操作

updatepanel 里面放ASPxGridView,使用RegisterClientScriptBlock方法,弹出框弹不出

Swift - 呈现已呈现的弹出框时应用程序崩溃