听他们说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");
}

这样做就是每次选中后,把当前选中的项目移到数据最后的位置。

 

chart 代码

 var chart = new Highcharts.chart('container', { title: { text: XMMC, x: -20 //center }, subtitle: { text: '', x: -20 }, xAxis: { categories: [] }, yAxis: { title: { text: '金额' }, plotLines: [{ value: 0, width: 1, color: '#808080' }] }, tooltip: { valueSuffix: '万元' }, legend: { layout: 'vertical', align: 'right', verticalAlign: 'middle', borderWidth: 0 }, series: [{ name: '缴存', data: [] //[7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6] //}, { //name: '使用', //data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5] //}, { //name: '余额', //data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0] }] });

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

Iris数据集散点图

图片 1

图形语法:

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')

 

series

$.ajax({
type: "post",
url: "tjfx.ashx",
data: { "action": "GetChartData", "xmdah": XMDAH },
cache: false,
success: function {
//alert(JSON.stringify;
dataTmp = "";
$.each(data, function {
dataTmp += "[" + field.a + ", "

  • field.b + ", "
  • field.c + ", "
  • field.d + ", "
  • field.e + ", "
  • field.f + ", "
  • field.g + ", "
  • field.h + ", "
  • field.i + ", "
  • field.j + ", "
  • field.k + ", "
  • field.l + "]" + ",";
    });
    dataTmp = dataTmp.substring(0, dataTmp.length - 1);
    alert;
    chart.series[0].setData;
    },
    error: function () {
    alert("请求超时,请重试!");
    }
    });

先看效果图: 用了jquery.image-maps.js这个插件 下载地址 原理是: 通过...

数据加载

第一步是加载数据:

图片 2

数据加载主要用到了三个库:

  • 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中的列名都不显示点,但实际数据并没有改变。

 

x轴和series 获取到的数据都木有问题

alert 出的series 数据也应该没问题
图片 3

但是显示出来x轴多了除年份之外的数据,series 也木有绑上。。。
图片 4
请问问大神们哪里错了?

<!--模块展示 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—>

数据展示

数据处理好后就是我们的核心内容,数据展示了。

图片 5

这一步主要是利用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');
  }
});

图形语法主要包含以下几个主要的元素:

 

x轴

 $.ajax({ type: "post", url: "tjfx.ashx?action=GetCategories", cache: false, success: function  { var dataTemp = data; var arr = new Array(); arr.push(dataTemp[0].Column1); arr.push(dataTemp[0].Column2); arr.push(dataTemp[0].Column3); arr.push(dataTemp[0].Column4); arr.push(dataTemp[0].Column5); arr.push(dataTemp[0].Column6); arr.push(dataTemp[0].Column7); arr.push(dataTemp[0].Column8); arr.push(dataTemp[0].Column9); arr.push(dataTemp[0].Column10); arr.push(dataTemp[0].Column11); arr.push(dataTemp[0].Column12); chart.xAxis[0].setCategories; }, error: function () { alert("请求超时,请重试!"); } });

复制代码 代码如下:

总结

本文分享了一个利用纯前端技术构建一个类似Tableau的BI应用的例子,整个代码统计:

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

总计474 行,用这么少的代码就能完成一个看上去还不错的BI工具,还算不错吧。当然这里主要是由于开源社区提供了这么多好的前端库以供应用,我要做的仅仅是让它们有效的工作在一起。这个只能算是个原型,从功能和质量上来说都不成熟,但是能在浏览器中不借助任何的服务器来实现BI的数据分析功能,应该会有很多人想要在自己的应用中嵌一个吧?

结合我之前分享的TensorflowJS的文章,下面一步可能是加入预测功能,为数据分析加入智能,前端应用的前景,不可限量!

 

highcharts 折线图数据绑定问题

现在整理下发出来,希望大家共同学习吧

Berkeley数据堆叠柱状图

图片 6

数据处理:

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')

 

复制代码 代码如下:

本文由杏彩发布,转载请注明来源

关键词: