前言

图表绘制可能是我们项目开发过程中比较常见的需求,简单点儿的需求,我们通过自定义控件就能完成,但是像那种比较复杂的图表,通过自定义的方式实现起来就比较麻烦了,这个时候,我们就需要借助第三方的开源库来实现。

Android 平台绘图的开源库有好几个,最成熟最出名的就属于MPAndroidChart了,他能帮我们实现曲线图、折线图、柱状图、饼状图,分布图等等。同时还可以实现混合图表。

  • 曲线图

    MPAndroidChart 绘制曲线图总结_java
  • 下方填充曲线图,可以设置纯色和渐变色


  • 混合图表

  • 柱状图

如上所示,实现的图表种类非常多,还没有列举完全,功能非常强大,正好最近在项目中有使用到MPAndroidChart,在此做一个总结。

项目中使用效果截图如下:
基础设置相关API
  • 1. Chart 的基础设置

      // 设置是否绘制背景
       mChart.setDrawGridBackground(false);
       // 设置是否绘制边框
       mChart.setDrawBorders(false);
       // 设置是否可以缩放图表
       mChart.setScaleEnabled(true);
       // 设置是否可以用手指移动图表
       mChart.setDragEnabled(true);

注意:这里说一下后面2个属性setScaleEnabledsetDragEnabled,设置图表是佛可以缩放和移动,当手机屏幕一屏显示不下时,我们希望能通过缩放或者滑动图表。但是经过试验,仅仅设置这两个属性是不行的,还需要配合Matrix来实现,代码如下:

 Matrix matrix = new Matrix();
 // x轴放大4倍,y不变
matrix.postScale(4.0f, 1.0f);
// 设置缩放
mChart.getViewPortHandler().refresh(matrix, mChart, false);
  • 2,图表描述相关设置

       // 不显示描述数据
       mChart.getDescription().setEnabled(true);
       mChart.getAxisRight().setEnabled(false);
       // 设置描述
       mChart.getDescription().setText("text desc");
       // 设置描述显示的位置,默认是显示在图表的右下角的
       mChart.getDescription().setPosition(200,100);

image.png

  • 3,是否显示右侧y轴

 mChart.getAxisRight().setEnabled(false);

image.png

  • 4, 图例相关设置

        Legend legend = mChart.getLegend();
      //是否显示
      legend.setEnabled(true);
       //图例样式:有圆点,正方形,短线 几种样式
       legend.setForm(Legend.LegendForm.CIRCLE);
       // 图例显示的位置:如下2行代码设置图例显示在左下角
       legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
       legend.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
       // 图例的排列方式:水平排列和竖直排列2种
       legend.setOrientation(Legend.LegendOrientation.HORIZONTAL);
       // 图例距离x轴的距离
       legend.setXEntrySpace(10f);
       //图例距离y轴的距离
       legend.setYEntrySpace(10f);
        //图例的大小
        legend.setFormSize(7f);
        // 图例描述文字大小
        legend.setTextSize(10);
  • 5,x轴先关设置

 XAxis xAxis = mChart.getXAxis();

       // 是否显示x轴线
       xAxis.setDrawAxisLine(true);
       // 设置x轴线的颜色
       xAxis.setAxisLineColor(Color.parseColor("#4cffffff"));
       // 是否绘制x方向网格线
       xAxis.setDrawGridLines(false);
       //x方向网格线的颜色
       xAxis.setGridColor(Color.parseColor("#30FFFFFF"));

       // 设置x轴数据的位置
       xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
       // 设置x轴文字的大小
       xAxis.setTextSize(12);

       // 设置x轴数据偏移量
       xAxis.setYOffset(5);
       final List<String> labels = mLabels;
       // 显示x轴标签
       IAxisValueFormatter formatter = new IAxisValueFormatter() {

           @Override
           public String getFormattedValue(float value, AxisBase axis) {
               int index = (int) value;
               if (index < 0 || index >= labels.size()) {
                   return "";
               }
               return labels.get(index);
               // return labels.get(Math.min(Math.max((int) value, 0), labels.size() - 1));
           }

       };
       // 引用标签
       xAxis.setValueFormatter(formatter);
       // 设置x轴文字颜色
       xAxis.setTextColor(mChart.getResources().getColor(R.color.char_text_color));
       // 设置x轴每最小刻度 interval
       xAxis.setGranularity(1f);

6,y轴先关设置

       YAxis yAxis = mChart.getAxisLeft();
       //设置x轴的最大值
       yAxis.setAxisMaximum(yMax);
       // 设置y轴的最大值
       yAxis.setAxisMinimum(yMin);
       // 不显示y轴
       yAxis.setDrawAxisLine(false);
       // 设置y轴数据的位置
       yAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
       // 不从y轴发出横向直线
       yAxis.setDrawGridLines(false);
       // 是否显示y轴坐标线
       yAxis.setDrawZeroLine(true);
       // 设置y轴的文字颜色
       yAxis.setTextColor(mChart.getResources().getColor(R.color.char_text_color));
       // 设置y轴文字的大小
       yAxis.setTextSize(12);
       // 设置y轴数据偏移量
       //yAxis.setXOffset(30);
       // yAxis.setYOffset(-3);
       yAxis.setXOffset(15);
       // 设置y轴label 数量
       yAxis.setLabelCount(5, false);
       // 设置y轴的最小刻度
       yAxis.setGranularity(5);//interval
  • 7,缩放和动画设置

  Matrix matrix = new Matrix();
       // 根据数据量来确定 x轴缩放大倍
       if (mLabels.size() <= 10) {
           matrix.postScale(1.0f, 1.0f);
       } else if (mLabels.size() <= 15) {
           matrix.postScale(1.5f, 1.0f);
       } else if (mLabels.size() <= 20) {
           matrix.postScale(2.0f, 1.0f);
       } else {
           matrix.postScale(3.0f, 1.0f);
       }

       // 在图表动画显示之前进行缩放
       mChart.getViewPortHandler().refresh(matrix, mChart, false);
       // x轴执行动画
       mChart.animateX(500);
  • 8, 无数据时,显示文案

 /**
    * 显示无数据的提示
    *
    * @param mChart
    */

   public static void NotShowNoDataText(Chart mChart) {
       mChart.clear();
       mChart.notifyDataSetChanged();
       mChart.setNoDataText("你还没有记录数据");
       mChart.setNoDataTextColor(Color.WHITE);
       // 记得最后要刷新一下
       mChart.invalidate();
   }
  • 9,设置marker
    (1)首先需要继承MarkerView 实现一个自定义View

public class ChartMarkerView extends MarkerView {

   private TextView textView;

   /**
    * Constructor. Sets up the MarkerView with a custom layout resource.
    *
    * @param context
    * @param layoutResource the layout resource to use for the MarkerView
    */

   public ChartMarkerView(Context context, int layoutResource) {
       super(context, layoutResource);
       textView = (TextView) findViewById(R.id.marker_view_text);
   }

   @Override
   public void refreshContent(Entry e, Highlight highlight) {
       float value = e.getY();
       textView.setText(DecimalFormatUtils.getIntOrFloatRemainOne(value));
   }

   @Override
   public MPPointF getOffsetForDrawingAtPoint(float posX, float posY) {
       return new MPPointF(-getWidth() / 2f, -getHeight() - 10);
   }
}

(2), 通过addMaker 添加到图上

combinedChart.setMarker(new ChartMarkerView(context, R.layout.chart_markerview_layout));

以上就是对Chart 的一些基础设置,包括x,y轴改如何显示(颜色、大小)、图例、描述等等。

下面就看看如何来绘制曲线图呢?

数据设置

当我们要绘制曲线图、折线图、和柱状图等等的时候,怎样将我们要绘制的一个个数据点显示在图上的呢?MPAndroidChart 是用dataSet来表示的,我们需要将数据点包装成DataSet,然后设置到Chart,刷新绘制就ok了。MPAndroidChart 库中有很多DataSet,如下所示:

image.png

以曲线图或者折线图为例,我们使用LineDataSet:

  /**
    * 获取LineDataSet
    *
    * @param entries
    * @param label
    * @param textColor
    * @param lineColor
    * @return
    */

   public static LineDataSet getLineData(List<Entry> entries, String label, @ColorInt int textColor, @ColorInt int lineColor, boolean isFill) {
       LineDataSet dataSet = new LineDataSet(entries, label);
       // 设置曲线的颜色
       dataSet.setColor(lineColor);
       //数值文字颜色
       dataSet.setValueTextColor(textColor);
       // 模式为贝塞尔曲线
       dataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);
       // 是否绘制数据值
       dataSet.setDrawValues(false);
       // 是否绘制圆点
       dataSet.setDrawCircles(true);
       dataSet.setDrawCircleHole(false);
       // 这里有一个坑,当我们想隐藏掉高亮线的时候,MarkerView 跟着不见了
       // 因此只有将它设置成透明色
       dataSet.setHighlightEnabled(true);// 隐藏点击时候的高亮线
       //设置高亮线为透明色
       dataSet.setHighLightColor(Color.TRANSPARENT);

       if (isFill) {
           //是否设置填充曲线到x轴之间的区域
           dataSet.setDrawFilled(true);
           // 填充颜色
           dataSet.setFillColor(lineColor);
       }
       //设置圆点的颜色
       dataSet.setCircleColor(lineColor);
       // 设置圆点半径
       dataSet.setCircleRadius(3.5f);
       // 设置线的宽度
       dataSet.setLineWidth(1f);
       return dataSet;
   }
将数据绘制到图表上

如果是一条曲线,直接用LineChart 和LineData就好,如果有多条曲线,就需要用CombinedChart 和 CombinedData (混合图、混合数据)。可以是LineData 和BarData 混合来绘制曲线和柱状的混合图。

/**
    * 初始化数据
    *
    * @param chart
    * @param lineDatas
    */

   public static void initData(CombinedChart chart, LineData... lineDatas) {
       CombinedData combinedData = new CombinedData();
       for (LineData lineData : lineDatas) {
           combinedData.setData(lineData);
       }

       chart.setData(combinedData);
       chart.invalidate();
   }

最后调用invalidate 绘制。

柱状图

柱状图跟曲线图其实是一样的,图表基础配置一样,然后将数据点包装成BarData,最后包装成BarDataSet。

/**
    * 初始化柱状图图表数据
    * @param chart
    * @param entries
    * @param title
    * @param barColor
    */

   public static void initBarChart(BarChart chart, List<BarEntry> entries, String title, @ColorInt int barColor) {
       BarDataSet set1 = new BarDataSet(entries, title);
       set1.setValueTextColor(Color.WHITE);
       set1.setColor(barColor);
       ArrayList<IBarDataSet> dataSets = new ArrayList<>();
       dataSets.add(set1);

       BarData data = new BarData(dataSets);
       data.setValueTextSize(10f);
       // 设置bar的宽度,但是点很多少的时候好像没作用,会拉得很宽
       data.setBarWidth(0.1f);
       // 设置value值 颜色
       data.setValueTextColor(Color.WHITE);
       //设置y轴显示的标签
       data.setValueFormatter(new IValueFormatter() {
           @Override
           public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
               return ((int) (value * 100)) + "%";
           }
       });


       chart.setData(data);
       chart.invalidate();
   }
工具类

项目中有很多出使用曲线图和柱状图的地方,因此抽取了一个工具类,完整代码如下:

public class MPChartUtils {
   /**
    * 不显示无数据的提示
    *
    * @param mChart
    */

   public static void NotShowNoDataText(Chart mChart) {
       mChart.clear();
       mChart.notifyDataSetChanged();
       mChart.setNoDataText("你还没有记录数据");
       mChart.setNoDataTextColor(Color.WHITE);
       mChart.invalidate();
   }
   /**
    *  配置Chart 基础设置
    * @param mChart 图表
    * @param mLabels x 轴标签
    * @param yMax y 轴最大值
    * @param yMin y 轴最小值
    * @param isShowLegend 是否显示图例
    */

   public static void configChart(CombinedChart mChart, List<String> mLabels, float yMax, float yMin, boolean isShowLegend) {

       mChart.setDrawGridBackground(false);
       mChart.setDrawBorders(false);
       mChart.setScaleEnabled(false);
       mChart.setDragEnabled(true);
       mChart.setNoDataText("");
       // 不显示描述数据
       mChart.getDescription().setEnabled(false);
       mChart.getAxisRight().setEnabled(false);

       Legend legend = mChart.getLegend();
       // 是否显示图例
       if (isShowLegend) {
           legend.setEnabled(true);
           legend.setTextColor(Color.WHITE);
           legend.setForm(Legend.LegendForm.CIRCLE);
           legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
           legend.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
           legend.setOrientation(Legend.LegendOrientation.HORIZONTAL);
           legend.setYEntrySpace(20f);
           //图例的大小
           legend.setFormSize(7f);
           // 图例描述文字大小
           legend.setTextSize(10);
           legend.setXEntrySpace(20f);

       } else {
           legend.setEnabled(false);
       }



       XAxis xAxis = mChart.getXAxis();

       // 是否显示x轴线
       xAxis.setDrawAxisLine(true);
       // 设置x轴线的颜色
       xAxis.setAxisLineColor(Color.parseColor("#4cffffff"));
       // 是否绘制x方向网格线
       xAxis.setDrawGridLines(false);
       //x方向网格线的颜色
       xAxis.setGridColor(Color.parseColor("#30FFFFFF"));

       // 设置x轴数据的位置
       xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
       // 设置x轴文字的大小
       xAxis.setTextSize(12);

       // 设置x轴数据偏移量
       xAxis.setYOffset(5);
       final List<String> labels = mLabels;
       // 显示x轴标签
       IAxisValueFormatter formatter = new IAxisValueFormatter() {

           @Override
           public String getFormattedValue(float value, AxisBase axis) {
               int index = (int) value;
               if (index < 0 || index >= labels.size()) {
                   return "";
               }
               return labels.get(index);
               // return labels.get(Math.min(Math.max((int) value, 0), labels.size() - 1));
           }

       };
       // 引用标签
       xAxis.setValueFormatter(formatter);
       // 设置x轴文字颜色
       xAxis.setTextColor(mChart.getResources().getColor(R.color.char_text_color));
       // 设置x轴每最小刻度 interval
       xAxis.setGranularity(1f);

       YAxis yAxis = mChart.getAxisLeft();
       //设置x轴的最大值
       yAxis.setAxisMaximum(yMax);
       // 设置y轴的最大值
       yAxis.setAxisMinimum(yMin);
       // 不显示y轴
       yAxis.setDrawAxisLine(false);
       // 设置y轴数据的位置
       yAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
       // 不从y轴发出横向直线
       yAxis.setDrawGridLines(false);
       // 是否显示y轴坐标线
       yAxis.setDrawZeroLine(true);
       // 设置y轴的文字颜色
       yAxis.setTextColor(mChart.getResources().getColor(R.color.char_text_color));
       // 设置y轴文字的大小
       yAxis.setTextSize(12);
       // 设置y轴数据偏移量
       //yAxis.setXOffset(30);
       // yAxis.setYOffset(-3);
       yAxis.setXOffset(15);
       // yAxis.setGranularity(yGranularity);
       yAxis.setLabelCount(5, false);
       //yAxis.setGranularity(5);//interval

       Matrix matrix = new Matrix();
       // 根据数据量来确定 x轴缩放大倍
       if (mLabels.size() <= 10) {
           matrix.postScale(1.0f, 1.0f);
       } else if (mLabels.size() <= 15) {
           matrix.postScale(1.5f, 1.0f);
       } else if (mLabels.size() <= 20) {
           matrix.postScale(2.0f, 1.0f);
       } else {
           matrix.postScale(3.0f, 1.0f);
       }

       // 在图表动画显示之前进行缩放
       mChart.getViewPortHandler().refresh(matrix, mChart, false);
       // x轴执行动画
       mChart.animateX(500);

   }

   /**
    * 初始化数据
    *
    * @param chart
    * @param lineDatas
    */

   public static void initData(CombinedChart chart, LineData... lineDatas) {
       CombinedData combinedData = new CombinedData();
       for (LineData lineData : lineDatas) {
           combinedData.setData(lineData);
       }
       chart.setData(combinedData);
       chart.invalidate();
   }

   /**
    * 获取LineDataSet
    *
    * @param entries
    * @param label
    * @param textColor
    * @param lineColor
    * @return
    */

   public static LineDataSet getLineData(List<Entry> entries, String label, @ColorInt int textColor, @ColorInt int lineColor, boolean isFill) {
       LineDataSet dataSet = new LineDataSet(entries, label);
       // 设置曲线的颜色
       dataSet.setColor(lineColor);
       //数值文字颜色
       dataSet.setValueTextColor(textColor);
       // 模式为贝塞尔曲线
       dataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);
       // 是否绘制数据值
       dataSet.setDrawValues(false);
       // 是否绘制圆点
       dataSet.setDrawCircles(true);
       dataSet.setDrawCircleHole(false);
       // 这里有一个坑,当我们想隐藏掉高亮线的时候,MarkerView 跟着不见了
       // 因此只有将它设置成透明色
       dataSet.setHighlightEnabled(true);// 隐藏点击时候的高亮线
       //设置高亮线为透明色
       dataSet.setHighLightColor(Color.TRANSPARENT);

       if (isFill) {
           //是否设置填充曲线到x轴之间的区域
           dataSet.setDrawFilled(true);
           // 填充颜色
           dataSet.setFillColor(lineColor);
       }
       //设置圆点的颜色
       dataSet.setCircleColor(lineColor);
       // 设置圆点半径
       dataSet.setCircleRadius(3.5f);
       // 设置线的宽度
       dataSet.setLineWidth(1f);
       return dataSet;
   }

   /**
    * 获取barDataSet
    * @param entries
    * @param label
    * @param textColor
    * @param lineColor
    * @return
    */

   public static BarDataSet getBarDataSet(List<BarEntry> entries, String label, @ColorInt int textColor, @ColorInt int lineColor) {
       BarDataSet dataSet = new BarDataSet(entries, label);
       dataSet.setBarBorderWidth(5);
       dataSet.setBarShadowColor(lineColor);
       dataSet.setValueTextColor(textColor);
       dataSet.setDrawValues(false);
       return dataSet;
   }

   /**
    * 配置柱状图基础设置
    * @param barChart
    * @param xLabels
    */

   public static void configBarChart(BarChart barChart, final List<String> xLabels) {
       barChart.getDescription().setEnabled(false);//设置描述
       barChart.setPinchZoom(false);//设置按比例放缩柱状图
       barChart.setScaleEnabled(false);
       barChart.setDragEnabled(true);
       barChart.setNoDataText(""); // 没有数据时的提示文案
       //x坐标轴设置
       // IAxisValueFormatter xAxisFormatter = new StringAxisValueFormatter(xAxisValue);//设置自定义的x轴值格式化器
       XAxis xAxis = barChart.getXAxis();//获取x轴
       xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);//设置X轴标签显示位置
       xAxis.setDrawGridLines(false);//不绘制格网线
       xAxis.setGranularity(1f);//设置最小间隔,防止当放大时,出现重复标签。
       // 显示x轴标签
       IAxisValueFormatter formatter = new IAxisValueFormatter() {

           @Override
           public String getFormattedValue(float value, AxisBase axis) {
               return xLabels.get(Math.min(Math.max((int) value, 0), xLabels.size() - 1));
           }

       };
       xAxis.setValueFormatter(formatter);
       xAxis.setTextSize(10);//设置标签字体大小
       xAxis.setTextColor(barChart.getResources().getColor(R.color.char_text_color));
       xAxis.setAxisLineColor(Color.parseColor("#4cffffff"));
       xAxis.setLabelCount(xLabels.size());//设置标签显示的个数

       //y轴设置
       YAxis leftAxis = barChart.getAxisLeft();//获取左侧y轴
       leftAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);//设置y轴标签显示在外侧
       leftAxis.setAxisMinimum(0f);//设置Y轴最小值
       leftAxis.setDrawGridLines(false);
       leftAxis.setDrawLabels(true);//禁止绘制y轴标签
       leftAxis.setDrawAxisLine(false);//禁止绘制y轴
       leftAxis.setAxisLineColor(Color.parseColor("#4cffffff"));
       leftAxis.setTextColor(barChart.getResources().getColor(R.color.char_text_color));
       leftAxis.setValueFormatter(new IAxisValueFormatter() {
           @Override
           public String getFormattedValue(float value, AxisBase axis) {
               return ((int) (value * 100)) + "%";
           }
       });

       barChart.getAxisRight().setEnabled(false);//禁用右侧y轴
       barChart.getLegend().setEnabled(false);
       //图例设置
      /* Legend legend = barChart.getLegend();
       legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER);//图例水平居中
       legend.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);//图例在图表上方
       legend.setOrientation(Legend.LegendOrientation.HORIZONTAL);//图例的方向为水平
       legend.setDrawInside(false);//绘制在chart的外侧
       legend.setDirection(Legend.LegendDirection.LEFT_TO_RIGHT);//图例中的文字方向

       legend.setForm(Legend.LegendForm.SQUARE);//图例窗体的形状
       legend.setFormSize(0f);//图例窗体的大小
       legend.setTextSize(16f);//图例文字的大小*/

       //legend.setYOffset(-2f);


       Matrix matrix = new Matrix();
       // 根据数据量来确定 x轴缩放大倍
       if (xLabels.size() <= 10) {
           matrix.postScale(1.0f, 1.0f);
       } else if (xLabels.size() <= 15) {
           matrix.postScale(1.5f, 1.0f);
       } else if (xLabels.size() <= 20) {
           matrix.postScale(2.0f, 1.0f);
       } else {
           matrix.postScale(3.0f, 1.0f);
       }
       barChart.getViewPortHandler().refresh(matrix, barChart, false);
       barChart.setExtraBottomOffset(10);//距视图窗口底部的偏移,类似与paddingbottom
       barChart.setExtraTopOffset(30);//距视图窗口顶部的偏移,类似与paddingtop
       barChart.setFitBars(true);//使两侧的柱图完全显示
       barChart.animateX(1500);//数据显示动画,从左往右依次显示
   }

   /**
    * 初始化柱状图图表数据
    * @param chart
    * @param entries
    * @param title
    * @param barColor
    */

   public static void initBarChart(BarChart chart, List<BarEntry> entries, String title, @ColorInt int barColor) {
       BarDataSet set1 = new BarDataSet(entries, title);
       set1.setValueTextColor(Color.WHITE);
       set1.setColor(barColor);
       ArrayList<IBarDataSet> dataSets = new ArrayList<>();
       dataSets.add(set1);

       BarData data = new BarData(dataSets);
       data.setValueTextSize(10f);
       // 设置bar的宽度,但是点很多少的时候好像没作用,会拉得很宽
       data.setBarWidth(0.1f);
       // 设置value值 颜色
       data.setValueTextColor(Color.WHITE);
       //设置y轴显示的标签
       data.setValueFormatter(new IValueFormatter() {
           @Override
           public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
               return ((int) (value * 100)) + "%";
           }
       });


       chart.setData(data);
       chart.invalidate();
   }
}
最终使用

最终,调用工具类的三个方法,三行代码就ok :

// 1.配置基础图表配置
MPChartUtils.configChart(mWeightChart, xLabels, maxWeight, minWeight, true);
// 2,获取数据Data,这里有2条曲线
LineDataSet tartgetDataSet = MPChartUtils.getLineData(targetEntries, "目标体重", Color.WHITE, Color.WHITE, false);
LineDataSet lineDataSet = MPChartUtils.getLineData(weightEntries, "当前体重", Color.WHITE, getResources().getColor(R.color.chart_dot_color), false);
//  3,初始化数据并绘制  
MPChartUtils.initData(mWeightChart, new LineData(lineDataSet, tartgetDataSet));