热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linechart+Datagrid互动展示数据(Linechart自定义数据点选择线)

如上图示,在linechart中添加红色Y线,拖动该线的过程中,经过数据点时,会实时更新datagrid中对应的X、Y值数据。实现要点:1

如上图示,在linechart中添加红色Y线,拖动该线的过程中,经过数据点时,会实时更新datagrid中对应的X、Y值数据。


实现要点:

1.linechart添加Y线

继承mx.charts.chartClasses.ChartElement,自定义Y线。

package
{
import flash.display.Graphics;
import flash.geom.Point;
import flash.text.TextField;

import mx.charts.chartClasses.CartesianChart;
import mx.charts.chartClasses.CartesianTransform;
import mx.charts.chartClasses.ChartElement;
import mx.charts.chartClasses.ChartState;
import mx.charts.chartClasses.IAxis;

public class DashedLines extends ChartElement
{
public function DashedLines()
{
super();
}

private var _yValue:Number = NaN;
private var _xValue:Date = null;

public function get xValue():Date
{
return _xValue;
}
public function set xValue(value:Date):void
{
_xValue = value;
invalidateDisplayList();
}

public function get yValue():Number
{
return _yValue;
}

public function set yValue(value:Number):void
{
_yValue = value;
invalidateDisplayList();
}

/**
* 实线部分的长度
* @default 10
*/
public var length:Number = 10;

/**
* 空白部分的长度
* @default 5
*/
public var gap:Number = 0;

/**
* 线条的宽度
* @default 1
*/
public var lineThickness:Number = 3;

/**
* 线条的颜色
* @default 黑色
*/
public var lineColor:uint = 0;

private var _displayName:String;

/**
* 该线所对应的数值名称(平均值,最大值等等)
* @default
*/
public function get displayName():String
{
return _displayName;
}

/**
* @private
*/
public function set displayName(value:String):void
{
_displayName = value;
invalidateDisplayList();
}

protected var label:TextField;

override protected function createChildren():void
{
super.createChildren();

if(!label)
{
label = new TextField();
label.mouseEnabled = false;
addChild(label);
}
}

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);

if (!chart||
chart.chartState == ChartState.PREPARING_TO_HIDE_DATA ||
chart.chartState == ChartState.HIDING_DATA)
{
return;
}

var g:Graphics = this.graphics;
g.clear();

// 如果没有设置数据,不显示
if(xValue == null)
{
return;
}

var w:Number = unscaledWidth;
var h:Number = unscaledHeight;
var vAxis:IAxis = CartesianChart(this.chart).verticalAxis;
var x:Number = dataToLocal(xValue,0).x;
var pFrom:Point = new Point(x,0);
var pTo:Point = new Point(x,h);

GraphicUtils.drawDashed(g, pFrom, pTo, this.length, this.gap, this.lineThickness, this.lineColor);

label.text = (displayName ? (displayName + " : ") : "") + xValue;
label.x = x > 21 ? x - 21 : x + 1;
label.y = 1;
}

// 这个方法复制自LineSeries
override public function dataToLocal(... dataValues):Point
{
var data:Object = {};
var da:Array /* of Object */ = [ data ];
var n:int = dataValues.length;

if (n > 0)
{
data["d0"] = dataValues[0];
dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS).
mapCache(da, "d0", "v0");
}

if (n > 1)
{
data["d1"] = dataValues[1];
dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS).
mapCache(da, "d1", "v1");
}

dataTransform.transformCache(da,"v0","s0","v1","s1");
return new Point(data.s0 + this.x,
data.s1 + this.y);
}
}
}


该类中主要用到dataTransform,他提供了数据点与坐标空间的对应转换,主类中通过xValue将Y线处的x值传入,通过该方法转换为Y线需要绘制的坐标位置。

该类用到工具类GraphicUtils

package
{
import flash.display.Graphics;
import flash.geom.Point;

/**
* 一些绘图相关的方法
* @author lip
*/
public class GraphicUtils
{
public function GraphicUtils()
{
}


/**
* 画虚线
* @param graphics 你懂的
* @param pFrom 起点
* @param pTo 终点
* @param length 实线段的长度
* @param gap 实线段的间距
* @param thickness 线的宽度
* @param color 线的颜色
*/
public static function drawDashed(graphics:Graphics, pFrom:Point, pTo:Point, length:Number = 5, gap:Number = 5, thickness:Number = 1, color:uint = 0):void
{
var max:Number = Point.distance(pFrom, pTo);
var l:Number = 0;
var p3:Point;
var p4:Point;
graphics.lineStyle(thickness, color);
while (l {
p3 = Point.interpolate(pTo, pFrom, l / max);
l += length;
if (l > max)
l = max;
p4 = Point.interpolate(pTo, pFrom, l / max);
graphics.moveTo(p3.x, p3.y)
graphics.lineTo(p4.x, p4.y)
l += gap;
}
}
}
}

2、datagrid对应样式的定义

   请参考博文:datagrid样式


3、组件主类


xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:customcompOnent="com.bjrz.view.centerview.customcomponent.*"
xmlns:amcharts="http://www.amcharts.com/com_internal"

creatiOnComplete="generateChartData()" xmlns:local="*">

import mx.charts.ChartItem;
import mx.charts.chartClasses.IAxis;
import mx.charts.chartClasses.Series;
import mx.charts.series.items.LineSeriesItem;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.formatters.DateFormatter;
[Bindable]
private var attributes:ArrayCollection = new ArrayCollection(
[{lineColor:"0xFF6600", dataItem:"label",time:"北京", currentValue:"label",unit:"北京", show:"true",describe:"北京"},
{lineColor:"0x00ff00", dataItem:"label",time:"北京", currentValue:"label",unit:"北京", show:"true",describe:"北京"}]);
private var dateFormat:DateFormatter = new DateFormatter();
private function generateChartData():void
{
dateFormat.formatString = "HH:NN:SS";
}
[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection( [
{ Month: "Tue May 20 16:23:50 GMT+0800 2014", Profit: 2000, Expenses: 1500, Amount: 450 },
{ Month: "Tue May 20 16:23:51 GMT+0800 2014", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Tue May 20 16:23:52 GMT+0800 2014", Profit: 1500, Expenses: 500, Amount: 300 },
{ Month: "Tue May 20 16:23:53 GMT+0800 2014", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "Tue May 20 16:23:54 GMT+0800 2014", Profit: 2400, Expenses: 575, Amount: 500 },
{ Month: "Tue May 20 16:23:55 GMT+0800 2014", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Tue May 20 16:23:56 GMT+0800 2014", Profit: 1500, Expenses: 500, Amount: 300 },
{ Month: "Tue May 20 16:23:57 GMT+0800 2014", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "Tue May 20 16:23:58 GMT+0800 2014", Profit: 2400, Expenses: 575, Amount: 500 },
{ Month: "Tue May 20 16:23:59 GMT+0800 2014", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Tue May 20 16:24:00 GMT+0800 2014", Profit: 1500, Expenses: 500, Amount: 300 },
{ Month: "Tue May 20 16:24:01 GMT+0800 2014", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "Tue May 20 16:24:02 GMT+0800 2014", Profit: 2400, Expenses: 575, Amount: 500 },
{ Month: "Tue May 20 16:24:03 GMT+0800 2014", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Tue May 20 16:24:04 GMT+0800 2014", Profit: 1500, Expenses: 500, Amount: 300 },
{ Month: "Tue May 20 16:24:05 GMT+0800 2014", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "Tue May 20 16:24:06 GMT+0800 2014", Profit: 2400, Expenses: 575, Amount: 500 },
{ Month: "Tue May 20 16:24:07 GMT+0800 2014", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Tue May 20 16:24:08 GMT+0800 2014", Profit: 1500, Expenses: 500, Amount: 300 },
{ Month: "Tue May 20 16:24:09 GMT+0800 2014", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "Tue May 20 16:24:10 GMT+0800 2014", Profit: 2400, Expenses: 575, Amount: 500 },
{ Month: "Tue May 20 16:24:11 GMT+0800 2014", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Tue May 20 16:24:12 GMT+0800 2014", Profit: 1500, Expenses: 500, Amount: 300 },
{ Month: "Tue May 20 16:24:13 GMT+0800 2014", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "Tue May 20 16:24:14 GMT+0800 2014", Profit: 2400, Expenses: 575, Amount: 500 },
{ Month: "Tue May 20 16:24:15 GMT+0800 2014", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Tue May 20 16:24:16 GMT+0800 2014", Profit: 1500, Expenses: 500, Amount: 300 },
{ Month: "Tue May 20 16:24:17 GMT+0800 2014", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "Tue May 20 16:24:18 GMT+0800 2014", Profit: 2400, Expenses: 575, Amount: 500 },
{ Month: "Tue May 20 16:24:19 GMT+0800 2014", Profit: 1000, Expenses: 200, Amount: 600 }]);
[Bindable]
private var expensesAC2:ArrayCollection = new ArrayCollection( [
{ Month: "Tue May 20 16:23:50 GMT+0800 2014", Profit: 2100, Expenses: 1500, Amount: 460 },
{ Month: "Tue May 20 16:23:51 GMT+0800 2014", Profit: 1100, Expenses: 200, Amount: 660 },
{ Month: "Tue May 20 16:23:52 GMT+0800 2014", Profit: 1100, Expenses: 500, Amount: 340 },
{ Month: "Tue May 20 16:23:53 GMT+0800 2014", Profit: 1100, Expenses: 1200, Amount: 960 },
{ Month: "Tue May 20 16:23:54 GMT+0800 2014", Profit: 2100, Expenses: 575, Amount: 500 },
{ Month: "Tue May 20 16:23:55 GMT+0800 2014", Profit: 1100, Expenses: 200, Amount: 630 },
{ Month: "Tue May 20 16:23:56 GMT+0800 2014", Profit: 1100, Expenses: 500, Amount: 360 },
{ Month: "Tue May 20 16:23:57 GMT+0800 2014", Profit: 1100, Expenses: 1200, Amount: 930 },
{ Month: "Tue May 20 16:23:58 GMT+0800 2014", Profit: 2400, Expenses: 575, Amount: 500 },
{ Month: "Tue May 20 16:23:59 GMT+0800 2014", Profit: 1100, Expenses: 200, Amount: 600 },
{ Month: "Tue May 20 16:24:00 GMT+0800 2014", Profit: 1500, Expenses: 500, Amount: 320 },
{ Month: "Tue May 20 16:24:01 GMT+0800 2014", Profit: 1800, Expenses: 1200, Amount: 300 },
{ Month: "Tue May 20 16:24:02 GMT+0800 2014", Profit: 2410, Expenses: 575, Amount: 500 },
{ Month: "Tue May 20 16:24:03 GMT+0800 2014", Profit: 1010, Expenses: 200, Amount: 650 },
{ Month: "Tue May 20 16:24:04 GMT+0800 2014", Profit: 1500, Expenses: 500, Amount: 360 },
{ Month: "Tue May 20 16:24:05 GMT+0800 2014", Profit: 1100, Expenses: 1200, Amount: 900 },
{ Month: "Tue May 20 16:24:06 GMT+0800 2014", Profit: 2100, Expenses: 575, Amount: 500 },
{ Month: "Tue May 20 16:24:07 GMT+0800 2014", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Tue May 20 16:24:08 GMT+0800 2014", Profit: 1500, Expenses: 500, Amount: 360 },
{ Month: "Tue May 20 16:24:09 GMT+0800 2014", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "Tue May 20 16:24:10 GMT+0800 2014", Profit: 2400, Expenses: 575, Amount: 570 },
{ Month: "Tue May 20 16:24:11 GMT+0800 2014", Profit: 1100, Expenses: 200, Amount: 600 },
{ Month: "Tue May 20 16:24:12 GMT+0800 2014", Profit: 1100, Expenses: 500, Amount: 300 },
{ Month: "Tue May 20 16:24:13 GMT+0800 2014", Profit: 1100, Expenses: 1200, Amount: 940 },
{ Month: "Tue May 20 16:24:14 GMT+0800 2014", Profit: 2400, Expenses: 575, Amount: 540 },
{ Month: "Tue May 20 16:24:15 GMT+0800 2014", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Tue May 20 16:24:16 GMT+0800 2014", Profit: 1500, Expenses: 500, Amount: 340 },
{ Month: "Tue May 20 16:24:17 GMT+0800 2014", Profit: 1100, Expenses: 1200, Amount: 940 },
{ Month: "Tue May 20 16:24:18 GMT+0800 2014", Profit: 2400, Expenses: 575, Amount: 500 },
{ Month: "Tue May 20 16:24:19 GMT+0800 2014", Profit: 1100, Expenses: 200, Amount: 640 }]);
protected function dashedlines1_mouseDownHandler(event:MouseEvent):void
{
this.addEventListener(MouseEvent.MOUSE_MOVE,dashedLine_mouseMoveHandler);
this.addEventListener(MouseEvent.MOUSE_UP,dashedlines1_mouseUpHandler);
}

protected function dashedlines1_mouseUpHandler(event:MouseEvent):void
{
this.removeEventListener(MouseEvent.MOUSE_MOVE,dashedLine_mouseMoveHandler);
this.removeEventListener(MouseEvent.MOUSE_UP,dashedlines1_mouseUpHandler);
}
[Bindable]
private var linePosition:Number = 2;

protected function dashedLine_mouseMoveHandler(event:MouseEvent):void
{
dashedLine.xValue = new Date(Number((((linechart.mouseX - 50)*((hAxis.maximum as Date).time-(hAxis.minimum as Date).time)/(linechart.width-50)
+(hAxis.minimum as Date).time)/1000).toFixed(0))*1000);
var allSeries:Array = linechart.series;
//由于只有一条线条,所以数组长度为1,这里得到线条的series
var series:Series = allSeries[0] as Series;

for(var i:int = 0;ivar item:ChartItem = series.items[i];
//图表中一个item唯一对应的就是数据源里的一个对象
var LCI:LineSeriesItem= item as LineSeriesItem;
if(dashedLine.xValue.toString() == LCI.xValue.toString()){
//符合要求就加到series的dataTipItems集合里面,以便最后显示
historyDatagrid.dataProvider.getItemAt(0).currentValue = LCI.yValue;
historyDatagrid.dataProvider.getItemAt(0).time = LCI.xValue;
}
}

var series2:Series = allSeries[1] as Series;

for(var j:int = 0;jvar item2:ChartItem = series2.items[j];
//图表中一个item唯一对应的就是数据源里的一个对象
var LCI2:LineSeriesItem= item2 as LineSeriesItem;
if(dashedLine.xValue.toString() == LCI2.xValue.toString()){
//符合要求就加到series的dataTipItems集合里面,以便最后显示
historyDatagrid.dataProvider.getItemAt(1).currentValue = LCI2.yValue;
historyDatagrid.dataProvider.getItemAt(1).time = LCI2.xValue;
}
}
historyDatagrid.dataProvider.itemUpdated(null,"currentValue");
historyDatagrid.dataProvider.itemUpdated(null,"time");
}

protected function button1_clickHandler(event:MouseEvent):void
{
/* dashedLine.xValue =2.5; */
dashedLine.xValue =new Date(2014,4,20,16,23,51);
}

/**
*
* 转换x轴坐标的显示 ,按HH:NN:SS 格式显示
* @return
* @param labelValue 时间
* @author
* @date
*/
private function mylabel(labelValue:Object, previousValue:Object, d:IAxis):String
{
dateFormat.formatString = "HH:NN:SS";
var str:String = dateFormat.format(labelValue);
return str;
}
]]>







paddingLeft="5" paddingRight="5"
showDataTips="true">


mouseDown="dashedlines1_mouseDownHandler(event)" mouseUp="dashedlines1_mouseUpHandler(event)"
lineColor="0xFF0000" xValue="{new Date(2014,4,20,16,23,52)}"/>























该类中,主要方法是针对Y线的拖拽处理。基本拖拽处理不再赘述。在mouseMove的处理中,需要对xValue执行重新赋值,以便刷新绘制Y线。

因为linechart只提供了数据点转坐标空间,没有找到坐标空间转数据点的方法。所以需要将鼠标位置mouseX通过计算转化为数据点x,然后作为xValue传入。

同时,根据数据点x获取对应的y值。这是出现一个问题: 

mouseX是连续的,而数据点非连续。

因为我的需求中linechart数据点十分密集,极近于连续点。所以我采用的方法是,将在计算转化的时候,取近似值。只将时间为整秒的数据做转化传入。这样并不影响最终使用效果。如果有更好的处理方式,望留言告知。






推荐阅读
  • 在Java项目中,当两个文件进行互相调用时出现了函数错误。具体问题出现在 `MainFrame.java` 文件中,该文件位于 `cn.javass.bookmgr` 包下,并且导入了 `java.awt.BorderLayout` 和 `java.awt.Event` 等相关类。为了确保项目的正常运行,请求提供专业的解决方案,以解决函数调用中的错误。建议从类路径、依赖关系和方法签名等方面入手,进行全面排查和调试。 ... [详细]
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • 在Django中提交表单时遇到值错误问题如何解决?
    在Django项目中,当用户提交包含多个选择目标的表单时,可能会遇到值错误问题。本文将探讨如何通过优化表单处理逻辑和验证机制来有效解决这一问题,确保表单数据的准确性和完整性。 ... [详细]
  • 本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。 ... [详细]
  • MySQL Decimal 类型的最大值解析及其在数据处理中的应用艺术
    在关系型数据库中,表的设计与SQL语句的编写对性能的影响至关重要,甚至可占到90%以上。本文将重点探讨MySQL中Decimal类型的最大值及其在数据处理中的应用技巧,通过实例分析和优化建议,帮助读者深入理解并掌握这一重要知识点。 ... [详细]
  • 本文介绍了如何使用 Node.js 和 Express(4.x 及以上版本)构建高效的文件上传功能。通过引入 `multer` 中间件,可以轻松实现文件上传。首先,需要通过 `npm install multer` 安装该中间件。接着,在 Express 应用中配置 `multer`,以处理多部分表单数据。本文详细讲解了 `multer` 的基本用法和高级配置,帮助开发者快速搭建稳定可靠的文件上传服务。 ... [详细]
  • Python 序列图分割与可视化编程入门教程
    本文介绍了如何使用 Python 进行序列图的快速分割与可视化。通过一个实际案例,详细展示了从需求分析到代码实现的全过程。具体包括如何读取序列图数据、应用分割算法以及利用可视化库生成直观的图表,帮助非编程背景的用户也能轻松上手。 ... [详细]
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • 使用Maven JAR插件将单个或多个文件及其依赖项合并为一个可引用的JAR包
    本文介绍了如何利用Maven中的maven-assembly-plugin插件将单个或多个Java文件及其依赖项打包成一个可引用的JAR文件。首先,需要创建一个新的Maven项目,并将待打包的Java文件复制到该项目中。通过配置maven-assembly-plugin,可以实现将所有文件及其依赖项合并为一个独立的JAR包,方便在其他项目中引用和使用。此外,该方法还支持自定义装配描述符,以满足不同场景下的需求。 ... [详细]
  • 使用 Vuex 管理表单状态:当输入框失去焦点时自动恢复初始值 ... [详细]
  • 在处理木偶评估函数时,我发现可以顺利传递本机对象(如字符串、列表和数字),但每当尝试将JSHandle或ElementHandle作为参数传递时,函数会拒绝接受这些对象。这可能是由于这些句柄对象的特殊性质导致的,建议在使用时进行适当的转换或封装,以确保函数能够正确处理。 ... [详细]
  • 探索聚类分析中的K-Means与DBSCAN算法及其应用
    聚类分析是一种用于解决样本或特征分类问题的统计分析方法,也是数据挖掘领域的重要算法之一。本文主要探讨了K-Means和DBSCAN两种聚类算法的原理及其应用场景。K-Means算法通过迭代优化簇中心来实现数据点的划分,适用于球形分布的数据集;而DBSCAN算法则基于密度进行聚类,能够有效识别任意形状的簇,并且对噪声数据具有较好的鲁棒性。通过对这两种算法的对比分析,本文旨在为实际应用中选择合适的聚类方法提供参考。 ... [详细]
  • 利用 Python 中的 Altair 库实现数据抖动的水平剥离分析 ... [详细]
  • 本题库精选了Java核心知识点的练习题,旨在帮助学习者巩固和检验对Java理论基础的掌握。其中,选择题部分涵盖了访问控制权限等关键概念,例如,Java语言中仅允许子类或同一包内的类访问的访问权限为protected。此外,题库还包括其他重要知识点,如异常处理、多线程、集合框架等,全面覆盖Java编程的核心内容。 ... [详细]
author-avatar
真实的独孤一剑
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有