`
eric.zhang
  • 浏览: 126049 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

FusionChart各种图与Springmvc结合

阅读更多
1.需要导入FusionCharts.js文件及所要用到的各种swf播放器

其实各种图的前台基本都一样,只是一个flash的swf文件选择的不一样,不同的图,选择其对应的swf播放器就OK,后台的数据源格式(暂时以xml形式),都
在FusionchartController处理类里:如下:

一、FusionChart与Springmvc结合,后台处理类:
FusionchartController.java
package com.xzjdxt.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/fusionchart")
public class FusionchartController {
	//跳转到单系列图表
	@RequestMapping("/single_chart/{flag}")
	public String single_chart(@PathVariable String flag,HttpServletRequest request, HttpServletResponse response,ModelMap model) {
		model.addAttribute("flag",flag);
		if("FCF_Column3D".equals(flag)){
			return "/fusionchart/single_chart/column3d";
		}
		if("FCF_Column2D".equals(flag)){
			return "/fusionchart/single_chart/column2d";
		}
		if("FCF_Bar2D".equals(flag)){
			return "/fusionchart/single_chart/bar2d";
		}
		if("FCF_Pie2D".equals(flag)){
			return "/fusionchart/single_chart/pie2d";
		}
		if("FCF_Pie3D".equals(flag)){
			return "/fusionchart/single_chart/pie3d";
		}
		if("FCF_Line".equals(flag)){
			return "/fusionchart/single_chart/line2d";
		}
		if("FCF_Area2D".equals(flag)){
			return "/fusionchart/single_chart/area2d";
		}
		if("FCF_Doughnut2D".equals(flag)){
			return "/fusionchart/single_chart/doughnut2d";
		}
		return null;
	}
	
	//单系列图表的数据源
	@RequestMapping(value="/single_chartData")
	public void single_chartData(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		response.setContentType("text/html;charset=UTF-8");
		response.setHeader("Pragma","No-cache"); 
		response.setHeader("Cache-Control","no-cache"); 
		response.setDateHeader("Expires", 0); 
		 StringBuffer sb = new StringBuffer();
		  sb.append("<graph caption='销售业绩图' xAxisName='月份' yAxisName='Units' showNames='1' decimalPrecision='0' formatNumberScale='0'>");
		  sb.append("<set name='一月' value='444' color='AFD8F8' />");
		  sb.append("<set name='二月' value='857' color='F6BD0F' />");
		  sb.append("<set name='三月' value='671' color='8BBA00' />");
		  sb.append("<set name='四月' value='494' color='FF8E46'/>");
		  sb.append("<set name='五月' value='761' color='008E8E'/>");
		  sb.append("<set name='六月' value='960' color='D64646'/>");
		  sb.append("<set name='七月' value='629' color='8E468E'/>");
		  sb.append("<set name='八月' value='622' color='588526'/>");
		  sb.append("<set name='九月' value='376' color='B3AA00'/>");
		  sb.append("<set name='十月' value='494' color='008ED6'/>");
		  sb.append("<set name='十一月' value='761' color='9D080D'/>");
		  sb.append("<set name='十二月' value='960' color='A186BE'/>");
		  sb.append("</graph>");
		response.getWriter().write(sb.toString());
	}
	
	//跳转到多系列图表
	@RequestMapping("/multi_chart/{flag}")
	public String multi_chart(@PathVariable String flag,HttpServletRequest request, HttpServletResponse response,ModelMap model) {
		model.addAttribute("flag",flag);
		if("FCF_MSColumn2D".equals(flag)){
			return "/fusionchart/multi_chart/mscolumn2d";
		}
		if("FCF_MSColumn3D".equals(flag)){
			return "/fusionchart/multi_chart/mscolumn3d";
		}
		if("FCF_MSBar2D".equals(flag)){
			return "/fusionchart/multi_chart/msbar2d";
		}
		if("FCF_MSColumn2DLineDY".equals(flag)){
			return "/fusionchart/multi_chart/msline2d";
		}
		if("FCF_MSArea2D".equals(flag)){
			return "/fusionchart/multi_chart/msarea2d";
		}
		return null;
	}
	
	//多系列图表数据源
	@RequestMapping(value="/multi_chartData")
	public void multi_chartData(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		response.setContentType("text/html;charset=UTF-8");
		response.setHeader("Pragma","No-cache"); 
		response.setHeader("Cache-Control","no-cache"); 
		response.setDateHeader("Expires", 0); 
		
		StringBuffer sb = new StringBuffer();
		  sb.append("<graph xaxisname='Continent' yaxisname='Export' hovercapbg='DEDEBE' hovercapborder='889E6D' rotateNames='0' yAxisMaxValue='100' numdivlines='9' divLineColor='CCCCCC'  decimalPrecision='0' showAlternateHGridColor='1' AlternateHGridAlpha='30' AlternateHGridColor='CCCCCC' caption='Global Export'>");
			  sb.append("<categories font='Arial' fontSize='11' fontColor='000000'>");
				  sb.append("<category name='N. America' hoverText='North America'/>");
				  sb.append("<category name='Asia'/>");
				  sb.append("<category name='Europe'/>");
				  sb.append("<category name='Australia'/>");
				  sb.append("<category name='Africa'/>");
			  sb.append("</categories>");
			  
			  sb.append("<dataset seriesname='Rice' color='FDC12E'>");
				  sb.append("<set value='30'/>");
				  sb.append("<set value='26'/>");
				  sb.append("<set value='29'/>");
				  sb.append("<set value='31'/>");
				  sb.append("<set value='34'/>");
			  sb.append("</dataset>");
			  
			  sb.append("<dataset seriesname='Wheat' color='56B9F9'>");
				  sb.append("<set value='67'/>");
				  sb.append("<set value='98'/>");
				  sb.append("<set value='79'/>");
				  sb.append("<set value='73'/>");
				  sb.append("<set value='70'/>");
			  sb.append("</dataset>");
		  
			  sb.append("<dataset seriesname='Grain' color='C9198D'>");
				  sb.append("<set value='27'/>");
				  sb.append("<set value='25'/>");
				  sb.append("<set value='28'/>");
				  sb.append("<set value='26'/>");
				  sb.append("<set value='10'/>");
			  sb.append("</dataset>");
		  sb.append("</graph>");
		response.getWriter().println(sb.toString());
	}
	
	//多系列图表:线性图数据源
	@RequestMapping(value="/multi_chartDataLine")
	public void multi_chartDataLine(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		response.setContentType("text/html;charset=UTF-8");
		response.setHeader("Pragma","No-cache"); 
		response.setHeader("Cache-Control","no-cache"); 
		response.setDateHeader("Expires", 0); 
		
		StringBuffer sb = new StringBuffer();
		  sb.append("<graph caption='Daily Visits' subcaption='(from 8/6/2006 to 8/12/2006)' hovercapbg='FFECAA' hovercapborder='F47E00' formatNumberScale='0' decimalPrecision='0' showvalues='0' numdivlines='3' numVdivlines='0' yaxisminvalue='1000' yaxismaxvalue='1800'  rotateNames='1'>");
			  sb.append("<categories font='Arial' fontSize='11' fontColor='000000'>");
				  sb.append("<category name='8/6/2006'/>");
				  sb.append("<category name='8/7/2006'/>");
				  sb.append("<category name='8/8/2006'/>");
				  sb.append("<category name='8/9/2006'/>");
				  sb.append("<category name='8/10/2006'/>");
				  sb.append("<category name='8/11/2006'/>");
				  sb.append("<category name='8/12/2006'/>");
			  sb.append("</categories>");
			  
			  sb.append("<dataset seriesName='Offline Marketing' color='1D8BD1' anchorBorderColor='1D8BD1' anchorBgColor='1D8BD1'>");
				  sb.append("<set value='1327'/>");
				  sb.append("<set value='1826'/>");
				  sb.append("<set value='1699'/>");
				  sb.append("<set value='1511'/>");
				  sb.append("<set value='1904'/>");
				  sb.append("<set value='1957'/>");
				  sb.append("<set value='1296'/>");
			  sb.append("</dataset>");
			  
			  sb.append("<dataset seriesName='Search' color='F1683C' anchorBorderColor='F1683C' anchorBgColor='F1683C'>");
			  sb.append("<set value='2042'/>");
			  sb.append("<set value='3210'/>");
			  sb.append("<set value='2994'/>");
			  sb.append("<set value='3115'/>");
			  sb.append("<set value='2844'/>");
			  sb.append("<set value='3576'/>");
			  sb.append("<set value='1862'/>");
			  sb.append("</dataset>");
		  
			  sb.append("<dataset  seriesName='Paid Search' color='2AD62A' anchorBorderColor='2AD62A' anchorBgColor='2AD62A'>");
				  sb.append("<set value='850'/>");
				  sb.append("<set value='1010'/>");
				  sb.append("<set value='1116'/>");
				  sb.append("<set value='1234'/>");
				  sb.append("<set value='1210'/>");
				  sb.append("<set value='1054'/>");
				  sb.append("<set value='802'/>");
			  sb.append("</dataset>");
			  
			  sb.append("<dataset seriesName='From Mail' color='DBDC25' anchorBorderColor='DBDC25' anchorBgColor='DBDC25'>");
				  sb.append("<set value='541' />");
				  sb.append("<set value='781' />");
				  sb.append("<set value='920' />");
				  sb.append("<set value='754' />");
				  sb.append("<set value='840' />");
				  sb.append("<set value='893' />");
				  sb.append("<set value='451' />");
			sb.append("</dataset>");
			  
		  sb.append("</graph>");
		response.getWriter().println(sb.toString());
	}
	
	//跳转到堆图表
	@RequestMapping("/stacked_chart/{flag}")
	public String stacked_chart(@PathVariable String flag,HttpServletRequest request, HttpServletResponse response,ModelMap model) {
		model.addAttribute("flag",flag);
		if("stacked_column2".equals(flag)){
			return "/fusionchart/stacked_chart/stackedcolumn2d";
		}
		if("stacked_column3".equals(flag)){
			return "/fusionchart/stacked_chart/stackedcolumn3d";
		}
		if("stacked_bar".equals(flag)){
			return "/fusionchart/stacked_chart/stackedbar2d";
		}
		if("stacked_area".equals(flag)){
			return "/fusionchart/stacked_chart/stackedarea2d";
		}
		return null;
	}
	//堆图表数据源
	@RequestMapping(value="/stacked_chartData")
	public void stacked_chartData(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		response.setContentType("text/html;charset=UTF-8");
		response.setHeader("Pragma","No-cache"); 
		response.setHeader("Cache-Control","no-cache"); 
		response.setDateHeader("Expires", 0); 
		
		StringBuffer sb = new StringBuffer();
		  sb.append("<graph xAxisName='Products' yAxisName='Sales' caption='Cumulative Sales' subCaption='( 2004 to 2006 )' decimalPrecision='0' rotateNames='1' numDivLines='3' numberPrefix='$' showValues='0' formatNumberScale='0'>");
			  sb.append("<categories>");
				  sb.append("<category name='Product A'/>");
				  sb.append("<category name='Product B'/>");
				  sb.append("<category name='Product C'/>");
				  sb.append("<category name='Product D'/>");
				  sb.append("<category name='Product E'/>");
			  sb.append("</categories>");
			  
			  sb.append("<dataset seriesName='2004' color='AFD8F8' showValues='0'>");
				  sb.append("<set value='25601.34'/>");
				  sb.append("<set value='20148.82'/>");
				  sb.append("<set value='17372.76'/>");
				  sb.append("<set value='35407.15'/>");
				  sb.append("<set value='38105.68'/>");
			  sb.append("</dataset>");
			  
			  sb.append("<dataset seriesName='2005'  color='F6BD0F' showValues='0'>");
			  sb.append("<set value='57401.85'/>");
			  sb.append("<set value='41941.19'/>");
			  sb.append("<set value='45263.37'/>");
			  sb.append("<set value='117320.16'/>");
			  sb.append("<set value='114845.27'/>");
			  sb.append("</dataset>");
		  
			  sb.append("<dataset  seriesName='Paid Search' color='2AD62A' anchorBorderColor='2AD62A' anchorBgColor='2AD62A'>");
				  sb.append("<set value='850'/>");
				  sb.append("<set value='1010'/>");
				  sb.append("<set value='1116'/>");
				  sb.append("<set value='1234'/>");
				  sb.append("<set value='1210'/>");
				  sb.append("<set value='1054'/>");
				  sb.append("<set value='802'/>");
			  sb.append("</dataset>");
			  
			  sb.append("<dataset seriesName='2006' color='8BBA00' showValues='0'>");
				  sb.append("<set value='45000.65' />");
				  sb.append("<set value='44835.76' />");
				  sb.append("<set value='18722.18' />");
				  sb.append("<set value='77557.31' />");
				  sb.append("<set value='92633.68' />");
			sb.append("</dataset>");
			  
		  sb.append("</graph>");
		response.getWriter().println(sb.toString());
	}
	//跳转到组合图
	@RequestMapping("/combination_chart/{flag}")
	public String combination_chart(@PathVariable String flag,HttpServletRequest request, HttpServletResponse response,ModelMap model) {
		model.addAttribute("flag",flag);
		if("column2dline".equals(flag)){
			return "/fusionchart/combination_chart/column2dline";
		}
		if("column3dline".equals(flag)){
			return "/fusionchart/combination_chart/column3dline";
		}
		return null;
	}
	//组合图数据源
	@RequestMapping(value="/combination_chartData")
	public void combination_chartData(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		response.setContentType("text/html;charset=UTF-8");
		response.setHeader("Pragma","No-cache"); 
		response.setHeader("Cache-Control","no-cache"); 
		response.setDateHeader("Expires", 0); 
		
		StringBuffer sb = new StringBuffer();
		  sb.append("<graph caption='Sales' PYAxisName='Revenue' SYAxisName='Quantity' numberPrefix='$' showvalues='0'  numDivLines='4' formatNumberScale='0' decimalPrecision='0' anchorSides='10' anchorRadius='3' anchorBorderColor='009900'>");
			  sb.append("<categories>");
				  sb.append("<category name='March'/>");
				  sb.append("<category name='April'/>");
				  sb.append("<category name='May'/>");
				  sb.append("<category name='June'/>");
				  sb.append("<category name='July'/>");
			  sb.append("</categories>");
			  
			  sb.append("<dataset seriesName='Product A' color='AFD8F8' showValues='0'>");
				  sb.append("<set value='25601.34'/>");
				  sb.append("<set value='20148.82'/>");
				  sb.append("<set value='17372.76'/>");
				  sb.append("<set value='35407.15'/>");
				  sb.append("<set value='38105.68'/>");
			  sb.append("</dataset>");
			  
			  sb.append("<dataset seriesName='Product B' color='F6BD0F' showValues='0'>");
				  sb.append("<set value='57401.85'/>");
				  sb.append("<set value='41941.19'/>");
				  sb.append("<set value='45263.37'/>");
				  sb.append("<set value='117320.16'/>");
				  sb.append("<set value='114845.27'/>");
			  sb.append("</dataset>");
			  
			  sb.append("<dataset seriesName='Total Quantity' color='8BBA00' showValues='0' parentYAxis='S'>");
				  sb.append("<set value='45000' />");
				  sb.append("<set value='44835' />");
				  sb.append("<set value='18722' />");
				  sb.append("<set value='77557' />");
				  sb.append("<set value='92633' />");
			sb.append("</dataset>");
			  
		  sb.append("</graph>");
		response.getWriter().println(sb.toString());
	}
	
}



二、前台JSP页面:
1.柱状图(2D)column2d.jsp
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ include file="/commons/taglibs.jsp" %>
<script src="${ctx }/fusionchart/js/FusionCharts.js" type="text/javascript" ></script>
<script type="text/javascript">	
	 $(document).ready(function() {
	 	
	     $.ajax({
	         type:"POST", 
	         url:"${ctx}/fusionchart/single_chartData",
	         success: function(responseText){
		       var chart = new FusionCharts("${ctx }/fusionchart/Charts/FCF_Column2D.swf","single_column2d", "600", "450");
		       chart.setDataXML(responseText);     
		       chart.render("single_column2div");
	      }
	     });
 	});	
</script>

<body bgcolor="#ffffff">
 <div id="single_column2div" align="center">FusionCharts</div>
</body>



2.柱状图(3D)column3d.jsp
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ include file="/commons/taglibs.jsp" %>
<script src="${ctx }/fusionchart/js/FusionCharts.js" type="text/javascript" ></script>
<script type="text/javascript">	
	 $(document).ready(function() {
	     $.ajax({
	         type:"POST", 
	         url:"${ctx}/fusionchart/single_chartData",
	         success: function(responseText){
		       var chart = new FusionCharts("${ctx }/fusionchart/Charts/FCF_Column3D.swf","single_column3d", "600", "450");
		       chart.setDataXML(responseText);     
		       chart.render("single_column3div");
	      }
	     });
 	});	
</script>

<body bgcolor="#ffffff">
 <div id="single_column3div" align="center">FusionCharts</div>
</body>



其它的前台JSP页面就不多写了,区别就在于new FusionCharts里的第一个参数。swf播放器。

效果图如下:

单一系统:
------------------------------------------------------=---
柱状图(2D纵向)

柱状图(3D纵向)

柱状图(2D横向)

饼状图(2D)

饼状图(3D)


线性图:


区域图


圆环图


-----------------------------------------------------------------
多系列图:
-----------------------------------------------------------------
柱状图(2D纵向)


柱状图(3D纵向)

柱状图(2D横向)

线性图

区域图

----------------------------------------------------------------
组合图:
----------------------------------
柱状图2D+线性图

柱状图3D+线性图

---------------------------------------------------
堆图:
----------------------------------------------------
柱状图2D(纵向)

柱状图3D(纵向)

柱状图2D(横向)

区域2D图

  • 大小: 42.3 KB
  • 大小: 47 KB
  • 大小: 44.1 KB
  • 大小: 31.7 KB
  • 大小: 23.6 KB
  • 大小: 32.7 KB
  • 大小: 34.7 KB
  • 大小: 27.6 KB
  • 大小: 41.3 KB
  • 大小: 48 KB
  • 大小: 40.3 KB
  • 大小: 41.8 KB
  • 大小: 30.8 KB
  • 大小: 40.6 KB
  • 大小: 42.1 KB
  • 大小: 31.4 KB
  • 大小: 35.9 KB
  • 大小: 35.6 KB
  • 大小: 32.2 KB
分享到:
评论

相关推荐

    Wex5与SpringMVC结合框架

    **Wex5与SpringMVC结合框架** Wex5是一个基于HTML5的开源移动应用开发框架,它提供了丰富的UI组件和强大的数据绑定功能,能够帮助开发者构建跨平台的移动应用程序。而SpringMVC是Spring框架的一部分,是一个轻量级...

    springMVC结合mybatis的小实例

    **SpringMVC与Mybatis整合** 1. **配置SpringMVC** 首先,我们需要在`web.xml`中配置DispatcherServlet,并指定SpringMVC的核心配置文件。然后在SpringMVC的配置文件中定义Controller、视图解析器等。 2. **配置...

    springmvc与hibernate结合实例

    本实例将详细介绍如何将 SpringMVC 与 Hibernate 结合,以创建一个简单的 Web 应用程序,并使用 MySQL 数据库进行数据存储。 首先,SpringMVC 是 Spring 框架的一个模块,它负责处理 HTTP 请求并返回响应。它的核心...

    springMVC图片上传示例

    在这个"springMVC图片上传示例"项目中,我们将深入探讨如何在SpringMVC环境中实现图片附件的上传功能,包括多图上传、图片预览及文本域传值。 一、SpringMVC概述 SpringMVC是Spring框架的一部分,它遵循模型-视图-...

    springmvc获取并保存base64编码的图片的方法

    ajax post 上传图片springmvc获取并保存base64编码的图片的方法

    SpringMVC结合ajaxfileupload.js实现文件无刷新上传

    总结起来,结合SpringMVC和ajaxfileupload.js实现文件无刷新上传,需要在前后端进行相应的配置和代码编写。前端利用ajaxfileupload.js处理文件选择和异步上传,后端通过SpringMVC Controller接收并处理文件。这种...

    RabbitMQ与SpringMVC集成

    **RabbitMQ与SpringMVC集成** RabbitMQ是一个开源的消息代理和队列服务器,它基于AMQP(Advanced Message Queuing Protocol)协议实现,广泛应用于分布式系统中的消息传递。RabbitMQ是由Erlang OTP平台构建的,因此...

    Ueditor与jsp、SpringMVC整合,结合文档使用

    这里我只讲解jsp版本的,与servlet和SpringMVC整合,两种方式的应用。这里提供了纯servlet使用的代码,可以完成一个简单的新闻发布系统,做的比较简单,但是代码写的很详细,根据你自己的需求可以补充的。如果想和...

    cas结合 springmvc shiro 单点登录

    本项目是关于如何将CAS(Central Authentication Service)与SpringMVC和Shiro结合实现SSO的实践示例。 首先,我们来了解一下三个主要组件: 1. **CAS**: CAS是一个开源的身份验证框架,主要用于处理用户身份验证...

    SpringMVC框架架构介绍

    3. HandlerAdapter:处理请求映射的适配器,使得Spring可以处理各种类型的控制器(Controller)。AnnotationMethodHandlerAdapter用于处理注解驱动的控制器方法。 4. Controller:控制器接口,通常与@Controller注解...

    springmvc 接受图片

    本工具类是为了让springmvc可以接受图片文件等内容.存放于服务器本地

    SpringMVC PPT_springmvc_

    SpringMVC 是一款基于 Java 的轻量级 Web 开发框架,它是 Spring 框架的重要组成部分,主要用于构建 MVC(Model-View-Controller)模式的 Web 应用程序。本教程将深入探讨 SpringMVC 的核心概念、配置以及实际应用。...

    SpringMvc+mybatis框架结合的一个练习项目

    在这个"SpringMvc+mybatis框架结合的一个练习项目"中,开发者利用 SpringMvc 处理 Web 请求,通过 Mybatis 进行数据操作。项目包含了论坛和聊天系统,这涉及到用户认证、消息传递、数据存储等多个方面,充分展示了这...

    Redis 与SpringMVC 基于代码方式 集成

    Redis 与SpringMVC 基于代码方式 集成

    springmvc+mybatis+mysql整合实现列表展示、新增、更新、删除功能

    在IT行业中,构建Web应用程序是常见的任务,而SpringMVC、Mybatis和MySQL的整合是这类应用中的常用技术栈。本项目"springmvc+mybatis+mysql整合实现列表展示、新增、更新、删除功能"旨在提供一个基础的Maven项目模板...

    SpringMVC+Hibernate+EXT

    EXTJS还提供了强大的数据包装和远程数据通信机制,如Ajax和Store,能够轻松与后端服务如SpringMVC+Hibernate进行交互。 【整合】 SpringMVC+Hibernate+EXT的整合是Web开发中的常见模式,用于构建高效、功能丰富的...

    上传图片springMVC和ajax

    结合SpringMVC和Ajax,我们可以构建出一个高效的图片上传功能,用户可以在不离开当前页面的情况下完成操作,提高了交互体验。同时,通过SpringMVC的控制层和业务逻辑,可以对上传过程进行严格的控制和错误处理,确保...

    SpringMVC完整使用教程

    SpringMVC 可以结合 Spring 的 AOP(面向切面编程)来实现全局行为,如日志记录、权限控制等。另外,`HandlerInterceptor` 实现类可以自定义拦截器,对请求处理流程进行扩展。 综上所述,SpringMVC 提供了一个强大...

    SpringMVC+Redis+MyBatis项目

    MyBatis与Spring的结合使用,可以实现事务管理,提供更强大的数据访问控制。 项目整合这三者,首先需要在SpringMVC的配置文件中添加Redis和MyBatis的相关配置,包括数据源、事务管理器、SqlSessionFactory等。接着...

Global site tag (gtag.js) - Google Analytics