DataV 是阿里云出品的拖拽式可视化工具,专精于业务数据与地理信息融合的大数据可视化。快速开始


准备环境

Node版本在 8.0.0 及以上,10.12.0以下,推荐使用nvm管理node版本。nvm使用说明

安装开发工具套件

  1. // 开发工具
  2. npm install --registry=https://registry.npm.taobao.org datav-cli -g
  3. // 开发工具版本
  4. datav --version

帮助命令

  1. $ datav -h
  2. Usage: datav [options] <folder|file...>
  3. Commands:
  4. set-key|login set-key with you username and token in the datav.aliyun.com
  5. init init com for datav-coms
  6. start|run [options] start service for preview component
  7. publish|pbl [options] publish component
  8. package|pack package component
  9. locale Set your locale
  10. locale-clear|lc Clear your locale
  11. help help
  12. latest check datav-cli latest version
  13. whoami display datav username, datav region
  14. Options:
  15. -h, --help output usage information
  16. -V, --version output the version number
  17. -v --verbose increase verbosity
  18. -E --exclude <items> exclude file or folder
  19. -V, --version output the version number

生成基础代码包

image.png

预览组件

  1. cd 您的组件名
  2. datav run
  3. http://localhost:1111/

预览页主要分为中心画布区,底部工具栏和右侧工具栏三部分,详细介绍如下:

  • 中心画布区
    • 中心画布区是用来展现组件,实时观测组件变化的区域。
    • 所有右侧工具栏的配置、数据修改都会实时展示在中心画布的组件上。
    • 组件的白框代表了组件的容器范围大小,每个方向上的白框都可以缩放来测试组件在任意方向缩放的表现。
  • 底部工具栏可以切换组件的语言环境。
  • 右侧工具栏右侧工具栏分为配置数据交互发布4个面板。

主要文件

index.js //入口文件
package.json //组件配置项 默认的配置和数据都在这里

package.json

控件总览 控件配置

  1. {
  2. "name": "@iwhalecloud-poc/ScrollZone",
  3. "version": "0.0.5",
  4. "dependencies": {
  5. "bcore": "0.0.18",
  6. "echarts": "^4.6.0",
  7. "jquery": "2.1.4",
  8. "lodash": "4.6.1",
  9. "zrender": "3.4.4"
  10. },
  11. "datav": {
  12. "cn_name": "滚动区",
  13. "icon": "",
  14. "protocol": 2,
  15. "type": [
  16. "regular_bar"
  17. ],
  18. "view": {
  19. "width": "600",
  20. "height": "400",
  21. "minWidth": "40",
  22. "minHeight": "20"
  23. },
  24. "apis": {
  25. "source": {
  26. "handler": "render",
  27. "description": "滚动事件列表接口",
  28. "fields": {
  29. "url": {
  30. "description": "事件图标",
  31. "type": "string",
  32. "optional": true
  33. },
  34. "title": {
  35. "description": "事件标题",
  36. "type": "string"
  37. },
  38. "status": {
  39. "description": "事件状态",
  40. "type": "int"
  41. },
  42. "desc": {
  43. "description": "事件简述",
  44. "type": "string"
  45. },
  46. "time": {
  47. "description": "时间",
  48. "type": "string",
  49. "optional": true
  50. },
  51. "act": {
  52. "description": "时间",
  53. "type": "string",
  54. "optional": true
  55. },
  56. "actIconUrl": {
  57. "description": "处理动作图标",
  58. "type": "string",
  59. "optional": true
  60. }
  61. }
  62. }
  63. },
  64. "config": {
  65. "options": {
  66. "name": "菜单",
  67. "type": "menu",
  68. "children": {
  69. "zone": {
  70. "name": "全局",
  71. "mode": "single",
  72. "children": {
  73. "size": {
  74. "type": "suite",
  75. "name": "大小",
  76. "children": {
  77. "width": {
  78. "name": "宽度",
  79. "type": "stepper",
  80. "default": 200,
  81. "step": 1,
  82. "min": 0,
  83. "suffix": "px",
  84. "description": "",
  85. "col": 12
  86. },
  87. "height": {
  88. "name": "高度",
  89. "type": "stepper",
  90. "default": 400,
  91. "step": 1,
  92. "min": 0,
  93. "suffix": "px",
  94. "description": "",
  95. "col": 12
  96. }
  97. }
  98. },
  99. "position": {
  100. "name": "位置",
  101. "type": "suite",
  102. "children": {
  103. "left": {
  104. "name": "x",
  105. "type": "stepper",
  106. "default": 0,
  107. "step": 0.1,
  108. "suffix": "px",
  109. "description": "",
  110. "col": 12
  111. },
  112. "top": {
  113. "name": "y",
  114. "type": "stepper",
  115. "default": 0,
  116. "step": 0.1,
  117. "suffix": "px",
  118. "description": "",
  119. "col": 12
  120. }
  121. }
  122. },
  123. "direction": {
  124. "name": "排列方式",
  125. "type": "select",
  126. "range": [
  127. {
  128. "name": "水平",
  129. "value": "row"
  130. },
  131. {
  132. "name": "竖直",
  133. "value": "column"
  134. }
  135. ],
  136. "default": "column"
  137. }
  138. }
  139. },
  140. "card": {
  141. "name": "卡片",
  142. "mode": "single",
  143. "children": {
  144. "margin": {
  145. "type": "margin",
  146. "name": "边距",
  147. "default": {
  148. "top": 10,
  149. "bottom": 10,
  150. "left": 10,
  151. "right": 10
  152. }
  153. },
  154. "border": {
  155. "type": "suite",
  156. "name": "边框",
  157. "children": {
  158. "borderWidth": {
  159. "name": "边框粗细",
  160. "type": "stepper",
  161. "step": 1,
  162. "default": 2,
  163. "col": 12,
  164. "suffix": "px"
  165. },
  166. "borderColor": {
  167. "name": "边框颜色",
  168. "type": "fill",
  169. "default": "rgba(0,0,0,0.7)",
  170. "col": 12
  171. },
  172. "borderRadius": {
  173. "name": "边框圆角",
  174. "type": "stepper",
  175. "step": 1,
  176. "default": 0,
  177. "col": 12,
  178. "suffix": "px"
  179. },
  180. "lineStyle": {
  181. "name": "边框线型",
  182. "type": "select",
  183. "range": [
  184. {
  185. "name": "实线",
  186. "value": "solid"
  187. },
  188. {
  189. "name": "虚线",
  190. "value": "dashed"
  191. },
  192. {
  193. "name": "点状",
  194. "value": "dotted"
  195. }
  196. ],
  197. "default": "solid",
  198. "col": 12
  199. }
  200. }
  201. },
  202. "color": {
  203. "name": "颜色",
  204. "type": "fill",
  205. "default": {
  206. "type": "flat",
  207. "value": "rgba(0,0,0,0.6)"
  208. },
  209. "components": [
  210. "flat",
  211. "linearGradient"
  212. ]
  213. },
  214. "icon": {
  215. "name": "图标",
  216. "type": "group",
  217. "children": {
  218. "show": {
  219. "name": "显示",
  220. "type": "boolean",
  221. "default": true
  222. },
  223. "size": {
  224. "type": "suite",
  225. "name": "大小",
  226. "children": {
  227. "width": {
  228. "name": "宽度",
  229. "type": "stepper",
  230. "default": 16,
  231. "step": 1,
  232. "min": 0,
  233. "suffix": "px",
  234. "description": "",
  235. "col": 12
  236. },
  237. "height": {
  238. "name": "高度",
  239. "type": "stepper",
  240. "default": 16,
  241. "step": 1,
  242. "min": 0,
  243. "suffix": "px",
  244. "description": "",
  245. "col": 12
  246. }
  247. }
  248. },
  249. "position": {
  250. "name": "位置",
  251. "type": "suite",
  252. "children": {
  253. "left": {
  254. "name": "x",
  255. "type": "stepper",
  256. "default": 0,
  257. "step": 0.1,
  258. "suffix": "px",
  259. "description": "",
  260. "col": 12
  261. },
  262. "top": {
  263. "name": "y",
  264. "type": "stepper",
  265. "default": 0,
  266. "step": 0.1,
  267. "suffix": "px",
  268. "description": "",
  269. "col": 12
  270. }
  271. }
  272. },
  273. "url": {
  274. "name": "图标",
  275. "type": "image",
  276. "default": "./assets/warning.png"
  277. }
  278. }
  279. },
  280. "title": {
  281. "name": "标题",
  282. "type": "group",
  283. "children": {
  284. "show": {
  285. "name": "显示",
  286. "type": "boolean",
  287. "default": true
  288. },
  289. "size": {
  290. "type": "suite",
  291. "name": "大小",
  292. "children": {
  293. "width": {
  294. "name": "宽度",
  295. "type": "stepper",
  296. "default": 0,
  297. "step": 1,
  298. "min": 0,
  299. "suffix": "px",
  300. "description": "",
  301. "col": 12
  302. },
  303. "height": {
  304. "name": "高度",
  305. "type": "stepper",
  306. "default": 30,
  307. "step": 1,
  308. "min": 0,
  309. "suffix": "px",
  310. "description": "",
  311. "col": 12
  312. }
  313. }
  314. },
  315. "position": {
  316. "name": "位置",
  317. "type": "suite",
  318. "children": {
  319. "left": {
  320. "name": "x",
  321. "type": "stepper",
  322. "default": 0,
  323. "step": 0.1,
  324. "suffix": "px",
  325. "description": "",
  326. "col": 12
  327. },
  328. "top": {
  329. "name": "y",
  330. "type": "stepper",
  331. "default": 0,
  332. "step": 0.1,
  333. "suffix": "px",
  334. "description": "",
  335. "col": 12
  336. }
  337. }
  338. },
  339. "text": {
  340. "name": "标题文字",
  341. "type": "text",
  342. "default": "标题文字"
  343. },
  344. "textStyle": {
  345. "type": "font",
  346. "name": "文本",
  347. "default": {
  348. "fontFamily": "Microsoft Yahei",
  349. "fontWeight": "normal",
  350. "fontSize": 12,
  351. "color": "rgb(255, 255, 255)"
  352. }
  353. },
  354. "align": {
  355. "name": "对齐方式",
  356. "type": "select",
  357. "range": [
  358. {
  359. "name": "左对齐",
  360. "value": "flex-start"
  361. },
  362. {
  363. "name": "居中对齐",
  364. "value": "center"
  365. },
  366. {
  367. "name": "右对齐",
  368. "value": "flex-end"
  369. }
  370. ],
  371. "default": "center"
  372. },
  373. "direction": {
  374. "name": "排列方式",
  375. "type": "select",
  376. "range": [
  377. {
  378. "name": "水平",
  379. "value": "horizontal"
  380. },
  381. {
  382. "name": "竖直",
  383. "value": "vertical"
  384. }
  385. ],
  386. "default": "horizontal"
  387. }
  388. },
  389. "fold": true
  390. }
  391. }
  392. }
  393. }
  394. }
  395. },
  396. "api_data": {
  397. "source": [
  398. {
  399. "url": "",
  400. "title": "我是事件标题1",
  401. "status": 0,
  402. "desc": "我是事件简述我是事件简述我是事件简述我是事件简述我是事件简述我是事件简述",
  403. "time": "2020年03月10日",
  404. "act": "前往处理"
  405. }
  406. ]
  407. },
  408. "events": {
  409. "title-click": {
  410. "description": "点击触发标题事件",
  411. "fields": {
  412. "value": {
  413. "description": "点击值"
  414. }
  415. }
  416. }
  417. }
  418. }
  419. }

index.js

  1. var Event = require("bcore/event");
  2. var $ = require("jquery");
  3. var _ = require("lodash");
  4. // var EChart = require("echarts");
  5. // var Utils = require("datav:/com/maliang-echarts-utils/0.0.18");
  6. /**
  7. * 马良基础类
  8. */
  9. module.exports = Event.extend(
  10. function Base(container, config) {
  11. this.config = {
  12. theme: {}
  13. };
  14. this.container = $(container); //容器
  15. this.apis = config.apis; //hook一定要有
  16. this._data = null; //数据
  17. this.chart = null; //图表
  18. this.init(config);
  19. },
  20. {
  21. /**
  22. * 公有初始化
  23. */
  24. init: function(config) {
  25. //1.初始化,合并配置
  26. this.mergeConfig(config);
  27. //2.刷新布局,针对有子组件的组件 可有可无
  28. this.updateLayout();
  29. //3.子组件实例化
  30. //this.chart = new Chart(this.container[0], this.config);
  31. //4.如果有需要, 更新样式
  32. this.updateStyle();
  33. },
  34. /**
  35. * 绘制
  36. * @param data
  37. * @param options 不一定有
  38. * !!注意: 第二个参数支持config, 就不需要updateOptions这个方法了
  39. */
  40. render: function(data, config) {
  41. // console.log(data, config);
  42. data = this.data(data);
  43. // console.log("data:", data);
  44. var cfg = this.mergeConfig(config);
  45. // console.log("config:", cfg);
  46. var card = cfg.options.card;
  47. var items = ["<div class='zone'>"];
  48. data.forEach(element => {
  49. items.push(
  50. "<div class='card'><div class='title-row'><img class='icon' src=" +
  51. (element.url || card.icon.url) +
  52. "></img><span class='title'>" +
  53. element.title +
  54. "</span><span class='status'>" +
  55. element.status +
  56. "</span></div>" +
  57. "<div class='desc'>" +
  58. element.desc +
  59. "</div>" +
  60. "<div class='time'>" +
  61. element.time +
  62. "</div>" +
  63. "<div class='act'>" +
  64. (element.act || card.act.text.text) +
  65. "<span class='act-icon'><img src=" +
  66. (element.actIconUrl || card.act.suffix.url) +
  67. "></img></span>" +
  68. "</div></div>"
  69. );
  70. });
  71. items.push("</div>");
  72. //更新图表
  73. //this.chart.render(data, cfg);
  74. // console.log(this.container);
  75. this.container.html(items.join(""));
  76. //如果有需要的话,更新样式
  77. this.updateStyle();
  78. this.scrollY();
  79. },
  80. scrollY: function() {
  81. $(function() {
  82. var $this = $(".datav-wraper");
  83. if (!$this.length) {
  84. $this = $(".-datav-wraper");
  85. }
  86. var scrollTimer;
  87. $this
  88. .hover(
  89. function() {
  90. clearInterval(scrollTimer);
  91. },
  92. function() {
  93. scrollTimer = setInterval(function() {
  94. scrollNews($this);
  95. }, 2000);
  96. }
  97. )
  98. .trigger("mouseleave");
  99. function scrollNews(obj) {
  100. var $self = obj.find(".zone");
  101. var lineHeight = $self.find(".card:nth-child(1)").height();
  102. $self.animate(
  103. {
  104. transform: "translateY(" + lineHeight + "px)",
  105. transition: "2s linear"
  106. },
  107. 2000,
  108. function() {
  109. $self
  110. .css({
  111. transform: "translateY(0)",
  112. transition: "2s linear"
  113. })
  114. .find(".card:nth-child(1)")
  115. .appendTo($self);
  116. }
  117. );
  118. }
  119. });
  120. },
  121. /**
  122. *
  123. * @param width
  124. * @param height
  125. */
  126. resize: function(width, height) {
  127. this.updateLayout(width, height);
  128. //更新图表
  129. //this.chart.render({
  130. // width: width,
  131. // height: height
  132. //})
  133. },
  134. /**
  135. * 每个组件根据自身需要,从主题中获取颜色 覆盖到自身配置的颜色中.
  136. * 暂时可以不填内容
  137. */
  138. setColors: function() {
  139. //比如
  140. //var cfg = this.config;
  141. //cfg.color = cfg.theme.series[0] || cfg.color;
  142. },
  143. /**
  144. * 数据,设置和获取数据
  145. * @param data
  146. * @returns {*|number}
  147. */
  148. data: function(data) {
  149. if (data) {
  150. this._data = data;
  151. }
  152. return this._data;
  153. },
  154. /**
  155. * 更新配置
  156. * 优先级: config.colors > config.theme > this.config.theme > this.config.colors
  157. * [注] 有数组的配置一定要替换
  158. * @param config
  159. * @private
  160. */
  161. mergeConfig: function(config) {
  162. if (!config) {
  163. return this.config;
  164. }
  165. this.config.theme = _.defaultsDeep(config.theme || {}, this.config.theme);
  166. this.setColors();
  167. this.config = _.defaultsDeep(config || {}, this.config);
  168. return this.config;
  169. },
  170. /**
  171. * 更新布局
  172. * 可有可无
  173. */
  174. updateLayout: function() {},
  175. /**
  176. * 更新样式
  177. * 有些子组件控制不到的,但是需要控制改变的,在这里实现
  178. */
  179. updateStyle: function() {
  180. var cfg = this.config;
  181. var card = cfg.options.card;
  182. var keys = Object.keys(card);
  183. keys = keys.filter(item => item !== "margin");
  184. keys.forEach(function(name) {
  185. // console.log(name);
  186. var element = name === "act" ? card[name].text : card[name];
  187. // console.log(element);
  188. var tdom = $("." + name);
  189. if (element.show) {
  190. if (name === "icon") {
  191. tdom.css({
  192. width: element.size.width,
  193. height: element.size.height,
  194. position: "relative",
  195. top: element.position.top,
  196. left: element.position.left
  197. });
  198. return;
  199. } else if (["title", "status"].indexOf(name) > -1) {
  200. tdom.css({
  201. display: "inline-flex"
  202. });
  203. } else {
  204. tdom.css({
  205. display: "flex"
  206. });
  207. }
  208. if (name === "act") {
  209. var item = card[name].suffix;
  210. $(".act-icon").css({
  211. display: "flex",
  212. "align-items": "center"
  213. });
  214. $(".act-icon img").css({
  215. width: item.size.width ? item.size.width : undefined,
  216. height: item.size.height,
  217. position: "relative",
  218. top: item.position.top,
  219. left: item.position.left
  220. });
  221. }
  222. tdom.css({
  223. "font-size": element.textStyle.fontSize,
  224. "font-family": element.textStyle.fontFamily,
  225. "font-weight": element.textStyle.fontWeight,
  226. color: element.textStyle.color,
  227. "justify-content": element.align,
  228. "align-items": "center",
  229. width: element.size.width ? element.size.width : undefined,
  230. height: element.size.height,
  231. position: "relative",
  232. top: element.position.top,
  233. left: element.position.left,
  234. overflow: "hidden",
  235. "text-overflow": "ellipsis",
  236. "white-space": "nowrap"
  237. });
  238. } else {
  239. tdom.css({
  240. display: "none"
  241. });
  242. }
  243. });
  244. $(".title-row").css({
  245. display: "flex",
  246. "justify-content": "space-between",
  247. "align-items": "center"
  248. });
  249. // console.log(card);
  250. $(".card").css(
  251. card.color.type === "flat"
  252. ? {
  253. background: card.color.value
  254. }
  255. : {
  256. background:
  257. "linear-gradient(" +
  258. card.color.value.angle +
  259. "deg, " +
  260. card.color.value.stops[0].color +
  261. ", " +
  262. card.color.value.stops[1].color +
  263. ")"
  264. }
  265. );
  266. $(".card").css({
  267. width: "auto",
  268. height: "auto",
  269. // border: "2px solid #000",
  270. "border-color": card.border.borderColor,
  271. "border-width": card.border.borderWidth,
  272. "border-style": card.border.lineStyle,
  273. "border-radius": card.border.borderRadius,
  274. // background: "rgba(0, 0, 0, 0.5)",
  275. "margin-top": card.margin.top,
  276. "margin-right": card.margin.right,
  277. "margin-bottom": card.margin.bottom,
  278. "margin-left": card.margin.left
  279. });
  280. // console.log(cfg);
  281. var zone = cfg.options.zone;
  282. $(".zone").css({
  283. display: "flex",
  284. "flex-direction": zone.direction,
  285. position: "absolute",
  286. top: zone.position.top,
  287. left: zone.position.left,
  288. // width: "100%",
  289. width: zone.size.width,
  290. height: zone.size.height,
  291. overflow: "hidden"
  292. });
  293. // $(".datav-com,.datav-wraper").css({
  294. // width: zone.size.width,
  295. // height: zone.size.height,
  296. // overflow: "hidden"
  297. // });
  298. // $(".-datav-transform-tool").css({
  299. // width: zone.size.width + 24,
  300. // height: zone.size.height + 24
  301. // });
  302. // this.container.css({
  303. // "font-size": cfg.size,
  304. // color: cfg.color || "#fff"
  305. // });
  306. },
  307. /**
  308. * 更新配置
  309. * !!注意:如果render支持第二个参数options, 那updateOptions不是必须的
  310. */
  311. //updateOptions: function (options) {},
  312. /**
  313. * 更新某些配置
  314. * 给可以增量更新配置的组件用
  315. */
  316. //updateXXX: function () {},
  317. /**
  318. * 销毁组件
  319. */
  320. destroy: function() {
  321. console.log("请实现 destroy 方法");
  322. }
  323. }
  324. );

发布组件

您可通过以下三种方式发布组件:

  • 方式一(推荐)进入组件的目录地址下,执行datav publish命令,组件将自动打包压缩发布至账号所在域的服务器。
  • 方式二进入组件的目录地址下,执行datav package命令,在组件目录外会有一个以组件-版本号命名的tar.gz压缩包,将此压缩包上传到datav.aliyun.com的组件页,即可发布。
    • 创建组件包

image.png

  • 方法三进入预览组件页面下的发布页面,单击发布,即可发布组件。

踩坑

问题:datav init 一直报错,

网上搜,说是gulp和node版本不一致
image.png

问题:组件上传不上去

image.png
字面意思是上传超限,实际是命名空间不对应导致;
image.png
组件包英文名:iwhalecloud-poc
image.png
image.png
package.json里也要对应上
image.png
so datav publish
image.png

问题:使用datav login命令,让输入UID和token

image.png
image.png

问题:哪里设置视频自动播放呢?

文档中关于设置视频自动播放的方法不再有用了
image.png
https://gov-mod-asset-zb.oss-cn-zhangjiakou.aliyuncs.com/video/dapindi.mp4

问题:跨域问题,页面打不开

image.png
code: EBADCSRFTOKEN,
message: invalid csrf token,
rid: undefined

image.png
image.png

image.png
Chrome 中打开 chrome://flags/#same-site-by-default-cookies 和 chrome://flags/#cookies-without-same-site-must-be-secure ,设置为 Disabled,重启浏览器