JFreeChart以及Cewolf使用

 
JFreeChart是一组功能强大、灵活易用的Java绘图API,使用它可以生成多种通用性的报表,包括柱状图、饼图、曲线图、甘特图等。它能够用在Swing和Web等中制作自定义的图表或报表,并且得到广泛的应用。本文将通过引领读者学习在JFreeChart中饼图、柱状图和曲线图的进阶应用,来达到熟练使用JFreeChart的目的。
一. 下载与环境配置
1. 下载JFreeChart
JFreeChart是开放源代码的免费软件,但是它的支持文档需要付费才能得到。其 下载地址为:http://sourceforge.net/project/showfiles.php?group_id=154 94,当前最新版本为1. 0. 9。笔者 下载的是1. 0. 9最新版。
说明:1)source目录:为jfreechart的源码目录;
2)lib目录:为包目录,我们需要关注的包为 jfreechart-1. 0. 9. jar、gnujaxp. jar和jcommon-1. 0.12. jar这三个包;
3)根目录下的 jfreechart-1. 0. 9-demo. jar是例子程序,大家双击后可看到其中有很多例子的运行结果。
2. 环境配置
笔者的开发环境如下:
JDK:1.6
MyEclipse:MyEclipse-6. 0M1
Tomcat:6. 0
为了后续的“用JFreeChart创建基于Web的图表”的一个例子的展示,我们在MyEclipse中创建一个名为jfreechart的Web工程。将 下载的JFreeChart1. 0. 9下lib目录下的 jar包拷贝到WebRoot/WEB-INF/lib目录下。另外还需要在web.xml文件中增加如下配置:
<servlet>
<servlet-name>DisplayChart</servlet-name>
<servlet-class>org.jfree.chart.servlet.DisplayChart</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DisplayChart</servlet-name>
<url-pattern>/DisplayChart</url-pattern>
</servlet-mapping>

在WebRoot目录下建立bar目录,用来存放柱状图的各个例子。首先在该目录下建立一个sample1.jsp文件,让我们来看一个简单的柱状图的例子,修改后的sample1.jsp的内容如下所示:

<%@ page contentType="text/html;charset=GBK"%><%@ page import="org.jfree.chart.ChartFactory,
org.jfree.chart.JFreeChart,
org.jfree.chart.plot.PlotOrientation,
org.jfree.chart.servlet.ServletUtilities,
org.jfree.data.category.DefaultCategoryDataset"%><%
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.addValue(61 0, "广州", "猪肉");
dataset.addValue(22 0, "广州", "牛肉");
dataset.addValue(53 0, "广州", "鸡肉");
dataset.addValue(34 0, "广州", "鱼肉");
JFreeChart chart = ChartFactory.createBarChart3D("肉类销量统计图",
"肉类",
"销量",
dataset,
PlotOrientation.VERTICAL,
false,
false,
false);
String filename = ServletUtilities.saveChartAsPNG(chart, 5 00, 3 00, null, session);
String graphURL = request.getContextPath() + "/DisplayChart?filename=" + filename;
%>
<img src="<%= graphURL %>" width=5 00 height=3 00 border= 0 usemap="#<%= filename %>">
在浏览器中输入地址:http://localhost:8 08 0/jfreechart/bar/sample1.jsp,可看到如下柱状图:
面的这个柱状图比较简单,稍显单调,在有些情况下,我们需要用不同颜色来表示不同的种类,或者在种类上标上具体数值,亦或需要加上3D水晶效果。下面让我们来做更深一步的探讨。接下来让我们看一个用不同颜色来表示不通种类的例子。在WebRoot的bar目录下新建sample2.jsp页面,将其代码修改如下:



<%@ page contentType="text/html;charset=GBK"%><%@ page import="org.jfree.chart.ChartFactory,
org.jfree.chart.JFreeChart,
org.jfree.chart.plot.PlotOrientation,
org.jfree.chart.servlet.ServletUtilities,
org.jfree.data.category.CategoryDataset,
org.jfree.data.general.DatasetUtilities"%><%
double[][] data = new double[][] {{131 0,72 0,113 0,44 0}};
String[] columnKeys = {"猪肉", "牛肉","鸡肉", "鱼肉"};
String[] rowKeys = {""};
CategoryDataset dataset = DatasetUtilities.createCategoryDataset(rowKeys, columnKeys, data);
JFreeChart chart = ChartFactory.createBarChart3D("广州肉类销量统计图",
"肉类",
"销量",
dataset,
PlotOrientation.VERTICAL,
true,
false,
false);
String filename = ServletUtilities.saveChartAsPNG(chart, 5 00, 3 00, null, session);
String graphURL = request.getContextPath() + "/DisplayChart?filename=" + filename;
%>
<img src="<%= graphURL %>" width=5 00 height=3 00 border= 0 usemap="#<%= filename %>">
该页面的运行效果如下图所示:




对比该例与前例,可看出createBarChart3D的倒数第三个参数修改成了true,该参数可用来显示下方的: 。上两例我们显示的只是一个城市的肉类销量,有时候我们有对比显示多个城市的不同肉类,只要将上例稍作修改即可。例如要在图中表示广州、深圳、东莞、佛山四个城市的四个肉类的销售情况,只需要将如下三句稍做修改:

double[][] data =newdouble[][] {{131 0}, {72 0}, {113 0}, {44 0}};
String[] rowKeys = {"猪肉", "牛肉","鸡肉", "鱼肉"};
String[] columnKeys = {""};
例如修改成:
double[][] data =newdouble[][] {{131 0, 122 0, 111 0, 1 000},
{72 0, 7 00, 68 0, 64 0},
{113 0, 1 02 0, 98 0, 8 00},
{44 0, 4 00, 36 0, 3 00}};
String[] rowKeys = {"猪肉", "牛肉","鸡肉", "鱼肉"};
String[] columnKeys = {"广州", "深圳", "东莞", "佛山"};

在运行该jsp页面,可看到如下界面:
行效果如下所示:



注意:jfreechart的很多版本不兼容,请大家在运行此例时确认 下载了对应的版本。
四.曲线图
接着我们来介绍曲线图的使用。在笔者日常的开发工作中,曲线图用得最多,它可以用来绘制趋势图、统计分析等。首先我们在WebRoot下建立一个line目录,用来存放曲线图实例的jsp页面。我们在该目录下建立sample1.jsp页面来做一个简单的曲线图的例子。在开始编码前,让我们来看看与画曲线图密切相关的几个类:
1) TimeSeriesCollection
曲线数据的集合。
2) TimeSeries
曲线信息序列。
3) ChartFactory
可以利用该类的createTimeSeriesChart方法来创建曲线的JFreeChart对象。

在下例中,我们显示阿蜜果的blog在2 007年度各月份的访问量情况,修改后的sample1.jsp的内容如下:
<%@ page contentType="text/html;charset=GBK"%>
<%@ page import = "org.jfree.chart.ChartFactory,
org.jfree.chart.JFreeChart,
org.jfree.chart.servlet.ServletUtilities,
org.jfree.chart.title.TextTitle,
org.jfree.data.time.TimeSeries,
org.jfree.data.time.Month,
org.jfree.data.time.TimeSeriesCollection,
java.awt.Font"%>
<%
//访问量统计时间线
TimeSeries timeSeries = new TimeSeries("阿蜜果blog访问量统计", Month.class);
//时间曲线数据集合
TimeSeriesCollection lineDataset = new TimeSeriesCollection();

//构造数据集合
timeSeries.add(new Month(1, 2 007), 112 00);
timeSeries.add(new Month(2, 2 007), 9 000);
timeSeries.add(new Month(3, 2 007), 62 00);
timeSeries.add(new Month(4, 2 007), 82 00);
timeSeries.add(new Month(5, 2 007), 82 00);
timeSeries.add(new Month(6, 2 007), 122 00);
timeSeries.add(new Month(7, 2 007), 132 00);
timeSeries.add(new Month(8, 2 007), 83 00);
timeSeries.add(new Month( 9, 2 007), 124 00);
timeSeries.add(new Month(1 0, 2 007), 125 00);
timeSeries.add(new Month(11, 2 007), 136 00);
timeSeries.add(new Month(12, 2 007), 125 00);

lineDataset.addSeries(timeSeries);
JFreeChart chart = ChartFactory.createTimeSeriesChart("访问量统计时间线", "月份", "访问量", lineDataset, true, true, true);

//设置子标题
TextTitle subtitle = new TextTitle("2 007年度", new Font("黑体", Font.BOLD, 12));
chart.addSubtitle(subtitle);
//设置主标题
chart.setTitle(new TextTitle("阿蜜果blog访问量统计", new Font("隶书", Font.ITALIC, 15)));
chart.setAntiAlias(true);

String filename = ServletUtilities.saveChartAsPNG(chart, 5 00, 3 00, null, session);
String graphURL = request.getContextPath() + "/DisplayChart?filename=" + filename;
%>
<img src="<%= graphURL %>"width=5 00 height=3 00 border= 0 usemap="#<%= filename %>">
运行后的曲线效果如下图所示:




有时我们需要显示各数据点及其数值,这是我们需要对上例进行一点改动,在JFreeChart chart = ChartFactory.createTimeSeriesChart……后,TextTitle subtitle = new TextTitle……前加上如下的代码:
XYPlot plot = (XYPlot) chart.getPlot();
XYLineAndShapeRenderer xylineandshaperenderer = (XYLineAndShapeRenderer)plot.getRenderer();
//设置网格背景颜色
plot.setBackgroundPaint(Color.white);
//设置网格竖线颜色
plot.setDomainGridlinePaint(Color.pink);
//设置网格横线颜色
plot.setRangeGridlinePaint(Color.pink);
//设置曲线图与xy轴的距离
plot.setAxisOffset(new RectangleInsets( 0D, 0D, 0D, 1 0D));
//设置曲线是否显示数据点
xylineandshaperenderer.setBaseShapesVisible(true);
//设置曲线显示各数据点的值
XYItemRenderer xyitem = plot.getRenderer();
xyitem.setBaseItemLabelsVisible(true);
xyitem.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_LEFT));
xyitem.setBaseItemLabelGenerator(new StandardXYItemLabelGenerator());
xyitem.setBaseItemLabelFont(new Font("Dialog", 1, 14));
plot.setRenderer(xyitem);

该例的运行效果如下:




五. 总结
本文通过详尽的实例讲述了如何利用JFreeChart开发常用的柱状图、饼图和曲线图。从这些实例中可以看出,JFreeChart是我们开发图表或报表的理想选择,它简单易用,并且容易理解,是我们开发的利刃。
1


介绍:Cewolf
写在JSP页面中的Cewolf,能用于基于web工程的Servlet/JSP,来制作复杂的统计图表.它提供几乎图的所有特征,象颜色,线条,图形等等.所以能够在不写任何JAVA代码的情况下让JSP页面显示图表.
Cewolf是基于JFreechart的,利用JFreechart的绘制引擎,将最终的图片写入客户端.在服务器端不会创建任何文件.一切都是基于轻量级的会话对象和动态的数据分析的.
Cewolf有一个单例的servlet,这个servlet用来处理图的绘画和标签库时,用这个标签库将在JSP页面的图的定义转成HTML img tag,servlet按HTML img tag绘制想要的图片送给客户端.
特点:
1:免费开源
2:可跑于J2EE compliant server or servlet container
3:图标签库特征: 1:jsp不需要编写java代码
2:由xml编写
4:图类型丰富: Line [XY]
[3D] Pie
[3D] Horizonal Bar
[3D] Vertical [XY] Bar
[3D] Stacked Vertical Bar
Area [XY]
Scatter Plot
Candlestick
High Low
Gantt
Overlaid
Combined
例子:在JSP中写下以下代码来表示一个图
<cewolf:chart
id="XYChart"
type="xy"
title="XYChart"
<cewolf:gradient>
<cewolf:point x=" 0" y=" 0" color="#FFFFFF"/>
<cewolf:point x=" 0" y="3 00" color="#C8C8C8"/>
</cewolf:gradient>
<cewolf:data>
<cewolf:producer id="xyData"/>
</cewolf:data>
</cewolf:chart>
<cewolf:img chartid="XYChart" renderer="cewolf" width="4 00" height="3 00"/>图示:
第一步:准备
下载标签库 jar包:http://cewolf.sourceforge.net/new/index.html
jar包下/Lib文件内容放在工程的/WEB-INF/lib 下面,/Lib文件内容:
jfreechart-*-demo. jar
jfreechart-*. jar
jcommon-*. jar
可以从jfreechart包里取的。也可以用自带的
commons-logging. jar
cewolf. jar
batik-xml. jar
batik-util. jar
batik-svggen. jar
batik-dom. jar
batik-awt-util. jar
Mozilla浏览器需要/example目录下的overlib.js,放入webapps根目录下。
在用Cewolf标签出现问题时,例如:"No Tags" is displayed in your containers console。你可以将cewolf.tld或cewolf-1.1.tld 文件放入你在WEB项目根目录下的新建的文件夹中,就能在JSP中使用这些标签
第二步:生成一个DatasetProducer
因为Cewolf使用MVC (Model-View-Control)处理显示在图中的数据,而这些数据是于定义在JSP页面中的VIEW层分离开的。为了给图提供正确的数据,你必须生成一个实现了de.laures.cewolf.DatasetProducer接口的对象,每次重画一个新的图的时候这个对象将被用到。
下面请看一个DatasetProducer实现的例子。

Java代码 复制代码
  1. package de.laures.cewolf.example;   
  2. import java.io.Serializable;   
  3. import java.util.Date;   
  4. import java.util.Map;   
  5. import org.apache.commons.logging.Log;   
  6. import org.apache.commons.logging.LogFactory;   
  7. import org.jfree.data.category.CategoryDataset;   
  8. import org.jfree.data.category.DefaultCategoryDataset;   
  9. import de.laures.cewolf.DatasetProduceException;   
  10. import de.laures.cewolf.DatasetProducer;   
  11. import de.laures.cewolf.links.CategoryItemLinkGenerator;   
  12. import de.laures.cewolf.tooltips.CategoryToolTipGenerator;   
  13. /**   
  14. * An example data producer.  
  15. * @author  Guido Laures   
  16. */  
  17. public class PageViewCountData implements DatasetProducer,    
  18. CategoryToolTipGenerator,    
  19. CategoryItemLinkGenerator,    
  20. Serializable {   
  21.     private static final Log log = LogFactory.getLog(PageViewCountData.class);   
  22.     // These values would normally not be hard coded but produced by   
  23. // some kind of data source like a database or a file   
  24. private final String[] categories = { "mon",   
  25. "tue",    
  26. "wen",    
  27. "thu",   
  28. "fri",   
  29. "sat",    
  30. "sun"};   
  31. private final String[] seriesNames = { "cewolfset.jsp",   
  32. "tutorial.jsp",    
  33. "testpage.jsp",   
  34. "performancetest.jsp"};   
  35.  /**  
  36. *  Produces some random data.  
  37. */  
  38. public Object produceDataset(Map params)    
  39. throws DatasetProduceException {   
  40. log.debug("producing data.");   
  41. DefaultCategoryDataset dataset = new DefaultCategoryDataset(){   
  42. /**  
  43. * @see java.lang.Object#finalize()  
  44. *当垃圾回收器确定不存在对该对象的更多引用时,  
  45. *由对象的垃圾回收器调用此方法  
  46. */  
  47. protected void finalize() throws Throwable {   
  48. super.finalize();   
  49. log.debug(this +" finalized.");   
  50. }   
  51. };   
  52. for (int series = <SPAN class=hilite2>0</SPAN>; series < seriesNames.length; series ++) {   
  53. int lastY = (int)(Math.random() * 1<SPAN class=hilite2>0</SPAN><SPAN class=hilite2>0</SPAN><SPAN class=hilite2>0</SPAN> + 1<SPAN class=hilite2>0</SPAN><SPAN class=hilite2>0</SPAN><SPAN class=hilite2>0</SPAN>);   
  54. for (int i = <SPAN class=hilite2>0</SPAN>; i < categories.length; i++) {   
  55. final int y = lastY + (int)(Math.random() * 2<SPAN class=hilite2>0</SPAN><SPAN class=hilite2>0</SPAN> - 1<SPAN class=hilite2>0</SPAN><SPAN class=hilite2>0</SPAN>);   
  56. lastY = y;   
  57. dataset.addValue(y, seriesNames[series], categories[i]);   
  58. }   
  59. }   
  60. return dataset;   
  61. }   
  62.     /**  
  63. * This producer's data is invalidated after 5 seconds. By this method the  
  64. * producer can influence Cewolf's caching behaviour the way it wants to.  
  65. */  
  66. public boolean hasExpired(Map params, Date since) {     
  67. log.debug(getClass().getName() + "hasExpired()");   
  68. return (System.currentTimeMillis() - since.getTime())  > 5<SPAN class=hilite2>0</SPAN><SPAN class=hilite2>0</SPAN><SPAN class=hilite2>0</SPAN>;   
  69. }   
  70.  /**  
  71. * Returns a unique ID for this DatasetProducer  
  72. */  
  73. public String getProducerId() {   
  74. return "PageViewCountData DatasetProducer";   
  75. }   
  76.     /**  
  77. * Returns a link target for a special data item.  
  78. */  
  79. public String generateLink(Object data, int series, Object category) {   
  80. return seriesNames[series];   
  81. }   
  82.   
  83. /**  
  84. * @see java.lang.Object#finalize()  
  85. */  
  86. protected void finalize() throws Throwable {   
  87. super.finalize();   
  88. log.debug(this + " finalized.");   
  89. }   
  90.  /**  
  91. * @see org.jfree.chart.tooltips.CategoryToolTipGenerator#generateToolTip(CategoryDataset, int, int)  
  92. */  
  93. public String generateToolTip(CategoryDataset arg<SPAN class=hilite2>0</SPAN>, int series, int arg2) {   
  94. return seriesNames[series];   
  95. }   
  96. }  

正如所见,这个datasetproducer不是很有用,通常,这个类会去访问一个数据源(例如一个数据库)获得需要的数据,这里仅作例子展示而已。
一个DatasetProducer需要实现3个方法,最重要的一个是produceDataset()方法,它实际上生成了一个用于画图的数据。这个方法用一个map作参数,这个map由许多指定的JSP标签填充,这个一会再介绍。
在当前生数据成器确实生成数据对象后,方法hasExpired()被才被Cewolf框架调用。当返回TRUE时,产生器将释放以前的数据。
Cewolf框架通过 getProducerId()方法提生成的一个唯一ID来标识一个生成者。2个具有相同ID生成实例将被认为时生成相同的数据。
编译该方法,然后把它放在WEB工程的/WEB-INF/类目录下。
第三步:在WEB工程下安装Cewolf Servlet
整个图的绘制由一个servle产生,所以要事先装入WEB工程,Cewolf提供了一个servlet类de.laures.cewolf.CewolfRenderer用来完成这个工作。
为了配置你的web工程,你必须编辑 /WEB-INF/web.xml,添加下列行
<servlet>
<servlet-name>CewolfServlet</servlet-name>
<servlet-class>de.laures.cewolf.CewolfRenderer</servlet-class>
</servlet>
另外你要提供一个servlet-mapping来告诉容器URL与Cewolf绘图servlet的映射关系.
Additionally you should provide a servlet-mapping to tell the container which URL maps to your Cewolf rendering servlet.
<servlet-mapping>
<servlet-name>CewolfServlet</servlet-name>
<url-pattern>/cewolf/ *</url-pattern>
</servlet-mapping>
你还需要告诉CeWolf的启动:
<load-on-startup>1</load-on-startup>
检查配置是否正确:
例如浏览器输入http://localhost:8 08 0/myapp/cewolf?state).
Cewolf应该回应: "Cewolf servlet up and running."
Java代码 复制代码
  1. <web-app>   
  2. <servlet>   
  3. <servlet-name>CewolfServlet</servlet-name>   
  4. <servlet-class>de.laures.cewolf.CewolfRenderer</servlet-class>   
  5. <!-- sets storage implementation -->   
  6. <init-param>   
  7. <param-name>storage</param-name>   
  8. <param-value>de.laures.cewolf.storage.TransientSessionStorage</param-value>   
  9. </init-param>   
  10. <!-- sets overlib.js location relative to webapp -->   
  11. <init-param>   
  12. <param-name>overliburl</param-name>   
  13. <param-value>etc/overlib.js</param-value>   
  14. </init-param>   
  15. <!-- turn on or off debugging logging -->   
  16. <init-param>   
  17. <param-name>debug</param-name>   
  18. <param-value>true</param-value>   
  19. </init-param>   
  20. <load-on-startup>1</load-on-startup>   
  21. </servlet>   
  22.   <servlet-mapping>   
  23. <servlet-name>CewolfServlet</servlet-name>   
  24. <url-pattern>/chart/chart.servlet</url-pattern>   
  25. </servlet-mapping>   
  26.   <session-config>   
  27. <session-timeout>1</session-timeout>   
  28. </session-config>   
  29.   <mime-mapping>   
  30. <extension>css</extension>   
  31. <mime-type>text/css</mime-type>   
  32. </mime-mapping>   
  33.   <welcome-file-list>   
  34. <welcome-file>index.html</welcome-file>   
  35. <welcome-file>index.htm</welcome-file>   
  36. </welcome-file-list>   
  37.   
  38. <!-- resource-ref>   
  39. <description>   
  40. Resource reference to a factory for java.sql.Connection   
  41. instances that may be used for talking to a particular   
  42. database that is configured in the server.xml file.   
  43. </description>   
  44. <resource-ref-name>   
  45. jdbc/testdb   
  46. </resource-ref-name>   
  47. <res-type>   
  48. javax.sql.DataSource   
  49. </res-type>   
  50. <res-auth>   
  51. Container   
  52. </res-auth>   
  53. </resource-ref -->   
  54. </web-app>  


第四步:在JSP定义图

Java代码 复制代码
  1. <%@page contentType="text/html"%>   
  2. <%@taglib uri='/WEB-INF/cewolf.tld' prefix='cewolf' %>   
  3. <HTML>   
  4. <BODY>   
  5. <H1>Page View Statistics</H1>   
  6. <HR>   
  7. <jsp:useBean id="pageViews"    
  8. class="de.laures.cewolf.example.PageViewCountData"/>   
  9. <cewolf:chart id="line" title="Page View Statistics"    
  10. type="line" xaxislabel="Page" yaxislabel="Views">    
  11. <cewolf:data>         
  12. <cewolf:producer id="pageViews"/>    
  13. </cewolf:data>   
  14. </cewolf:chart>   
  15. <p>   
  16. <cewolf:img chartid="line" renderer="/chart/chart.servlet"    
  17. width="4<SPAN class=hilite2>0</SPAN><SPAN class=hilite2>0</SPAN>" height="3<SPAN class=hilite2>0</SPAN><SPAN class=hilite2>0</SPAN>"/>   
  18. <P>   
  19. </BODY>   
  20. </HTML>  


正如所见,有3个cewolf的标签。<cewolf:chart>定义一个可参数化的图,
具体的绘画是交给<cewolf:img>标签的,它向HTML页面添加的正确的<img>标签。
JSP页面中两个cewolf标签之间的关联是通过使用相同的ID。
当在客户端浏览器调用这个JSP时,你能看到静态的图。如果失败,你可以查看容器的日志文件。
第五步:生成ImageMap和Tooltip信息
为了给你的图生成ImageMap和Tooltip信息,你必须自己额外写java类或者修改象下面的一个已经存在的类。在这一步我们将向datasetproducer添加新的方法。
...
public String generateLink(Object data, int series, Object category)
{ return seriesNames[series]; }
public String generateToolTip(CategoryDataset arg 0, int series, int arg2)
{ return seriesNames[series]; }
...
可见,生成ImageMap和Tooltip信息是很简单的事情,
首先要实现接口CategoryItemLinkGenerator和CategoryToolTipGenerator (因为生成的是CategoryDataset). 别的数据类型请参见cewolf java api:http://cewolf.sourceforge.net/new/apidoc/index.html
de.laures.cewolf.tooltips下有4个接口:
CategoryToolTipGenerator
PieToolTipGenerator
ToolTipGenerator
XYToolTipGenerator
为了能让你的类能在图片上生成ImageMap和Tooltip,你必须对<cewolf:img>做如下修改:
<cewolf:img chartid="line" renderer="/chart/chart.servlet" width="4 00" height="3 00">
<cewolf:map tooltipgeneratorid="pageViews" linkgeneratorid="pageViews" />
</cewolf:img>
重新ANT你的页面,你将在数据点看到tooltips和links。浏览器在绘制上面有细小的不同,因为他们能在一个image map绘制基于alt属性的tooltip。而别的浏览器需要overlib.js的支持。Cewolf能试着确定可用的浏览器并清晰的绘制正确的页面。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值