当前位置: 永利皇宫463手机版 > Web前端 > 正文

听他们讲jquery自定义图片热区效果,用500行纯前

时间:2019-10-06 20:01来源:Web前端
用500行纯前端代码在浏览器中创设五个Tableau 2018/05/16 · 基础技术 ·BI,Tableau,数量可视化 初稿出处: naughty    在Gartner最新的对商务智能软件的科班深入分析报告中,Tableau持续领跑。

用500行纯前端代码在浏览器中创设五个Tableau

2018/05/16 · 基础技术 · BI, Tableau, 数量可视化

初稿出处: naughty   

在Gartner最新的对商务智能软件的科班深入分析报告中,Tableau持续领跑。Microsoft因为PowerBI表现卓绝也高居领导者象限。目前后的首长像SAP,SAS,IBM,MicroStrategy等逐步被拉开了差距。

图片 1

Tableau因为其心灵手巧,非凡的数量表现已经成为BI领域里确实的领头羊。而其数据驱动的可视化和主旨情想是来源于于Leland Wilkinson的The Grammar Of Graphics ,同样面前境遇该思量熏陶的还应该有Odyssey的图形库ggplot。

图片 2

在数码可视化开源领域里,大家对百度开拓的echarts可谓耳熟能详,echarts经过日久天长的前行,其意义确实特别庞大,可用杰出来描写。可是蚂蚁金服开源的依赖The Grammar Of Graphics的语法驱动的可视化库G2,令人雅观。那大家就看看哪些行使G2和500行左右的纯前端代码来促成三个的好像Tableau的数目深入分析效果与利益。

  • 演示参见 
  • 代码参见 https://gist.github.com/gangtao/e053cf9722b64ef8544afa371c2daaee 

 

前几日重新整建下发出来,希望我们一块学习吧

多少加载

先是步是加载数据:

图片 3

数码加载首要行使了多个库:

  • axios  基于Promise的HTTP客户端
  • alasql 基于JS的开源SQL数据库
  • jquery datatable JQuery的数码表格插件

多少通过自己寄存在GitHub中的csv格式的文书,以REST伏乞的诀要来加载。上边包车型地铁代码把Axios的Promise产生async/wait格局。

// Ajax async request const request = { get: url => { return new Promise((resolve, reject) => { axios .get(url) .then(response => { resolve({ data: response.data }); }) .catch(error => { resolve({ data: error }); }); }); } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Ajax async request
const request = {
  get: url => {
    return new Promise((resolve, reject) => {
      axios
        .get(url)
        .then(response => {
          resolve({ data: response.data });
        })
        .catch(error => {
          resolve({ data: error });
        });
    });
  }
};

装进好后,我们就足以用request.get()方法发送REST恳求,获取csv文件。

let csv = await request.get(url);

1
let csv = await request.get(url);

这一步大概会遇上跨域须求的难题,github上的文本扶助跨域。

把数量存款和储蓄在二个SQL数据库中,那样做的益处是为了下一步做多少妄想的时候,能够一本万利的施用SQL来进展询问和解析。

JavaScript

class SqlTable { constructor(data) { this.data = data; } async query(sql) { // following line of code does not run in full page view due to security concern. // const query_str = sql.replace(/(?<=FROMs+)w+/, "CSV(?)"); const query_str = sql.replace("table", "CSV(?)"); return await alasql.promise(query_str, [this.data]); } }

1
2
3
4
5
6
7
8
9
10
11
12
class SqlTable {
  constructor(data) {
    this.data = data;
  }
 
  async query(sql) {
    // following line of code does not run in full page view due to security concern.
    // const query_str = sql.replace(/(?<=FROMs+)w+/, "CSV(?)");
    const query_str = sql.replace("table", "CSV(?)");
    return await alasql.promise(query_str, [this.data]);
  }
}

SqlTable是三个对数据表的包装,把csv数据存在SQL数据库表中,提供贰个query()方法。这里要做的是把SQL查询个从 “SELECT * FROM table” 变成 “SELECT * FROM CSV(?)” 表示查询参数是CSV数据。因为codepen的安全性限制,运行前向搜索的replace语句(这里的regex表示把前边是“FROM ”词的轮换为CSV(?)的)在full page view下是不可能试行的,所以小编用了贰个更简短的比方,客商的表名就是table,那样做有过多主题材料,大家只要在codepen之外的意况,能够用注释掉的代码。

然后把”SELECT * FROM table”的查询结果(JSON Array)用datatable来体现。

function sanitizeData(jsonArray) { let newKey; jsonArray.forEach(function(item) { for (key in item) { newKey = key.replace(/s/g, "").replace(/./g, ""); if (key != newKey) { item[newKey] = item[key]; delete item[key]; } } }); return jsonArray; } function displayData(tableId, data) { // tricky to clone array let display_data = JSON.parse(JSON.stringify(data)); display_data = sanitizeData(display_data); let columns = []; for (let item in display_data[0]) { columns.push({ data: item, title: item }); } $("#" + tableId).DataTable({ data: display_data, columns: columns, destroy: true }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function sanitizeData(jsonArray) {
  let newKey;
  jsonArray.forEach(function(item) {
    for (key in item) {
      newKey = key.replace(/s/g, "").replace(/./g, "");
      if (key != newKey) {
        item[newKey] = item[key];
        delete item[key];
      }
    }
  });
  return jsonArray;
}
 
function displayData(tableId, data) {
  // tricky to clone array
  let display_data = JSON.parse(JSON.stringify(data));
  display_data = sanitizeData(display_data);
  let columns = [];
  for (let item in display_data[0]) {
    columns.push({ data: item, title: item });
  }
  $("#" + tableId).DataTable({
    data: display_data,
    columns: columns,
    destroy: true
  });
}

这一步有两点要小心:

  1. 数据中,假设列的名字中有隐含点,空格等字符,比方Iris数据汇总的Sepal.Length,datatable是无能为力符合规律展现的,这里要调用sanitizeData()方法把列名,也正是JsonArray中Json对象的性质名中的点和空格去掉。
  2. sanitizeData()方法会改动输入对象,所以在传播之前做了三个纵深拷贝,这里运用JSON的stringfy和parse方法能够对JSON宽容的靶子有效的正片。

那边要留意,Iris数据聚集在datatable中的列名都不呈现点,但实际多少并不曾退换。

 

先看效果图:
图片 4
用了jquery.image-maps.js那几个插件 下载地址 //www.jb51.net/jiaoben/57930.html
原理是:
透过拖动总括出近来热区可活动模块的left top right bottom
对应area的 coords 属性集成上边的岗位,就能够达成热区了。
对应的模块代码是:

多少策动

多少加载实现,大家赶到第二步的多寡计划阶段。数据图谋是多少正确项目最花时间的一步,日常需求对数据开展大气的洗刷,变形,收取等职业,使得数据变得可用。

在这一步我们做了两件事:

一是显得数据的多少个摘要,让我们初叶摸底多少的大概,为进一步的数码变形和处理做好希图。

其一是艾丽丝数据集的摘要:

图片 5

function isString(o) { return typeof o == "string" || (typeof o == "object" && o.constructor === String); } function summaryData(data) { let summary = {}; summary.count = data.length; summary.fields = []; for (let p in data[0]) { let field = {}; field.name = p; if ( isString(data[0][p]) ) { field.type = "string"; } else { field.type = "number"; } summary.fields.push(field); } for (let f of summary.fields) { if ( f.type == "number" ) { f.max = d3.max(data, x => x[f.name]); f.min = d3.min(data, x => x[f.name]); f.mean = d3.mean(data, x => x[f.name]); f.median = d3.median(data, x => x[f.name]); f.deviation = d3.deviation(data, x => x[f.name]); } else { f.values = Array.from(new Set(data.map(x => x[f.name]))); } } return summary; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function isString(o) {
    return typeof o == "string" || (typeof o == "object" && o.constructor === String);
}
 
function summaryData(data) {
  let summary = {};
  summary.count = data.length;
  summary.fields = [];
  for (let p in data[0]) {
    let field = {};
    field.name = p;
    if ( isString(data[0][p]) ) {
      field.type = "string";
    } else {
      field.type = "number";
    }
    summary.fields.push(field);
  }
  
  for (let f of summary.fields) {
      if ( f.type == "number" ) {
        f.max = d3.max(data, x => x[f.name]);
        f.min = d3.min(data, x => x[f.name]);
        f.mean = d3.mean(data, x => x[f.name]);
        f.median = d3.median(data, x => x[f.name]);
        f.deviation = d3.deviation(data, x => x[f.name]);
      } else {
        f.values = Array.from(new Set(data.map(x => x[f.name])));
      }
  }
  return summary;
}

这边我们运用多少的门类判别出每三个字段是数值型照旧字符型。对于字符型的字段,大家使用JS6的Set来博取全部的Unique数据。对于数值型,大家应用d3的max,min,mean,median,deviation方法总计出相应的最大值,最小值,平平均数量,中位数和谬误。

另贰个正是运用SQL查询来对数据开展更为的加工。

图片 6

上海教室的例子中大家运用限制条件获得三个Iris数据的子集。

别的G2还提供了Dataset的功能:

  • 源数据的剖判,将csv, dsv,geojson 转成标准的JSON,查看Connector
  • 加工数据,包括 filter,map,fold(补多少) 等操作,查看 Transform
  • 总括函数,汇总总结、百分比、封箱 等总结函数,查看 Transform
  • 非凡数据管理,富含 地理数据、矩形树图、桑基图、文字云 的多寡处理,查看 Transform

数据管理是二个非常的大的话题,大家的靶子是选取尽只怕少的代码实现多少个数额深入分析的工具,所以这一步仅仅是运用alasql提供的SQL查询来管理数据。

 

复制代码 代码如下:

数据显示

数码管理好后就是大家的核心内容,数据显示了。

图片 7

这一步关键是应用select2提供的选项控件创设图形语法来驱动数据显示。如上海体育场所所示,对应的G2代码图形语法为:

g2chart.facet('rect', { fields: [ 'Admit', 'Dept' ], eachView(view) { view.interval().position('Gender*Freq').color('Gender').label('Freq'); } });

1
2
3
4
5
6
g2chart.facet('rect', {
  fields: [ 'Admit', 'Dept' ],
  eachView(view) {
    view.interval().position('Gender*Freq').color('Gender').label('Freq');
  }
});

图表语法主要包罗以下多少个至关心爱戴要的因素:

 

<!--模块呈现 begin-->
<div class="modeShow">
<div id="debug"></div>
<div class="imgMap mapBox">
<img src="../images/hot_images_map.png" name="test" border="0" usemap="#Map1" width="980" height="450" ref='imageMaps' />
<map name="Map1">
<area shape="rect" coords="300,80,500,150" href="mall.10010.com" />
</map>
</div>
</div>
<!--模块显示 end—>

几何标识 吉优metry

几何标志概念了选取什么的几何图形来表征数据。G2未来帮衬如下那一个几何标识:

geom 类型 描述
point 点,用于绘制各种点图。
path 路径,无序的点连接而成的一条线,常用于路径图的绘制。
line 线,点按照 x 轴连接成一条线,构成线图。
area 填充线图跟坐标系之间构成区域图,也可以指定上下范围。
interval 使用矩形或者弧形,用面积来表示大小关系的图形,一般构成柱状图、饼图等图表。
polygon 多边形,可以用于构建色块图、地图等图表类型。
edge 两个点之间的链接,用于构建树图和关系图中的边、流程图中的连接线。
schema 自定义图形,用于构建箱型图(或者称箱须图)、蜡烛图(或者称 K 线图、股票图)等图表。
heatmap 用于热力图的绘制。

此处要注意,intervalstack是法定协理的,可是文档未有关联,在翻阅G2的API文书档案的时候,笔者也发觉文书档案讲的不是很领悟,有众多地点尚未讲驾驭怎么样行使API。那也是开源软件值得立异的地点。

 

js代码:

图表属性 Attributes

图片属性对应视觉编码中的不一样因素,我们能够参见笔者的另一博客 数码可视化中的视觉属性 。

图表属性主要有以下两种。

  1. position:地点,二维坐标系内映射至 x 轴、y 轴;
  2. color:颜色,包涵了色彩、饱和度和亮度;
  3. size:大小,不相同的几何标识对大小的定义有反差;
  4. shape:形状,几何标志的形制决定了某些具体图表类型的展现情势,比方点图,能够动用圆点、三角形、图片表示;线图能够有折线、曲线、点线等表现格局;
  5. opacity:折射率,图形的发光度,那本本性从某种意义上的话能够运用颜色代表,必要运用 ‘rgba’ 的款式,所以在 G2 中大家独立出来。

在构建语法的时候,大家把图片属性绑定二个要么八个数据字段。

 

复制代码 代码如下:

坐标系 Coordinates

坐标系是将二种职位标度结合在一同构成的 2 维定位系统,描述了数量是怎么着映射到图片所在的平面。

G2提供了以下三种坐标系:

coordType 说明
rect 直角坐标系,目前仅支持二维,由 x, y 两个互相垂直的坐标轴构成。
polar 极坐标系,由角度和半径 2 个维度构成。
theta 一种特殊的极坐标系,半径长度固定,仅仅将数据映射到角度,常用于饼图的绘制。
helix 螺旋坐标系,基于阿基米德螺旋线。

 

(function($) {
jQuery.fn.imageMaps = function(setting) {
var $container = this;
if ($container.length == 0) return false;
$container.each(function(){
var container = $(this);
var $images = container.find('img[ref=imageMaps]');
$images.wrap('<div class="image-maps-conrainer image-maps-conrainerEdit" style="position:relative;"></div>').css('border','1px solid #ccc');
$images.each(function(){
var _img_conrainer = $(this).parent();
_img_conrainer.append('<div class="button-conrainer"><a href="javascript:void(0)" class="addHot">加多火爆</a><a href="javascript:void(0)" class="addImg">上传图片</a><a class="delSub delMode" href="javascript:void(0)">删除×</a></div>').append('<div class="link-conrainer"><ul></ul><div class="clr"></div></div><div class="clr"></div><span class="numFloor">模块-1</span>').append($.browser.msie ? $('<div class="position-conrainer" style="position:absolute"></div>').css({
background:'#fff',
opacity:0
}) : '<div class="position-conrainer" style="position:absolute"></div>');
var _img_offset = $(this).offset();
var _img_conrainer_offset = _img_conrainer.offset();
_img_conrainer.find('.position-conrainer').css({
top: _img_offset.top - _img_conrainer_offset.top,
left: _img_offset.left - _img_conrainer_offset.left,
width:$(this).width(),
height:$(this).height(),
border:'1px solid transparent'
});
var map_name = $(this).attr('usemap').replace('#','');
if(map_name !=''){
var index = 1;
var _link_conrainer = _img_conrainer.find('.link-conrainer ul');
var _position_conrainer = _img_conrainer.find('.position-conrainer');
var image_param = $(this).attr('name') == '' ? '' : '['+ $(this).attr('name') + ']';
container.find('map[name='+map_name+']').find('area[shape=rect]').each(function(){
var coords = $(this).attr('coords');
$(this).attr('ref',"1");
_link_conrainer.append('<li ref="'+index+'" class="map-link"><span class="link-number-text">热点'+index+'</span>: <input type="text" size="60" name="link'+index+'" class="linkHref" value="'+$(this).attr('href')+'" /><input type="hidden" class="rect-value" name="rect'+index+'" value="'+coords+'" /></li>');
coords = coords.split(',');
_position_conrainer.append('<div ref="'+index+'" class="map-position" style="left:'+coords[0]+'px;top:'+coords[1]+'px;width:'+(coords[2]-coords[0])+'px;height:'+(coords[3]-coords[1])+'px;"><div class="map-position-bg"></div><span class="link-number-text">热点'+index+'</span><span class="delete">X</span><span class="resize"></span></div>');
index++;
});
}
});
});
$container.find('.button-conrainer .addHot').live("click",function(){
var _link_conrainer = $(this).parent().parent().find('.link-conrainer ul');
var _position_conrainer = $(this).parent().parent().find('.position-conrainer');
var index = _link_conrainer.find('.map-link').length +1;
var _coordsMap = $(this).parent().parent().next('map');
var image = $(this).parent().parent().find('img[ref=imageMaps]').attr('name');
image = (image == '' ? '' : '['+ image + ']');
_link_conrainer.append('<li ref="'+index+'" class="map-link"><span class="link-number-text">热点'+index+'</span>: <input type="text" size="60" name="link'+index+'" class="linkHref" value="" /><input type="hidden" class="rect-value" name="rect'+index+'" value="300,80,500,150" /></li>');
_position_conrainer.append('<div ref="'+index+'" class="map-position" style="left:300px;top:80px;width:200px;height:70px;"><div class="map-position-bg"></div><span class="link-number-text">热点'+index+'</span><span class="delete">X</span><span class="resize"></span></div>');
var coords = _link_conrainer.find('input[name=rect'+ index +']').val();
_coordsMap.append('<area ref="'+index+'" href="" coords="'+ coords +'" shape="rect">');
$("input[name='link"+index+"']").val("请输入本火热对应的链接地址");
bind_map_event();
define_css();
//添加map热区
});
//修改链接地址
$(".linkHref").live("blur",function(){
var valueHref = $(this).val();
var thisRef = $(this).parent().attr('ref');
var appArea = $(this).parents(".link-conrainer").parent().next('map');
$(this).val(valueHref);
appArea.find('area[ref='+thisRef+']').attr("href",valueHref);
});
//绑定map事件
function bind_map_event(){
$('.position-conrainer .map-position .map-position-bg').each(function(){
var map_position_bg = $(this);
var conrainer = $(this).parent().parent();
map_position_bg.unbind('mousedown').mousedown(function(event){
map_position_bg.data('mousedown', true);
map_position_bg.data('pageX', event.pageX);
map_position_bg.data('pageY', event.pageY);
map_position_bg.css('cursor','move');
return false;
}).unbind('mouseup').mouseup(function(event){
map_position_bg.data('mousedown', false);
map_position_bg.css('cursor','default');
return false;
});
conrainer.mousemove(function(event){
if (!map_position_bg.data('mousedown')) return false;
var dx = event.pageX - map_position_bg.data('pageX');
var dy = event.pageY - map_position_bg.data('pageY');
if ((dx == 0) && (dy == 0)){
return false;
}
var map_position = map_position_bg.parent();
var p = map_position.position();
var left = p.left+dx;
if(left <0) left = 0;
var top = p.top+dy;
if (top < 0) top = 0;
var bottom = top + map_position.height();
if(bottom > conrainer.height()){
top = top-(bottom-conrainer.height());
}
var right = left + map_position.width();
if(right > conrainer.width()){
left = left-(right-conrainer.width());
}
map_position.css({
left:left,
top:top
});
map_position_bg.data('pageX', event.pageX);
map_position_bg.data('pageY', event.pageY);
bottom = top + map_position.height();
right = left + map_position.width();
var newArea = new Array(left,top,right,bottom).join(',');
var mapApp = conrainer.parent().next('map');
mapApp.find('area[ref='+map_position.attr('ref')+']').attr("coords",newArea);
$('.link-conrainer li[ref='+map_position.attr('ref')+'] .rect-value').val(newArea);
return false;
}).mouseup(function(event){
map_position_bg.data('mousedown', false);
map_position_bg.css('cursor','default');
return false;
});
});
$('.position-conrainer .map-position .resize').each(function(){
var map_position_resize = $(this);
var conrainer = $(this).parent().parent();
map_position_resize.unbind('mousedown').mousedown(function(event){
map_position_resize.data('mousedown', true);
map_position_resize.data('pageX', event.pageX);
map_position_resize.data('pageY', event.pageY);
return false;
}).unbind('mouseup').mouseup(function(event){
map_position_resize.data('mousedown', false);
return false;
});
//点击撤销拖动
conrainer.unbind('click').click(function(event){
map_position_resize.data('mousedown', false);
return false;
});
conrainer.mousemove(function(event){
if (!map_position_resize.data('mousedown')) return false;
var dx = event.pageX - map_position_resize.data('pageX');
var dy = event.pageY - map_position_resize.data('pageY');
if ((dx == 0) && (dy == 0)){
return false;
}
var map_position = map_position_resize.parent();
var p = map_position.position();
var left = p.left;
var top = p.top;
var height = map_position.height()+dy;
if((top+height) > conrainer.height()){
height = height-((top+height)-conrainer.height());
}
if (height <20) height = 20;
var width = map_position.width()+dx;
if((left+width) > conrainer.width()){
width = width-((left+width)-conrainer.width());
}
if(width <50) width = 50;
map_position.css({
width:width,
height:height
});
map_position_resize.data('pageX', event.pageX);
map_position_resize.data('pageY', event.pageY);
bottom = top + map_position.height();
right = left + map_position.width();
var newArea = new Array(left,top,right,bottom).join(',');
var mapApp = conrainer.parent().next('map');
mapApp.find('area[ref='+map_position.attr('ref')+']').attr("coords",newArea);
$('.link-conrainer li[ref='+map_position.attr('ref')+'] .rect-value').val(newArea);
return false;
}).mouseup(function(event){
map_position_resize.data('mousedown', false);
return false;
});
});
$('.position-conrainer .map-position .delete').unbind('click').click(function(){
var ref = $(this).parent().attr('ref');
var _link_conrainer = $(this).parent().parent().parent().find('.link-conrainer ul');
var _coordsMap = $(this).parent().parent().parent().next('map');
var _position_conrainer = $(this).parent().parent().parent().find('.position-conrainer');
_link_conrainer.find('.map-link[ref='+ref+']').remove();
_position_conrainer.find('.map-position[ref='+ref+']').remove();
_coordsMap.find('area[ref='+ref+']').remove();
var index = 1;
_link_conrainer.find('.map-link').each(function(){
$(this).attr('ref',index).find('.link-number-text').html('热点'+index);
index ++;
});
index = 1;
_position_conrainer.find('.map-position').each(function(){
$(this).attr('ref',index).find('.link-number-text').html('热点'+index);
index ++;
});
index = 1;
_coordsMap.find('area').each(function(){
$(this).attr('ref',index);
index ++;
});
});
}
bind_map_event();
function define_css(){
//样式定义
$container.find('.map-position .resize').css({
display:'block',
position:'absolute',
right:0,
bottom:0,
width:5,
height:5,
cursor:'nw-resize',
background:'#000'
});
}
define_css();
};
})(jQuery);

分面 Facet

分面,将一份数据依据某些维度分隔成几何子集,然后创制一个图纸的矩阵,将每贰个数据子集绘制到图片矩阵的窗格中。分面其实提供了三个成效:

  1. 遵从钦定的维度划分数据集;
  2. 对图片举办排版。

G2帮助以下的分面类型:

分面类型 说明
rect 默认类型,指定 2 个维度作为行列,形成图表的矩阵。
list 指定一个维度,可以指定一行有几列,超出自动换行。
circle 指定一个维度,沿着圆分布。
tree 指定多个维度,每个维度作为树的一级,展开多层图表。
mirror 指定一个维度,形成镜像图表。
matrix 指定一个维度,形成矩阵分面。

小心,在小编的代码中,为了简化使用,只援助list和rect,当绑定五个字段的时候用list,绑定八个字段的时候用rect。

除了那么些之外上面提到的元素,当然还只怕有大多别样的因素大家平昔不满含和支撑,举例:坐标轴,图例,提醒等等。

有关图形的语法的越来越多内容,请参照他事他说加以考察这里。

调换图形语法的为主代码如下:

function getFacet(faced, grammarScript) { let facedType = "list"; let facedScript = "" grammarScript = grammarScript.replace(chartScriptName,"view"); if ( faced.length == 2 ) { facedType = "rect"; } let facedFields = faced.join("', '") facedScript = facedScript + `${ chartScriptName }.facet('${ facedType }', {n`; facedScript = facedScript + ` fields: [ '${ facedFields }' ],n`; facedScript = facedScript + ` eachView(view) {n`; facedScript = facedScript + ` ${ grammarScript };n`; facedScript = facedScript + ` }n`; facedScript = facedScript + `});n`; return facedScript } function getGrammar() { let grammar = {}, grammarScript = chartScriptName + "."; grammar.geom = $('#geomSelect').val(); grammar.coord = $('#coordSelect').val(); grammar.faced = $('#facetSelect').val(); geom_attributes.map(function(attr){ grammar[attr] = $('#' + attr + "attr").val(); }); grammarScript = grammarScript + grammar.geom + "()"; geom_attributes.map(function(attr){ if (grammar[attr].length > 0) { grammarScript = grammarScript + "." + attr + "('" + grammar[attr].join("*") + "')"; } }); if (grammar.coord) { grammarScript = grammarScript + ";n " + chartScriptName + "." + "coord('" + grammar.coord + "');"; } else { rammarScript = grammarScript

  • ";"; } if ( grammar.faced ) { if ( grammar.faced.length == 1 || grammar.faced.length == 2 ) { grammarScript = getFacet(grammar.faced, grammarScript); } } console.log(grammarScript) return grammarScript; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function getFacet(faced, grammarScript) {
  let facedType = "list";
  let facedScript = ""
  grammarScript = grammarScript.replace(chartScriptName,"view");
  if ( faced.length == 2 ) {
      facedType = "rect";
  }
  let facedFields = faced.join("', '")
  facedScript = facedScript + `${ chartScriptName }.facet('${ facedType }', {n`;
  facedScript = facedScript + `  fields: [ '${ facedFields }' ],n`;
  facedScript = facedScript + `  eachView(view) {n`;
  facedScript = facedScript + `    ${ grammarScript };n`;
  facedScript = facedScript + `  }n`;
  facedScript = facedScript + `});n`;
  return facedScript
}
 
function getGrammar() {
  let grammar = {}, grammarScript = chartScriptName + ".";
  grammar.geom = $('#geomSelect').val();
  grammar.coord = $('#coordSelect').val();
  grammar.faced = $('#facetSelect').val();
  geom_attributes.map(function(attr){
    grammar[attr] = $('#' + attr + "attr").val();
  });
  
  grammarScript = grammarScript + grammar.geom + "()";
  geom_attributes.map(function(attr){
    if (grammar[attr].length > 0) {
      grammarScript = grammarScript + "." + attr + "('" + grammar[attr].join("*") + "')";
    }
  });
  
  if (grammar.coord) {
    grammarScript = grammarScript + ";n " + chartScriptName + "." + "coord('" + grammar.coord + "');";
  } else {
    rammarScript = grammarScript + ";";
  }
  
  if ( grammar.faced ) {
    if ( grammar.faced.length == 1 ||
        grammar.faced.length == 2 ) {
      grammarScript = getFacet(grammar.faced, grammarScript);
    }
  }
  
  console.log(grammarScript)
  return grammarScript;
}

此地有几点要当心:

  • 动用JS的模板字符串能够使得的布局代码片段
  • 选拔eval施行组织好的语法驱动的代码来响应select的change事件,以获得特出的交互性。在生产条件,要在意该措施的安全性隐患,因为纯前端,eval能推动的威迫异常的小,生产中,能够把那些试行放在安全的沙箱中运维
  • 您供给驾驭图形语法,并非随机的结合都能使得出可行的图样。

此间对于select2的多选,有贰个小的提醒,在缺省气象下,多选的相继是牢固的相继,并不依赖采用的逐条,然则无数图片语法和字段的一一有关,所以大家使用如下的格局来对号入座select的挑选事件。

function updateSelect2Order(evt) { let element = evt.params.data.element; let $element = $(element); $element.detach(); $(this).append($element); $(this).trigger("change"); }

1
2
3
4
5
6
7
function updateSelect2Order(evt) {
  let element = evt.params.data.element;
  let $element = $(element);
  $element.detach();
  $(this).append($element);
  $(this).trigger("change");
}

与上述同类做便是每趟选中后,把当下相中的项目移到多少最后的职位。

 

页面引用:$('.imgMap').imageMaps();

有些例证

好了,下边大家就来看一些例证,明白一下哪些运用图形语法来分析和研究数据。

 

Iris数据集散点图

图片 8

图片语法:

g2chart.point().position('Sepal.Length*Petal.Length').color('Species').size('Sepal.Width')

1
g2chart.point().position('Sepal.Length*Petal.Length').color('Species').size('Sepal.Width')

 

Car数据集折线图

图片 9

图片语法:

g2chart.line().position('id*speed');

1
g2chart.line().position('id*speed');

切换来极坐标:

图片 10

图片语法:

g2chart.line().position('id*speed'); g2chart.coord('polar');

1
2
g2chart.line().position('id*speed');
g2chart.coord('polar');

 

伯克利数据柱状图

图片 11

多少管理:

SELECT SUM(Freq) as f , Gender FROM table GROUP BY Gender

1
SELECT SUM(Freq) as f , Gender FROM table GROUP BY Gender

图形语法:

g2chart.interval().position('Gender*f').color('Gender').label('f');

1
g2chart.interval().position('Gender*f').color('Gender').label('f');

 

Berkeley数据聚积柱状图

图片 12

数据管理:

SELECT SUM(Freq) as f , Gender , Admit FROM table GROUP BY Gender, Admit

1
SELECT SUM(Freq) as f , Gender , Admit FROM table GROUP BY Gender, Admit

图片语法:

g2chart.intervalStack().position('Gender*f').color('Admit')

1
g2chart.intervalStack().position('Gender*f').color('Admit')

 

Berkeley数据饼图

图片 13

数量管理:

SELECT SUM(Freq) as f , Gender FROM table GROUP BY Gender

1
SELECT SUM(Freq) as f , Gender FROM table GROUP BY Gender

图形语法:

g2chart.intervalStack().position('f').color('Gender').label('f'); g2chart.coord('theta')

1
2
g2chart.intervalStack().position('f').color('Gender').label('f');
g2chart.coord('theta')

 

Berkeley数据分面包车型地铁采用

图片 14

图片语法:

g2chart.facet('rect', { fields: [ 'Dept', 'Admit' ], eachView(view) { view.coord('theta'); view.intervalStack().position('Freq').color('Gender'); } });

1
2
3
4
5
6
7
g2chart.facet('rect', {
  fields: [ 'Dept', 'Admit' ],
  eachView(view) {
    view.coord('theta');
    view.intervalStack().position('Freq').color('Gender');
  }
});

更加的多的解析图形留给大家去尝尝

 

总结

本文分享了一个接纳纯前端本领营造二个看似Tableau的BI应用的例子,整个代码总括:

  • JS 370 行 JS6
  • HTML 69 + 9 + 5 = 83
  • CSS 21

总计474 行,用如此少的代码就能够一鼓作气一个看上去还不易的BI工具,还算不错啊。当然这里主借使出于开源社区提供了这么多好的前端库以供应用,作者要做的单纯是让它们有效的做事在联合签字。那几个只可以算是个原型,从成效和材料上的话都不成熟,不过能在浏览器中不相信任任何的服务器来贯彻BI的数据分析功用,应该会有广大人想要在友好的采纳中嵌贰个吗?

结缘自个儿事先分享的TensorflowJS的文章,上面一步也许是参预预测效果,为多少分析加入智能,前端选用的前景,深不可测!

 

参考

  • axios  基于Promise的HTTP客户端
  • alasql 基于JS的开源SQL数据库
  • jquery datatable JQuery的多少表格插件
  • select2 JQuery的挑三拣四控件插件
  • 连带博客 使用开源软件神速搭建数据分析平台 
  • 连带博客 数量可视化中的视觉属性

    2 赞 1 收藏 评论

图片 15

编辑:Web前端 本文来源:听他们讲jquery自定义图片热区效果,用500行纯前

关键词: