前言

图表是一种以简单方式显示信息的图形,通常使用直线和曲线来显示金额。 JJFreeChart 由 David Gilbert 于 2000 年创立。如今,JFreeChart 是 Java 开发人员中使用最广泛的图表库。

JFreeChart 允许创建各种交互式和非交互式图表;可以广泛地定制; 它允许修改图表项目的颜色和绘制,图例,线条或标记的样式。 它会自动绘制轴刻度和图例。可以创建折线图,条形图,面积图,散点图,饼图,甘特图和各种专用图,例如风向图或气泡图。它支持多种输出格式,包括 PNG,JPEG,PDF 和 SVG。

相关jar包:JFreeChart绘图包-Java文档类资源-CSDN下载

类级结构构解释了库中的各种类如何相互交互以创建各种类型的图表。下图为JFreeChart的类级结构:

Units Description
File具有用户输入的源,用于在文件中创建数据集。
Database具有用户输入的源,用于在数据库中创建数据集。
Create Dataset接受数据集并将数据集存储到数据集对象中。
General Dataset这种类型的数据集主要用于饼图。
Category Dataset此类数据集用于条形图、折线图等。
Series Dataset这种类型的数据集用于存储一系列数据和构建折线图。
Series Collection Dataset将不同类别的系列数据集添加到系列集合数据集中。这种类型的数据集用于 XY 线图。
Create Chart这是为创建最终图表而执行的方法。
Frame/Image该图显示在一个Swing框架或创建映像。

一、快速绘图教程

1. 折线图

package plot;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;

public class Example {
	public static void main(String[] args) {

		// 创建数据
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		dataset.addValue(15, "schools", "1970");
		dataset.addValue(30, "schools", "1980");
		dataset.addValue(60, "schools", "1990");
		dataset.addValue(120, "schools", "2000");
		dataset.addValue(240, "schools", "2010");
		dataset.addValue(300, "schools", "2020");
		dataset.addValue(320, "schools", "2022");

		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createLineChart(
				"Example", // 图标题
				"Year", // x轴标题
				"Schools Count", // y轴标题
				dataset, //数据集
				PlotOrientation.VERTICAL, //图表方向
				false, true, false);


		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
	}

}

2. 条形图

package plot;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;

public class Example {
	public static void main(String[] args) {

		// 创建数据
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		dataset.addValue(1.0, "A", "Ⅰ");
		dataset.addValue(3.0, "A", "Ⅱ");
		dataset.addValue(5.0, "A", "Ⅲ");
		dataset.addValue(5.0, "A", "Ⅳ");
		dataset.addValue(5.0, "B", "Ⅰ");
		dataset.addValue(6.0, "B", "Ⅱ");
		dataset.addValue(10.0, "B", "Ⅲ");
		dataset.addValue(4.0, "B", "Ⅳ");

		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createBarChart(
				"Example", // 图标题
				"Category",            
		         "Score",            
		         dataset,          
		         PlotOrientation.VERTICAL,           
		         true, true, false);

		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
	}

}

package plot;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;

public class Example {
	public static void main(String[] args) {

		// 创建数据
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		dataset.addValue(1.0, "A", "Ⅰ");
		dataset.addValue(3.0, "A", "Ⅱ");
		dataset.addValue(5.0, "A", "Ⅲ");
		dataset.addValue(5.0, "A", "Ⅳ");
		dataset.addValue(5.0, "B", "Ⅰ");
		dataset.addValue(6.0, "B", "Ⅱ");
		dataset.addValue(10.0, "B", "Ⅲ");
		dataset.addValue(4.0, "B", "Ⅳ");

		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createBarChart3D(
				"Example", // 图标题
				"Category", 
				"Score", 
				dataset, 
				PlotOrientation.VERTICAL, 
				true, true, false);

		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
	}

}

3. 饼状图

package plot;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;

public class Example {
	public static void main(String[] args) {

		// 创建数据
		DefaultPieDataset dataset = new DefaultPieDataset();
		dataset.setValue("A", 20);
		dataset.setValue("B", 10);
		dataset.setValue("C", 40);
		dataset.setValue("D", 30);

		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createPieChart(
				"Example", // 图标题
				dataset, // 数据集
				false, true, true);

		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);

	}

}

 

package plot;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;

public class Example {
	public static void main(String[] args) {

		// 创建数据
		DefaultPieDataset dataset = new DefaultPieDataset();
		dataset.setValue("A", 20);
		dataset.setValue("B", 10);
		dataset.setValue("C", 40);
		dataset.setValue("D", 30);

		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createPieChart3D(
				"Example", // 图标题
				dataset, // 数据集
				false, true, true);

		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);

	}

}

4. XY图

package plot;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class Example {
	public static void main(String[] args) {

		// 创建数据
		XYSeries data = new XYSeries("InternetExplorer");
		data.add(1.0, 1.0);
		data.add(2.0, 2.0);
		data.add(3.0, 3.0);
		data.add(4.0, 2.0);
		data.add(5.0, 1.0);
		data.add(6.0, 2.0);
		data.add(6.0, 3.0);
		data.add(7.0, 2.0);
		data.add(8.0, 1.0);
		data.add(9.0, 2.0);
		XYSeriesCollection dataset = new XYSeriesCollection();
		dataset.addSeries(data);

		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createXYLineChart(
				"Example", 
				"X", 
				"Y", 
				dataset, 
				PlotOrientation.VERTICAL, 
				false,true, false);

		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);

	}

}

5. 散点图

package plot;

import java.io.IOException;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class Example {
	public static void main(String[] args) throws IOException {

		// 添加数据
		XYSeriesCollection dataset = new XYSeriesCollection();
		XYSeries series1 = new XYSeries("Series1");
		for (int i = 0; i < 100; i++) {
			series1.add(Math.random()*100, Math.random()*100);
		}
		dataset.addSeries(series1);

		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createScatterPlot(
		        "Example", 
		        "X-Axis", "Y-Axis", dataset);

		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);

	}

}

6. 气泡图

package plot;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.DefaultXYZDataset;

public class ShowExample {
	public static void main(String[] args) {

		// 创建数据
		DefaultXYZDataset dataset = new DefaultXYZDataset();
		double x[] = { 30, 40, 50, 60, 70, 80 };
		double y[] = { 10, 20, 30, 40, 50, 60 };
		double z[] = { 1, 2, 3, 4, 2, 1 };
		double xyz[][] = { x, y, z };
		dataset.addSeries("Series", xyz);

		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createBubbleChart(
		         "AGE vs WEIGHT vs WORK", 
		         "Weight", 
		         "AGE", 
		         dataset, 
		         PlotOrientation.HORIZONTAL, 
		         true, true, false);

		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
	}

}

7. 时序图

package plot;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.SeriesException;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;

public class ShowExample {
	public static void main(String[] args) {

		// 创建数据
		TimeSeries series = new TimeSeries("Random Data");
		Second current = new Second();
		double value = 100.0;
		for (int i = 0; i < 4000; i++) {
			try {
				value = value + Math.random() - 0.5;
				series.add(current, value);
				current = (Second) current.next();
			} catch (SeriesException e) {
				System.err.println("Error adding to series");
			}
		}
		XYDataset dataset = (XYDataset) new TimeSeriesCollection(series);

		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createTimeSeriesChart(
				"Computing Test", 
				"Seconds", 
				"Value", 
				dataset, 
				false,false, false);

		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);
	}

}

二、常见类与方法

在本章中,我们将讨论一些在JFreeChart库重要的软件包,类和方法。这些软件包,类和方法是最常见的,同时建立了各种使用JFreeChart库图表。

1. ChartFactory 类

ChartFactory是org.jfree.chart包中抽象类。它提供了实用方法的集合,用于生成标准的图表。以下是几个重要方法的列表:

类构造方法

方法描述
ChartFactory() ChartFactory类的默认构造函数。

类方法

S.N.方法 & 描述
1createPieChart(java.lang.String title, PieDataset dataset, boolean legend, boolean tooltips, boolean urls) 此方法使用默认设置创建一个饼图。它返回JFreeChart类型的对象。
2createPieChart3D(java.lang.String title, PieDataset dataset, boolean legend, boolean tooltips, boolean urls) 此方法使用指定的数据集三维/3D饼图。
3createBarChart(java.lang.String title, java.lang.String categoryAxisLabel, java.lang.String valueAxisLabel, CategoryDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls) 参数java.lang.String categoryAxisLabel标签放置在X轴的值。该参数的java.lang.String valueAxisLabel标签放置在Y轴的数值。此方法创建一个条形图。
4createBarChart3D(java.lang.String title, java.lang.String categoryAxisLabel, java.lang.String valueAxisLabel, CategoryDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls) 此方法创建一个柱形图具有3D效果。它返回JFreeChart类型的对象。
5createLineChart(java.lang.String title, java.lang.String categoryAxisLabel, java.lang.String valueAxisLabel, CategoryDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls)

此方法使用默认设置创建一个折线图。

6createLineChart3D(java.lang.String title, java.lang.String categoryAxisLabel, java.lang.String valueAxisLabel, CategoryDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls) 此方法创建一个折线图与3D效果。
7createXYLineChart(java.lang.String title, java.lang.String xAxisLabel, java.lang.String yAxisLabel, XYDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls) 此方法使用默认设置创建基于XYDataset的折线图。

2. ChartFrame 类

ChartFrame类在org.jfree.chart包中,提供所有的帧相关的功能和工具。 ChartFrame类继承自父类,如Frame, Window, Container, Component 类功能。

类构造方法

S.N.构造方法及描述
1ChartFrame (java.lang.Frame String, JfreeChart chart) 它构建一个框架/frame。
2Chart Frame (java.lang.Frame String, JfreeChart chart, boolean scrollpane) 它构建一个框架/frame。

类方法

S.N.构造方法及描述
1getChartPanel() 此方法返回图表面板的框架/frame。

3. ChartPanel 类

org.jfree.chart包中的ChartPanel类用于swing GUI部件,用于显示JfreeChart对象。

类构造方法

S.N.构造方法及描述
1ChartPanel(JFreeChart chart) 此构造一个面板/panel ,显示指定的图表。
2ChartPanel(JFreeChart chart, boolean useBuffer) 这个构造函数构造包含图表的面板/panel。
3ChartPanel(JFreeChart chart, boolean properties, boolean save, boolean print, boolean zoom, boolean tooltips) 此构造一个JFreeChart面板。

类方法

S.N.方法及描述
1setPreferredSize(java.awt.Dimension) 该方法用于java.awt中设置的帧大小。 Dimension类对象作为参数。这个方法是从javax.swing.JComponent中实现。

4. ChartUtilities 类

org.jfree.chart包中的CharUtilites类提供JFreeCharts包括将图表转换成图像文件格式,如PNG,JPEG和创建HTML图像映射方法的实用方法的集合。

类构造函数

S.N.构造方法及描述
1ChartUtilities() 这是类的一个默认构造函数

类方法

S.N.方法及描述
1saveChartAsPNG(java.io.File file, JfreeChart chart, int width, int height) 此方法转换和保存图表为PNG格式指定的文件。
2saveChartAsJPEG(java.io.File file, JfreeChart chart, int width, int height) 此方法转换并保存一个图表,以JPEG格式指定的文件。

5. JFreeChart 类

JFreeChart 类是在org.jfree.chart包的核心类。这个类提供了JFreeChart的方法来创建柱状图,折线图,饼图和XY坐标图,包括时间序列数据。

类构造函数

S.N.构造方法及描述
1JfreeChart(Plot plot) 此构造函数创建基于所提供的节点一个新的图表。
2JfreeChart(java.lang.String title, java.awt.Font titleFont, Plot plot, boolean createLegend) 该构造函数创建一个新的图表给定标题和绘图。
3JfreeChart(java.lang.String title, Plot plot) 该构造函数创建一个新的图表给定标题和绘图。

类方法

S.N.方法及描述
1getXYPlot() 此方法返回节点图表作为XYPlot。使用XYPolt我们可以XY图表做了一些实用操作。

6. PiePlot 类

这个类是org.jfree.chart.plot包的一部分,来自同一个包扩展Plot 类。这个类提供了一些方法来创建饼图块。

类的构造函数

S.N.构造方法及描述
1PiePlot() 它创建了一个新的绘图。
2PiePlot(PieDataset dataset) 它创建了一个绘图,饼图由指定的数据集。

类方法

S.N.方法及描述
1setStartAngle(double angle) 此方法设置起始角度和发送PlotChangeEvent向所有注册的侦听器

7. PiePlot3D 类

PiePlot3D类和PiePlot类在同一个包中的子类。因此,这两个类有相同的功能,PiePlot类只不过是用于创建3D图形。

类的构造函数

S.N.构造方法及描述
1PiePlot3D() 此构造函数创建没有数据集的新实例。
2PiePlot3D(PieDataset dataset) 该构造函数创建一个饼图和使用指定的数据集三维效果。

类方法

S.N.方法及描述
1setForegroundAlpha(float alpha) 它设置alpha透明度并向所有发送PlotChangeEvent注册的侦听器。
2setInteriorGap(double percent) 它设置了内部差距并发送PlotChangeEvent向所有注册的侦听器。这种控制的饼图绘图边缘与绘图区本身(即,其中部分标签显示的区域)之间的空间。这个方法是从父类PiePlot继承。

8. PlotOrientation 类

这是一个串行化类从org.jfree.chart.plot封装,它是用来显示一个二维曲线图的方位。方向可以是垂直的或水平的。它设置Y轴的方向。传统的绘图有一个垂直的Y轴。

字段摘要

S.N.类型字段 & 描述
1PlotOrientationHORIZONTAL 为一个曲线图,其中所述范围轴(Y轴)是水平。
2PlotOrientationVERTICAL 为一个曲线图,其中所述范围轴(Y轴)是垂直的。这个默认的方向。

类方法

S.N.方法及描述
1isHorizontal() 如果这个方向是水平的,此方法返回true,否则返回false。
2isVertical() 如果这个方向是VERTICAL,此方法返回true,否则返回false。

9. XYPlot 类

这在org.jfree.chart.plot包可用一个通用类,并将其用于在(X,Y)对的形式标绘数据。这个曲线图可以从实现XYDataSet接口的任何其它类中使用的数据。 XYPlot利用一个XYItemRenderer的画在图上的每个点。

类的构造函数

S.N.构造方法及描述
1XYPlot() 该构造器没有数据集,无轴,无渲染器创建一个新的XYPlot实例。
2XYPlot(XYDataset dataset,ValueAxis domainAxis,ValueAxis rangeAxis,XYItemRenderer renderer),此构造函数创建一个新的绘图并指定数据集,轴和渲染。

类方法

S.N.方法及描述
1setRenderer(XYItemRenderer renderer) 此方法设置渲染器的主要数据集,并发送更改事件向所有注册的侦听器。

10. NumberAxis 类

这个类是org.jfree.chart.axis封装,它可以访问任意轴的数值数据。当我们设置任何轴的范围为默认值,它根据所述数据的范围配合。但使用NumberAxis,类我们可以设置较低的利润率和定义域和值域轴的上侧边距。

类的构造函数

S.N.构造方法及描述
1NumberAxis( ) 这是NumberAxis一个默认的构造函数。
2NumberAxis( java.lang.String label) 构造函数NumberAxis使用必要的默认值在哪里。

类方法

S.N.方法及描述
1setLowerMargin(double margin) 它为轴心的利润率较低(为轴心范围的百分比),并发送一个AxisChangeEvent所有已注册的侦听器。这个方法是从父类ValueAxis继承。
2setUpperMargin(double margin) 它设置于所述轴的上缘(视轴范围的百分比),并发送一个AxisChangeEvent给所有注册的监听器。这种方法也存在于ValueAxis类。

11. XYLineAndShapeRenderer 类

这是在org.jfree.chart.renderer.xy包下的类,它需要连接数据点与线,并绘制形状,在每个数据点下是可用的。这个渲染器类是专为XYPlot类配合使用。

类的构造函数

S.N.构造和描述
1XYLineAndShapeRenderer() 它创建了一个新的渲染器有两种线条和形状可见。
2XYLineAndShapeRenderer (boolean lines, boolean shapes) 它创建了一个新的渲染与特定的属性。

类方法

S.N.方法及描述
1setSeriesPaint(int series, java.awt.Paint paint) 此方法设置用于一系列的涂料,并发送RendererChangeEvent给所有注册的监听器。这个方法是从AbstratRenderer抽象类从渲染器包中JFreeChart的API。
2setSeriesStroke(int series, java.awt.Stroke stroke) 此方法设置用于一系列的流程,并发送RendererChangeEvent向所有注册的侦听器。这个方法是从AbstratRenderer抽象类,它是这个包的超类。

12. XYItemRenderer通用数据集

这是用于使一个单一的(X,Y)格式项在XYPlot接口。org.Jfree.data.general包其具有类和接口,以定义不同类型的数据集来构造图。

PieDataset

这是作为一个通用的数据集,其中值与键相关联的接口。正如其名称所暗示的,可以使用这个数据集提供数据的饼图。此接口扩展KeyedValues数据集的接口。所有使用此接口的方法取自KeyedValues,Values和数据集的接口。

13. DefaultPieDataset 类

这是一个默认的实现类PieDataset接口。

类的构造函数

S.N.构造函数和描述
1DefaultPieDataset() 该构造函数创建一个新的数据集,初始为空。
2DefaultPieDataset(KeyedValues data) 它从一个KeyedValues实例复制数据创建了一个新的数据集。

类方法

S.N.方法及描述
1setValue(java.lang.Comparable key, double value) 它设置数据值的键,发送DatasetChangeEvent向所有注册的侦听器。
2setValue(java.lang.Comparable key, java.lang.Number value) 它设置数据值的键,发送DatasetChangeEvent向所有注册的侦听器。

14. SeriesException 类

这是一个异常类。它会引发发生在时间序列中数据集的数据的异常。异常是引发上的重复或无效数据的次数。时间序列不能与重复应用,格式必须是有效的。

15. DefaultCategoryDataset

这是一个默认的实现类CategoryDataset接口。

类的构造函数

S.N.构造函数及描述
1DefaultCategoryDataset() 此构造函数创建新的空数据集。

类方法

S.N.方法及描述
1addValue(double value, java.lang.Comparable rowKey, java.lang.Comparable columnKey) 这种方法增加了一个值,以使用可比的键表。
2addValue(java.lang.Number value, java.lang.Comparable rowKey, java.lang.Comparable columnKey) 这种方法增加了一个值的表。
3setValue(double value, java.lang.Comparable rowKey, java.lang.Comparable columnKey) 此方法添加或在表中更新的值,并发送aDatasetChangeEvent给所有注册的监听器。
4setValue(java.lang.Number value, java.lang.Comparable rowKey, java.lang.Comparable columnKey) 此方法添加或在表中更新的值,并发送DatasetChangeEvent给所有注册的监听器。

参见JFreeChart的API,用于各种其他方法和字段的详细信息。

16. 序列数据集

系列数据集用于XY图表。该软件包是org.Jfree.data.xy,其中包含类和属于XY图表接口。核心接口是XYDataset。

XYDataset

这是通过该数据中的(X,Y)的项目的形式可被访问的接口。正如其名称所提示的,可以使用这个数据集服务XY图表。一些在这个接口中的方法都取自SeriesDateset接口。

XYZDataset

这是通过该数据的形式(x,y,z)的项目可被访问的接口。正如其名称所暗示的,可以使用这个数据集服务XYZ图。一些在这个接口中的方法都取自SeriesDateset。

XYSeries

这是一类,它代表了在所述形式的零个或多个数据项(x,y)的序列。默认情况下,该系列中的数据项都按升序排列由x值,并重复允许的x值。无论是排序和复制缺省值可以在构造函数中被改变。 Y值可以表示为空值代表缺失值。

类构造函数

S.N.构造函数描述
1XYSeries(java.lang.Comparable key) 该构造函数创建一个新的空系列。
2XYSeries(java.lang.Comparable key, boolean autoSort) 它构造一个新的空系列,具有自动排序标志集的请求,并且重复的值是允许的。
3XYSeries(java.lang.Comparable key, boolean autoSort, boolean allowDuplicateXValues) 它构造一个新的xy系列不包含任何数据。

类方法

S.N.方法描述
1add(double x, double y) 这种方法增加了数据项成系列。

在上述方法中使用的教程例子。如果想了解其余的方法和字段,请参考JFreeChart的API。

XYSeriesCollection

XYSeriesCollection类有类似父类AbstractIntervelDataset,AbstractXYDatset,AbstractSeriesDataset和AbstractDataset。一些在这个类中的方法属于这个类的父类。

类的构造函数

S.N.构造函数描述
1XYSeriesCollection() 它构造一个空的数据集。
2XYSeriesCollection(XYSeries xyseries)它构建了一个数据集,并用一个系列的填充。

类方法

S.N.方法及描述
1addSeries(XYSeries series) 这种方法增加了一系列的收集和发送DatasetChangeEvent向所有注册的侦听器。

参见JFreeChart的API其余的方法和字段。

Default XYZDataset :

DefaultXYZDataset类都有父类,如AbstractIntervelDataset,AbstractXYDatset,AbstractSeriesDataset,AbstractDataset和AbstractXYZDataset。一些在这个类中的方法属于这一类的父类。

类的构造函数

S.N.构造方法及描述
1DefaultXYZDataset() 它构造一个空的数据集。

类方法

S.N.方法及描述
1addSeries(java.lang.Comparable seriesKey, double[ ][ ] data ) 该方法增加了一系列的收集和发送DatasetChangeEvent向所有注册的侦听器。

请参考JFreeChart的API,其余的方法和字段。

JFreeCharts的时间序列

该软件包是org.jfree.data.time。该软件包包含用于时间相关的数据的类和接口。

TimeSeries :

此类表示数据项的期值的形式,其中一段是RegularTimePeriod抽象类,如时间,日,小时,分钟和秒类的一些实例序列。

类的构造函数

S.N.构造方法及描述
1TimeSeries(java.lang.Comparable name) 它创建新的空系列。
2TimeSeries(java.lang.Comarable name, java.lang.String domain, java.lang.Strin range) 它会创建一个不包含任何数据的新的时间序列。

类方法

S.N.方法及描述
1add(RegularTimePeriod period,double value) 该方法增加了一个新的数据项用以串联。

其余的方法和字段参见JFreeChart的API。

TimeSeriesCollection :

这是作为时间序列的对象的集合的类。这个类实现了XYDataset接口,以及它扩展了IntervelXYDataset接口。这使得它可以方便地收集序列数据对象。

类的构造函数

S.N.构造方法及描述
1TimeSeriesCollection() 它构造一个空的数据集,绑在默认时区。
2TimeSeriesCollection(TimeSeries series) 它构造一个包含单个系列(更多可添加),绑在默认时区的数据集。
3TimeSeriesCollection(TimeSeries series, java.util.TimeZone zone) 它构造包含单个系列(更可添加),绑定到特定的时间段的数据集。
4TimeSeriesCollection(java.util.TimeZone zone) 它构造一个空的数据集时,绑定到特定的时间区。

类方法

S.N.方法及描述
1addSeries(TimeSeries series) 方法增加了一系列的收集和发送DatasetChangeEvent向所有注册的侦听器。

其余的方法和字段请参考JFreeChart的API。

Second 类:

这个类表示一个特定的日子一秒钟。这个类是不可变的,这是对所有RegularTimePeriod子类的要求。

类的构造函数

S.N.构造函数及描述
1Second() 它构造一个新的Second,基于系统的日期/时间。
2Second(java.util.Date time) 它构造从指定日期/时间和默认时区的新实例。
3Second(java.util.Date time, java.util.TimeZone zone, java.util.Locale locale) 它创建基于所提供的时间和时区的新的Second对象。
4Second(int second, int minute, int hour, int day, int month, int year)它创建了一个新的Second对象。
5Second(int second, Minute minute) 它构建了一个新的Second。

类方法

S.N.方法及描述
1getSecond() 它返回分钟和秒。
2next() 它返回当前的下一秒。

其余的方法和字段请参考JFreeChart的API。

JFreeCharts 中的帧:

该软件包是org.jfree.ui。这是包所属JFreeChart的JCommons的API。它包含用于创建预配置的图表框架的实用程序类。

ApplicationFrame :

这是用于创建简单的应用程序的主框架的基类。帧监听窗口关闭事件,并作出反应,关闭JVM。这是很好的小型演示应用。对于企业应用程序,需要使用一些更稳健的东西。在这个类中的主要核心方法取自Component, Container, Window, Frame 和Jframe类。

类构造函数

S.N.构造方法及描述
1ApplicationFrame(java.lang.String title) 它会创建一个字符串标题的应用程序框架。

这个类有助于创建AWT框架。这就是为什么我们使用这个类作为父类在本教程中的例子的原因。

其采取父类的方法用于打开一个框架,关闭一个框架,改变大小,改变背景或前景颜色和监听器。

RefineryUtilities :

这是关于用户界面的工具方法的类的集合。

类方法

S.N.方法及描述
1centerFrameOnScreen(java.awt.Window frame) 它定位在屏幕的中间的指定帧。

在上述方法中使用的教程例子以外的类,方法和字段参见JFreeChart的API。

三、高级用法

1. 图形的展示与保存

package plot;

import java.io.File;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;

public class Example {
	public static void main(String[] args) throws IOException {
		
		// 创建数据
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
	    dataset.addValue( 15 , "schools" , "1970" );
	    dataset.addValue( 30 , "schools" , "1980" );
	    dataset.addValue( 60 , "schools" , "1990" );
	    dataset.addValue( 120 , "schools" , "2000" );
	    dataset.addValue( 240 , "schools" , "2010" ); 
	    dataset.addValue( 300 , "schools" , "2014" );
	    
	    // 创建JFreeChart对象
	    JFreeChart chart = ChartFactory.createLineChart(
	         "Example",  // 图标题
	         "Year",  // x轴
	         "Schools Count",// y轴
	         dataset,
	         PlotOrientation.VERTICAL,
	         false,true,false);
	    
	    // 保存到本地(PNG或者JPEG格式)
	    File f = new File( "chart.png" ); 
	    ChartUtilities.saveChartAsPNG(f ,chart, 800 ,400);
        // 保存为矢量图形(需要借助JFreeSVG包)
        SVGGraphics2D g2 = new SVGGraphics2D(640, 480);
        chart.draw(g2, new Rectangle(640, 480));
        File f = new File("SVGBarChartDemo.svg");
        SVGUtils.writeToSVG(f, g2.getSVGElement());

	    // 利用swing进行展示
	    JPanel jPanel = new ChartPanel(chart);
        JFrame frame = new JFrame("JFreechart Test");
        frame.add(jPanel);
        frame.setBounds(0, 0, 800, 500);
        frame.setVisible(true);

        // 利用awt进行显示
        ChartFrame chartFrame = new ChartFrame("Test", chart);
        chartFrame.pack();
        chartFrame.setVisible(true);      
        
	}
}

2. 通用设置

package plot;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.RectangleEdge;

public class Test {
	public static void main(String[] args) {
		
		
		// 添加数据集
        DefaultCategoryDataset dataSet = new DefaultCategoryDataset();
        dataSet.addValue(3542, "2020年", "第一季度");// Y轴-图例-X轴
        dataSet.addValue(3692, "2020年", "第二季度");// Y轴-图例-X轴
        dataSet.addValue(8542, "2020年", "第三季度");// Y轴-图例-X轴
        dataSet.addValue(5742, "2020年", "第四季度");// Y轴-图例-X轴

        dataSet.addValue(1242, "2021年", "第一季度");// Y轴-图例-X轴
        dataSet.addValue(2612, "2021年", "第二季度");// Y轴-图例-X轴
        dataSet.addValue(1942, "2021年", "第三季度");// Y轴-图例-X轴
        dataSet.addValue(4612, "2021年", "第四季度");// Y轴-图例-X轴
        
        
        // 主题样式设置
        StandardChartTheme standardChartTheme = new StandardChartTheme("CN"); // 创建主题样式
        standardChartTheme.setExtraLargeFont(new Font("宋体", Font.BOLD, 64)); // 设置标题字体
        standardChartTheme.setRegularFont(new Font("宋体", Font.BOLD, 32)); // 设置图例的字体
        standardChartTheme.setLargeFont(new Font("宋体", Font.BOLD, 20)); // 设置轴向的字体
        standardChartTheme.setChartBackgroundPaint(Color.WHITE);// 设置主题背景色
        ChartFactory.setChartTheme(standardChartTheme);// 应用主题样式

        
        // 定义图表对象
        JFreeChart chart = ChartFactory.createLineChart(
        		// 图表的标题-横轴标题-纵轴标题-数据集
        		"JFreeChart折线图", "销售额", "季度", dataSet, 
        		// 图表方向-图例-工具提示-超链接
        		PlotOrientation.VERTICAL,true, false, false);
        // chart.setTitle(new TextTitle(title[0], new Font("宋书", Font.BOLD, 64)));// 重新设置标题
        // chart.removeLegend();// 是否移除图例
        CategoryPlot plot = (CategoryPlot)chart.getPlot(); // 获得图表显示对象
        plot.setOutlineVisible(false);// 是否显示外边框
        plot.setOutlinePaint(Color.WHITE);// 外边框颜色
        // plot.setOutlineStroke(new BasicStroke(2.f));// 外边框框线粗细
        plot.setBackgroundPaint(Color.WHITE);// 白色背景
        plot.setNoDataMessage("无图表数据");// 无数据提示
        plot.setNoDataMessageFont(new Font("宋体", Font.BOLD, 32));// 提示字体
        plot.setNoDataMessagePaint(Color.RED);// 提示字体颜色

        
        // 图例
        LegendTitle legend = chart.getLegend();// 图例对象
        legend.setPosition(RectangleEdge.BOTTOM);// 图例所在位置(上、下、左、右)
        legend.setVisible(true);// 是否显示图例
        legend.setBorder(2, 0, 0, 2); // 图例上下左右边框粗细
        legend.setItemFont(new Font("宋体", Font.BOLD, 32));// 图例大小
        

        // 网格线
        plot.setDomainGridlinePaint(Color.BLUE);
        plot.setDomainGridlinesVisible(true);// 竖线
        plot.setRangeGridlinePaint(Color.BLACK);
        plot.setRangeGridlinesVisible(true);// 横线

        
        // 横坐标
        CategoryAxis xAxis = plot.getDomainAxis();
        xAxis.setTickLabelFont(new Font("宋体", Font.BOLD, 25));// 设置X轴值字体
        xAxis.setLabelFont(new Font("宋书", Font.BOLD, 32));// 设置X轴标签字体
        xAxis.setAxisLineStroke(new BasicStroke(1f)); // 设置X轴线粗细
        xAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);// 倾斜
        xAxis.setAxisLinePaint(Color.BLACK);// 轴线颜色
        xAxis.setUpperMargin(0.18D);// 右边距
        xAxis.setLowerMargin(0.1D);// 左边距

        
        // 纵坐标
        ValueAxis yAxis = plot.getRangeAxis();
        yAxis.setTickLabelFont(new Font("宋体", Font.BOLD, 25));// 设置y轴字体
        yAxis.setLabelFont(new Font("宋体", Font.BOLD, 32));// 设置X轴标签字体
        yAxis.setAxisLineStroke(new BasicStroke(1f)); // 设置y轴线粗细
        yAxis.setAxisLinePaint(Color.BLACK);// 轴线颜色
        yAxis.setUpperMargin(0.18D);// 上边距
        yAxis.setLowerMargin(0.1D);// 下边距

        
        LineAndShapeRenderer r1 = new LineAndShapeRenderer();
        // 数据标签
        r1.setBaseItemLabelsVisible(true);// 是否显示数据标签
        r1.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());// 数据标签格式
        r1.setSeriesPaint(0, Color.BLUE);
        r1.setBaseShapesFilled(Boolean.TRUE); // 在数据点显示实心的小图标
        r1.setBaseShapesVisible(true); // 设置显示小图标
        r1.setBaseItemLabelFont(new Font("Dialog", Font.BOLD, 12));// 设置数字的字体大小
        r1.setBaseStroke(new BasicStroke(4f));
        // 线条颜色
        r1.setSeriesPaint(0, new Color(204, 232, 207)); 
        r1.setSeriesPaint(1, new Color(0x00, 0xff, 0xff)); 
        r1.setSeriesShapesVisible(0,  false);
        r1.setSeriesShapesVisible(1,  false);
        plot.setDataset(dataSet);
        // 应用以上设置
        plot.setRenderer(r1); 

        // 条形图间距设置
        // BarRenderer r = (BarRenderer) plot.getRenderer();
		// renderer.setItemMargin(0.01);

        
        
        // 显示图表
        ChartFrame chartFrame = new ChartFrame("Test", chart);
        chartFrame.pack();
        chartFrame.setVisible(true);  
	}

}

3. 其他设置

3.1 坐标轴刻度设置

package com.test;

import java.io.File;
import java.io.IOException;

import javax.swing.JFrame;
import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class Test {

	public static void main(String[] args) throws IOException {
		
		// 创建数据
		final XYSeries data = new XYSeries( "InternetExplorer" );
		data.add( 1.0 , 4.0 );          
		data.add( 2.0 , 5.0 );          
		data.add( 3.0 , 4.0 ); 
		data.add( 4.0 , 5.0 );          
		data.add( 5.0 , 4.0 );          
		data.add( 6.0 , 5.0 );
		data.add( 6.0 , 4.0 ); 
		data.add( 7.0 , 5.0 ); 
		data.add( 8.0 , 4.0 ); 
		data.add( 9.0 , 5.0 ); 
		final XYSeriesCollection dataset = new XYSeriesCollection( );        
		dataset.addSeries(data);
	    
	    // 创建JFreeChart对象
	    JFreeChart chart = ChartFactory.createXYLineChart(
	    		"Example", "X", "Y", dataset,
	    		PlotOrientation.VERTICAL,
	    		false, true, false);

	    // 设置坐标轴刻度间距
	    XYPlot plot = (XYPlot) chart.getPlot();
	    NumberAxis xAxis = (NumberAxis) plot.getDomainAxis();  
	    xAxis.setTickUnit(new NumberTickUnit(2));
	    
	    // 保存到本地
	    File lineChart = new File( "1.png" ); 
	    ChartUtilities.saveChartAsPNG(lineChart ,chart, 1000 ,500);

	}

}

四、其他图表

1. 时间序列图

 

package plot;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.time.Month;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.ui.TextAnchor;

import javax.swing.*;
import java.awt.*;
import java.text.SimpleDateFormat;

public class TimeSeriesChart {
    private TimeSeriesChart() {

        // A网站的访问量统计
        @SuppressWarnings("deprecation")
		TimeSeries timeSeries1 = new TimeSeries("A", Month.class);
        // 添加数据
        timeSeries1.add(new Month(1, 2016), 154);
        timeSeries1.add(new Month(2, 2016), 256);
        timeSeries1.add(new Month(3, 2016), 312);
        timeSeries1.add(new Month(4, 2016), 489);
        timeSeries1.add(new Month(5, 2016), 563);
        timeSeries1.add(new Month(6, 2016), 555);
        timeSeries1.add(new Month(7, 2016), 359);
        timeSeries1.add(new Month(8, 2016), 291);
        timeSeries1.add(new Month(9, 2016), 123);
        timeSeries1.add(new Month(10, 2016), 438);
        timeSeries1.add(new Month(11, 2016), 286);

        // A网站的访问量统计
        TimeSeries timeSeries2 = new TimeSeries("A", Month.class);
        // 添加数据
        timeSeries2.add(new Month(1, 2016), 124);
        timeSeries2.add(new Month(2, 2016), 326);
        timeSeries2.add(new Month(3, 2016), 12);
        timeSeries2.add(new Month(4, 2016), 567);
        timeSeries2.add(new Month(5, 2016), 546);
        timeSeries2.add(new Month(6, 2016), 123);
        timeSeries2.add(new Month(7, 2016), 222);
        timeSeries2.add(new Month(8, 2016), 545);
        timeSeries2.add(new Month(9, 2016), 56);
        timeSeries2.add(new Month(10, 2016), 543);
        timeSeries2.add(new Month(11, 2016), 221);

        // 定义时间序列的集合
        TimeSeriesCollection lineDataset = new TimeSeriesCollection();
        lineDataset.addSeries(timeSeries1);
        lineDataset.addSeries(timeSeries2);


//         JFreeChart chart = ChartFactory.createXYStepChart("Time line graph", "M", "F", xySeriesCollection, PlotOrientation.HORIZONTAL, false, false, false);
        JFreeChart chart = ChartFactory.createTimeSeriesChart("Time line graph", "M", "F", lineDataset, false, false, false);
        //设置主标题
        chart.setTitle(new TextTitle("A,B网站访问量统计对比图"));
        //设置子标题
        TextTitle subtitle = new TextTitle("2016年度", new Font("宋体", Font.BOLD, 12));
        chart.addSubtitle(subtitle);

        chart.setAntiAlias(true);

        //设置时间轴的范围。
        XYPlot plot = (XYPlot) chart.getPlot();
        DateAxis dateaxis = (DateAxis) plot.getDomainAxis();
        dateaxis.setDateFormatOverride(new SimpleDateFormat("M"));
        dateaxis.setTickUnit(new DateTickUnit(DateTickUnit.MONTH, 2));

        //设置曲线是否显示数据点
        XYLineAndShapeRenderer xylinerenderer = (XYLineAndShapeRenderer) plot.getRenderer();
        xylinerenderer.setBaseShapesVisible(true);

        //设置曲线显示各数据点的值
        XYItemRenderer xyitem = plot.getRenderer();
        xyitem.setBaseItemLabelsVisible(true);
        xyitem.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER));
        xyitem.setBaseItemLabelGenerator(new StandardXYItemLabelGenerator());
        xyitem.setBaseItemLabelFont(new Font("Dialog", Font.BOLD, 12));
        plot.setRenderer(xyitem);

        JPanel jPanel = new ChartPanel(chart);
        JFrame frame = new JFrame("JFreechart Test");
        frame.add(jPanel);
        frame.setBounds(0, 0, 800, 600);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        TimeSeriesChart timeSeriesChart = new TimeSeriesChart();
    }
}

2. XY阶梯面积图

package plot;

import java.awt.Color;
import java.io.IOException;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class Example {
	public static void main(String[] args) throws IOException {

		// 创建XYSeriesCollection对象
		XYSeriesCollection dataset = new XYSeriesCollection();
		// 系列一数据
		XYSeries series1 = new XYSeries("Series1");
		series1.add(2, 4);
		series1.add(3, 6);
		series1.add(5, 2);
		series1.add(8, 5);
		series1.add(1, 8);

		// 系列二数据
		XYSeries series2 = new XYSeries("Series2");
		series2.add(5, 6);
		series2.add(9, 5);
		series2.add(10, 9);
		series2.add(18, 11);
		series2.add(15, 18);
		// 添加到数据集
		dataset.addSeries(series1);
		dataset.addSeries(series2);

		// 创建JFreeChart对象
		JFreeChart chart = ChartFactory.createXYStepAreaChart("XY Step Area Chart", // Chart Title
				"X-Axis", // X-Axis Label
				"Y-Axis", // Y-Axis Label
				dataset);

		XYPlot plot = (XYPlot) chart.getPlot();
		plot.setBackgroundPaint(new Color(229, 150, 97, 60));

		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);

	}

}

3. 条形图与折线图结合

package plot;

import java.io.IOException;

import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.data.category.DefaultCategoryDataset;

public class ShowExample {
	public static void main(String[] args) throws IOException {

		// 创建数据
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		dataset.addValue(1.0, "A", "Ⅰ");
		dataset.addValue(3.0, "A", "Ⅱ");
		dataset.addValue(5.0, "A", "Ⅲ");
		dataset.addValue(5.0, "A", "Ⅳ");
		dataset.addValue(5.0, "B", "Ⅰ");
		dataset.addValue(6.0, "B", "Ⅱ");
		dataset.addValue(10.0, "B", "Ⅲ");
		dataset.addValue(4.0, "B", "Ⅳ");

		// 创建CategoryPlot对象
		CategoryPlot plot = new CategoryPlot();

		// 添加第一个数据集并渲染为line
		CategoryItemRenderer lineRenderer = new LineAndShapeRenderer();
		plot.setDataset(0, dataset);
		plot.setRenderer(0, lineRenderer);

		// 添加第二个数据集并渲染为线条bar
		CategoryItemRenderer baRenderer = new BarRenderer();
		plot.setDataset(1, dataset);
		plot.setRenderer(1, baRenderer);

		// 设置坐标轴
		plot.setDomainAxis(new CategoryAxis("Time"));
		plot.setRangeAxis(new NumberAxis("Value"));

		// 创建JFreeChart对象
		JFreeChart chart = new JFreeChart(plot);

		// 利用awt进行显示
		ChartFrame chartFrame = new ChartFrame("Test", chart);
		chartFrame.pack();
		chartFrame.setVisible(true);

	}

}

参考资料

官网:www.jfree.org

中文JFreeChart教程

英文JFreeChart教程

 JFreeChart | BORAJI.COM

https://www.roseindia.net/chartgraphs/index.shtml

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐