上传文件
上传文件的后端服务
使用Python Flask实现。
import os
from flask import Flask, request, redirect, url_for, send_from_directory
from werkzeug import secure_filename
from flask_cors import CORS
UPLOAD_FOLDER = '/path/to/the/uploads'
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
app = Flask(__name__)
CORS(app)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
@app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
file = request.files['file']
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('uploaded_file',
filename=filename))
return '''
Upload new File
Upload new File
'''
@app.route('/uploads/')
def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'],
filename)
解决跨域访问,需安装flask-cors
上传组件
使用Element UI实现
// action指定上传文件后台服务, on-success指定上传成功后执行的方法
点击上传
只能上传txt文件,分隔符为\t
// 在Vue中指定数据fileName、计算属性fileContent、以及上传成功后的方法handleSuccess
new Vue({
el: '#app',
data: {
fileName: null
},
computed: {
fileContent: function() {
if(this.fileName != null) {
return this.fileName.response;
}
}
},
methods: {
handleSuccess: function(response, file, fileList) {
this.fileName = file;
return this.$confirm(`上传 ${ file.name }成功!`);
}
}
});
TSV解析
使用d3-dsv库。
d3.tsvParse("foo\tbar\n1\t2"); // [{foo: "1", bar: "2"}, columns: ["foo", "bar"]]
表格
使用v-for实现动态列名
JS数组操作
资料
创建、排序、删除、追加、reverse、slice、join转字符串、concat拼接数组、forEach循环
JS字符串操作
split拆分、parseInt等类型转换
事件
表格点击行事件
Leaflet组件
Vue.component("leaflet", {
props: ['table_data', 'selected_row'],
data() {
return {
map: null,
layer: null,
point: null
};
},
template: '',
mounted: function() {
this.init();
this.update();
this.highlight();
},
watch: {
table_data: function () {
this.update();
},
selected_row: function() {
this.highlight();
}
},
methods: {
init: function() {
this.map = L.map(this.$el.id).setView([29.802946,106.396835], zoom = 10);
L.tileLayer(
'https://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0',
{
maxZoom: 18,
subdomains: "0123",
tms: true,
attribution: '© 腾讯地图',
}
).addTo(this.map);
},
update: function() {
if(this.layer != null) this.layer.removeFrom(this.map);
if(this.point != null) this.point.removeFrom(this.map);
// 绘制数据
var markerArray = Array();
this.table_data.forEach((pnt) => {
var date = new Date(pnt['collecttime']*1000);
markerArray.push(L.circle([pnt["bmuserlat"], pnt["bmuserlng"]]).bindTooltip(date+""));
// L.circle([pnt["bmuserlat"], pnt["bmuserlng"]], {radius:15}).addTo(this.map);
});
this.layer = L.featureGroup(markerArray).addTo(this.map);
this.map.fitBounds(this.layer.getBounds());
},
highlight: function() {
if(this.point != null) this.point.removeFrom(this.map);
// 绘制选中点
if(this.selected_row != null) {
this.point = L.circleMarker([this.selected_row['bmuserlat'], this.selected_row['bmuserlng']], {color: "red"}).addTo(this.map).bindPopup(this.selected_row['collecttime'] + "");
}
}
}
});
ECharts组件
Vue.component('echarts-heatmap', {
props: ['table_data'],
data: function() {
return {
map: null
}
},
computed: {
plot_data: function() {
//GCJ-02 to BD-09
function bd_encrypt(gcjLat, gcjLon)
{
x_pi = 3.14159265358979324 * 3000.0 / 180.0;
var x = gcjLon, y = gcjLat;
var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
var bdLon = z * Math.cos(theta) + 0.0065;
var bdLat = z * Math.sin(theta) + 0.006;
return { 'lat': bdLat, 'lon': bdLon };
}
var heatArray = Array();
this.table_data.forEach(function(item) {
var x = Math.round(item['bmuserlng'] * 1000) / 1000;
var y = Math.round(item['bmuserlat'] * 1000) / 1000;
var res = bd_encrypt(y, x);
var x = res.lon;
var y = res.lat;
var idx = item["color_idx"]
heatArray.push([x, y, idx]);
});
var heatMap = [];
heatArray.reduce(function(res, value){
if(!res[value]) {
res[value] = value;
heatMap.push(value);
}
return res;
}, {});
var result = [];
heatMap.reduce(function(res, value) {
k = [value[0], value[1]]
if(!res[k]) {
res[k] = [value[0], value[1], 0];
result.push(res[k]);
}
res[k][2] += 1;
return res;
}, {});
var max = 0;
result.reduce(function(res, value){
if(res < value[2]) {
res = value[2];
max = res;
}
return res;
}, 0);
//result = result.filter(word => word[2] == max);
console.log(result);
return(result);
},
option: function() {
var points = this.plot_data;
center = points.reduce(function(res, value){
return [res[0] + value[0], res[1] + value[1]];
}, [0,0]);
let center_x = center[0] / points.length;
let center_y = center[1] / points.length;
return {
animation: false,
bmap: {
center: [center_x, center_y],
zoom: 14,
roam: true
},
visualMap: {
show: false,
top: 'top',
min: 0,
max: 5,
seriesIndex: 0,
calculable: true,
inRange: {
color: ['blue', 'blue', 'green', 'yellow', 'red']
}
},
series: [{
type: 'heatmap',
coordinateSystem: 'bmap',
data: points,
pointSize: 5,
blurSize: 6
}]}
}
},
template: '',
mounted: function() {
this.initMap();
this.updateMap();
},
watch: {
table_data: function() {
this.updateMap();
}
},
methods: {
initMap: function() {
this.map = echarts.init(this.$el);
} ,
updateMap: function() {
var app = {};
app.title = '热力图与百度地图扩展';
this.map.setOption(option = this.option);
var bmap = this.map.getModel().getComponent('bmap').getBMap();
bmap.addControl(new BMap.MapTypeControl());
this.map.setOption(option, true);
}
}
});