├── timeline-map.png ├── public ├── echarts_timelinemap.html ├── timeline_map.js ├── echarts_timelinemap_editor.html ├── timeline_map.less ├── echarts_timelinemap.js └── echarts_timelinemap_controller.js ├── index.js ├── package.json └── README.md /timeline-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hivefans/timeline_map/HEAD/timeline-map.png -------------------------------------------------------------------------------- /public/echarts_timelinemap.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | export default function (kibana) { 2 | return new kibana.Plugin({ 3 | uiExports: { 4 | visTypes: ['plugins/timeline_map/timeline_map'] 5 | } 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /public/timeline_map.js: -------------------------------------------------------------------------------- 1 | import visTypes from 'ui/registry/vis_types'; 2 | define(function (require) { 3 | visTypes.register(require('plugins/timeline_map/echarts_timelinemap')); 4 | }); 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "timeline_map", 3 | "version": "0.1.01", 4 | "kibana": { 5 | "version": "5.2.0" 6 | }, 7 | "dependencies": { 8 | "echarts": "3.4.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /public/echarts_timelinemap_editor.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 7 |
8 | -------------------------------------------------------------------------------- /public/timeline_map.less: -------------------------------------------------------------------------------- 1 | @import (reference) "~ui/styles/mixins.less"; 2 | 3 | .echart-vis { 4 | width: 100%; 5 | display: flex; 6 | flex-direction: row; 7 | flex-wrap: wrap; 8 | justify-content: space-around; 9 | align-items: center; 10 | align-content: space-around; 11 | 12 | .echart-container { 13 | text-align: center; 14 | padding: 1em; 15 | width:100%; 16 | position:relative; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # timeline_map 2 | Kibana的Echarts 时间轴趋势地图插件 3 | 可以支持省份字段中英文,只支持手动选择日期,自动播放问题待解决。 4 | 5 | ![ScreenShot](https://raw.github.com/hivefans/timeline_map/master/timeline-map.png) 6 | ## 基于: 7 | 8 | Kibana 5.2.0 9 | 10 | Echarts 3.4 11 | 12 | ## 安装方法: 13 | ``` bash 14 | cd node/bin 15 | mv npm npm.bak 16 | ln -s ../lib/node_modules/npm/bin/npm-cli.js npm 17 | cd ../.. 18 | vim package.json 19 | 在engines配置上面增加echarts 20 | "dependencies": { 21 | "echarts": "3.4.0" 22 | }, 23 | "engines": { 24 | "node": "6.9.0" 25 | } 26 | node/bin/npm update 27 | bin/kibana-plugin install https://github.com/hivefans/timeline_map/files/1030552/timeline_map.1.0.1.zip 28 | ``` 29 | -------------------------------------------------------------------------------- /public/echarts_timelinemap.js: -------------------------------------------------------------------------------- 1 | import 'plugins/timeline_map/timeline_map.less'; 2 | import 'plugins/timeline_map/echarts_timelinemap_controller'; 3 | import TemplateVisTypeTemplateVisTypeProvider from 'ui/template_vis_type/template_vis_type'; 4 | import VisSchemasProvider from 'ui/vis/schemas'; 5 | import echartsTimelineMapTemplate from 'plugins/timeline_map/echarts_timelinemap.html'; 6 | import echartsTimelineMapParamsTemplate from 'plugins/timeline_map/echarts_timelinemap_editor.html'; 7 | 8 | 9 | // require('ui/registry/vis_types').register(echartsPieProvider); 10 | 11 | function echartsTimelineMapProvider(Private) { 12 | const TemplateVisType = Private(TemplateVisTypeTemplateVisTypeProvider); 13 | const Schemas = Private(VisSchemasProvider); 14 | // we also need to load the controller and used by the template 15 | // require('plugins/kibana-plugin-echarts/echartsPieController'); 16 | 17 | return new TemplateVisType({ 18 | name: 'timeline_map', 19 | title: 'Echarts timeline Map', 20 | icon: 'fa-map-marker', 21 | description: '数据统计中国地图时间轴趋势', 22 | template: echartsTimelineMapTemplate, 23 | params: { 24 | defaults: { 25 | shareYAxis: true, 26 | addTooltip: true, 27 | addLegend: true, 28 | isDonut: false 29 | }, 30 | editor: echartsTimelineMapParamsTemplate 31 | }, 32 | legendPositions: [{ 33 | value: 'left', 34 | text: 'left', 35 | }, { 36 | value: 'right', 37 | text: 'right', 38 | }, { 39 | value: 'top', 40 | text: 'top', 41 | }, { 42 | value: 'bottom', 43 | text: 'bottom', 44 | }], 45 | responseConverter: false, 46 | hierarchicalData: true, 47 | schemas: new Schemas([{ 48 | group: 'metrics', 49 | name: 'metric', 50 | title: 'Y-Axis', 51 | min: 1, 52 | max: 1, 53 | aggFilter: '!geohash_grid', 54 | defaults: [{ 55 | schema: 'metric', 56 | type: 'count', 57 | }] 58 | }, { 59 | group: 'buckets', 60 | name: 'segment', 61 | icon: 'fa fa-scissors', 62 | title: 'X-Axis', 63 | min: 1, 64 | max: 1, 65 | aggFilter: '!geohash_grid' 66 | }, 67 | { 68 | group: 'buckets', 69 | name: 'group', 70 | title: 'Split Area', 71 | min: 0, 72 | max: 1, 73 | aggFilter: '!geohash_grid' 74 | }]) 75 | }); 76 | }; 77 | 78 | export default echartsTimelineMapProvider; 79 | -------------------------------------------------------------------------------- /public/echarts_timelinemap_controller.js: -------------------------------------------------------------------------------- 1 | import echarts from 'echarts/lib/echarts'; 2 | import 'echarts/lib/chart/map'; 3 | import 'echarts/map/js/china'; 4 | // import 'public_function'; 5 | 6 | var module = require('ui/modules').get('timeline_map'); 7 | 8 | module.controller('EchartsTimelineMapController', function ($scope, $element, $rootScope, Private, Notifier) { 9 | var tabifyAggResponse = Private(require('ui/agg_response/tabify/tabify')); 10 | var notify = new Notifier({ location: 'timeline_map/EchartsTimelineMapController'}); 11 | let mychart = echarts.init($element.get(0)); 12 | let rootElement = $element; 13 | let margin = { 14 | top: 10, 15 | right: 10, 16 | bottom: 10, 17 | left: 10 18 | }; 19 | let width; 20 | let height; 21 | //state.query 22 | var provinces = [ 23 | { name: "anhui", value: "安徽" }, 24 | { name: "beijing", value: "北京" }, 25 | { name: "fujian", value: "福建" }, 26 | { name: "gansu", value: "甘肃" }, 27 | { name: "guangdong", value: "广东" }, 28 | { name: "guangxi", value: "广西" }, 29 | { name: "guizhou", value: "贵州" }, 30 | { name: "hainan", value: "海南" }, 31 | { name: "hebei", value: "河北" }, 32 | { name: "henan", value: "河南" }, 33 | { name: "hubei", value: "湖北" }, 34 | { name: "hunan", value: "湖南" }, 35 | { name: "jilin", value: "吉林" }, 36 | { name: "jiangsu", value: "江苏" }, 37 | { name: "jiangxi", value: "江西" }, 38 | { name: "liaoning", value: "辽宁" }, 39 | { name: "ningxia", value: "宁夏" }, 40 | { name: "qinghai", value: "青海" }, 41 | { name: "shandong", value: "山东" }, 42 | { name: "sanxi", value: "山西" }, 43 | { name: "shanxi", value: "陕西" }, 44 | { name: "shanghai", value: "上海" }, 45 | { name: "sichuan", value: "四川" }, 46 | { name: "tianjin", value: "天津" }, 47 | { name: "xizang", value: "西藏" }, 48 | { name: "xinjiang", value: "新疆" }, 49 | { name: "yunnan", value: "云南" }, 50 | { name: "zhejiang", value: "浙江" }, 51 | { name: "chongqing", value: "重庆" }, 52 | { name: "aomen", value: "澳门" }, 53 | { name: "xianggang", value: "香港" }, 54 | { name: "taiwan", value: "台湾" }, 55 | { name: "heilongjiang", value: "黑龙江" }, 56 | { name: "neimenggu", value: "内蒙古" } 57 | ] 58 | 59 | // 转化省份到汉字 60 | var convertProvince = function (data) { 61 | for (var i = 0; i < provinces.length; i++) { 62 | if (provinces[i].name == data) { 63 | return provinces[i].value; 64 | } 65 | } 66 | // console.log(data) 67 | return "other"; 68 | } 69 | 70 | var getdateformat = function (timestamp){ 71 | var date = new Date(timestamp); 72 | var Y = date.getFullYear() + '-'; 73 | var M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1) + '-'; 74 | var D = (date.getDate() < 10 ? '0'+(date.getDate()) : date.getDate()) + ' '; 75 | var h = (date.getHours() < 10 ? '0'+(date.getHours()) : date.getHours()) + ':'; 76 | var m = (date.getMinutes() < 10 ? '0'+(date.getMinutes()) : date.getMinutes()); 77 | return Y+M+D+h+m; 78 | } 79 | 80 | 81 | var all={}; 82 | var avgArr=[]; 83 | var tableGroups; 84 | $scope.$watch('esResponse', function(resp) { 85 | if (!resp) { 86 | return; 87 | } 88 | tableGroups = tabifyAggResponse($scope.vis, resp); 89 | tableGroups.tables.forEach(function (table,index) { 90 | var cols = table.columns; 91 | var prov_len=0; 92 | var j=0; 93 | all.dates=[]; 94 | all.options=[]; 95 | avgArr = []; 96 | prov_len=cols[2].aggConfig.params.size; 97 | table.rows.forEach(function (row,i) { 98 | var datestr = row[0]; 99 | var region_name = ""; 100 | region_name = row[2].toString(); 101 | var avg_speed = 0; 102 | avg_speed = row[3]; 103 | avg_speed=avg_speed.toFixed(2); 104 | 105 | if(all.dates.indexOf(getdateformat(datestr))===-1){ 106 | all.dates.push(getdateformat(datestr)); 107 | all.options.push( 108 | { 109 | "series":[{ 110 | "data":[] 111 | }] 112 | } 113 | ); 114 | j=j+1; 115 | } 116 | 117 | avgArr.push(avg_speed); 118 | if(escape(region_name).indexOf("%u")<0) { 119 | region_name = convertProvince(region_name); 120 | } 121 | all.options[j-1].series[0].data.push( 122 | { 123 | name:region_name, 124 | value:avg_speed 125 | } 126 | ) 127 | }); 128 | }); 129 | 130 | var option={}; 131 | option = { 132 | baseOption: { 133 | timeline: { 134 | axisType: 'category', 135 | orient: 'vertical', 136 | autoPlay: true, 137 | inverse: true, 138 | playInterval: 5000, 139 | left: 10, 140 | right: null, 141 | top: 20, 142 | bottom: 20, 143 | width: 120, 144 | height: null, 145 | label: { 146 | emphasis: { 147 | textStyle: { 148 | color: '#fff' 149 | }, 150 | "show":true 151 | }, 152 | normal: { 153 | "show": true 154 | } 155 | }, 156 | symbol: 'none', 157 | lineStyle: { 158 | color: '#555' 159 | }, 160 | checkpointStyle: { 161 | color: '#bbb', 162 | borderColor: '#777', 163 | borderWidth: 2 164 | }, 165 | controlStyle: { 166 | showNextBtn: true, 167 | showPrevBtn: true, 168 | normal: { 169 | color: '#666', 170 | borderColor: '#666' 171 | }, 172 | emphasis: { 173 | color: '#aaa', 174 | borderColor: '#aaa' 175 | } 176 | }, 177 | data: all.dates 178 | }, 179 | tooltip: { 180 | }, 181 | series: [{ 182 | type: 'map', 183 | name: '数据统计', 184 | map: 'china', 185 | roam: false, 186 | label: { 187 | "emphasis": { 188 | "show": true 189 | }, 190 | "normal": { 191 | "show": true 192 | } 193 | } 194 | }], 195 | animationDurationUpdate: 1000, 196 | animationEasingUpdate: 'quinticInOut', 197 | visualMap: { 198 | min:0, 199 | max: 500, 200 | left: 'right', 201 | top: 'bottom', 202 | text: ['高','低'], 203 | calculable: true, 204 | inRange: { 205 | color: ['#0ba800','#eac736','#d94e5d'] 206 | } 207 | } 208 | }, 209 | options: all.options 210 | }; 211 | 212 | mychart.clear(); 213 | option.baseOption.visualMap.max=Math.max.apply(Math, avgArr); 214 | mychart.setOption(option,true); 215 | width = $(rootElement).width() - margin.left - margin.right; 216 | height = $(rootElement).height() - margin.top - margin.bottom; 217 | mychart.resize({ 218 | option, 219 | width, 220 | height 221 | }); 222 | return notify.timed('Echarts Map Controller', resp); 223 | }); 224 | 225 | // Automatic resizing of graphics 226 | $scope.$watch( 227 | function () { 228 | width = $(rootElement).width() - margin.left - margin.right; 229 | height = $(rootElement).height() - margin.top - margin.bottom; 230 | mychart.resize({ 231 | width, 232 | height 233 | }); 234 | }, 235 | true 236 | ); 237 | }); 238 | 239 | --------------------------------------------------------------------------------