mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
feat: add g2-ssr
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
components.d.ts
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
package-lock.json
|
||||
Binary file not shown.
@@ -0,0 +1,81 @@
|
||||
const http = require('http');
|
||||
const url = require("url");
|
||||
const util = require('util');
|
||||
const { createChart } = require('@antv/g2-ssr');
|
||||
const port = 3000;
|
||||
const { getPieOptions } = require('./charts/pie.js');
|
||||
const { getLineOptions } = require('./charts/line.js');
|
||||
const { getColumnOptions } = require('./charts/column.js');
|
||||
const { getBarOptions } = require('./charts/bar.js');
|
||||
|
||||
http.createServer((req, res) => {
|
||||
res.statusCode = 200,
|
||||
res.setHeader('Content-Type', 'text/plain;charset=utf-8');
|
||||
if (req.method === 'GET') {
|
||||
toGet(req, res);
|
||||
} else if (req.method === 'POST') {
|
||||
toPost(req, res);
|
||||
}
|
||||
}).listen(port, () => {
|
||||
console.log(`Server listening on: http://localhost:${port}`);
|
||||
});
|
||||
|
||||
function getOptions(type, axis, data) {
|
||||
|
||||
const base_options = {
|
||||
width: 640,
|
||||
height: 480,
|
||||
imageType: 'png',
|
||||
theme: {
|
||||
view: {
|
||||
viewFill: '#FFFFFF',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'bar':
|
||||
return getBarOptions(base_options, axis, data);
|
||||
case 'column':
|
||||
return getColumnOptions(base_options, axis, data);
|
||||
case 'line':
|
||||
return getLineOptions(base_options, axis, data);
|
||||
case 'pie':
|
||||
return getPieOptions(base_options, axis, data);
|
||||
}
|
||||
|
||||
return base_options
|
||||
}
|
||||
|
||||
|
||||
// 创建 Chart 和配置
|
||||
async function GenerateCharts(obj) {
|
||||
console.log(obj)
|
||||
const options = getOptions(obj.type, JSON.parse(obj.axis), JSON.parse(obj.data));
|
||||
console.log(options);
|
||||
const chart = await createChart(options);
|
||||
|
||||
// 导出
|
||||
chart.exportToFile(obj.path || 'chart');
|
||||
// -> chart.png
|
||||
|
||||
chart.toBuffer();
|
||||
}
|
||||
|
||||
// -> get buffer
|
||||
|
||||
|
||||
//获取GET请求内容
|
||||
function toGet(req, res) {
|
||||
let data = 'GET请求内容:\n' + util.inspect(url.parse(req.url));
|
||||
res.end(data);
|
||||
console.log(data);
|
||||
}
|
||||
|
||||
//获取POST请求内容、cookie
|
||||
function toPost(req, res) {
|
||||
req.on('data', async function (chunk) {
|
||||
await GenerateCharts(JSON.parse(chunk))
|
||||
res.end('complete');
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
const {checkIsPercent} = require("./utils");
|
||||
|
||||
function getBarOptions(baseOptions, axis, data) {
|
||||
|
||||
const x = axis.filter((item) => item.type === 'x')
|
||||
const y = axis.filter((item) => item.type === 'y')
|
||||
const series = axis.filter((item) => item.type === 'series')
|
||||
|
||||
if (x.length === 0 || y.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const _data = checkIsPercent(y[0], data)
|
||||
|
||||
const options = {
|
||||
...baseOptions,
|
||||
type: 'interval',
|
||||
data: _data.data,
|
||||
coordinate: {transform: [{type: 'transpose'}]},
|
||||
encode: {
|
||||
x: x[0].value,
|
||||
y: y[0].value,
|
||||
color: series.length > 0 ? series[0].value : undefined,
|
||||
},
|
||||
style: {
|
||||
radiusTopLeft: (d) => {
|
||||
if (d[y[0].value] && d[y[0].value] > 0) {
|
||||
return 4
|
||||
}
|
||||
return 0
|
||||
},
|
||||
radiusTopRight: (d) => {
|
||||
if (d[y[0].value] && d[y[0].value] > 0) {
|
||||
return 4
|
||||
}
|
||||
return 0
|
||||
},
|
||||
radiusBottomLeft: (d) => {
|
||||
if (d[y[0].value] && d[y[0].value] < 0) {
|
||||
return 4
|
||||
}
|
||||
return 0
|
||||
},
|
||||
radiusBottomRight: (d) => {
|
||||
if (d[y[0].value] && d[y[0].value] < 0) {
|
||||
return 4
|
||||
}
|
||||
return 0
|
||||
},
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
title: x[0].name,
|
||||
labelFontSize: 12,
|
||||
labelAutoHide: {
|
||||
type: 'hide',
|
||||
keepHeader: true,
|
||||
keepTail: true,
|
||||
},
|
||||
labelAutoRotate: false,
|
||||
labelAutoWrap: true,
|
||||
labelAutoEllipsis: true,
|
||||
},
|
||||
y: {title: y[0].name},
|
||||
},
|
||||
scale: {
|
||||
x: {
|
||||
nice: true,
|
||||
},
|
||||
y: {
|
||||
nice: true,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
elementHighlight: {background: true},
|
||||
},
|
||||
tooltip: (data) => {
|
||||
if (series.length > 0) {
|
||||
return {
|
||||
name: data[series[0].value],
|
||||
value: `${data[y[0].value]}${_data.isPercent ? '%' : ''}`,
|
||||
}
|
||||
} else {
|
||||
return {name: y[0].name, value: `${data[y[0].value]}${_data.isPercent ? '%' : ''}`}
|
||||
}
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
text: (data) => {
|
||||
const value = data[y[0].value]
|
||||
if (value === undefined || value === null) {
|
||||
return ''
|
||||
}
|
||||
return `${value}${_data.isPercent ? '%' : ''}`
|
||||
},
|
||||
transform: [
|
||||
{type: 'contrastReverse'},
|
||||
{type: 'exceedAdjust'},
|
||||
{type: 'overlapHide'},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
if (series.length > 0) {
|
||||
options.transform = [{type: 'stackY'}]
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
module.exports = {getBarOptions}
|
||||
@@ -0,0 +1,113 @@
|
||||
const {checkIsPercent} = require("./utils");
|
||||
|
||||
function getColumnOptions(baseOptions, axis, data) {
|
||||
|
||||
const x = axis.filter((item) => item.type === 'x')
|
||||
const y = axis.filter((item) => item.type === 'y')
|
||||
const series = axis.filter((item) => item.type === 'series')
|
||||
|
||||
if (x.length === 0 || y.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const _data = checkIsPercent(y[0], data)
|
||||
|
||||
const options = {
|
||||
...baseOptions,
|
||||
type: 'interval',
|
||||
data: _data.data,
|
||||
encode: {
|
||||
x: x[0].value,
|
||||
y: y[0].value,
|
||||
color: series.length > 0 ? series[0].value : undefined,
|
||||
},
|
||||
style: {
|
||||
radiusTopLeft: (d) => {
|
||||
if (d[y[0].value] && d[y[0].value] > 0) {
|
||||
return 4
|
||||
}
|
||||
return 0
|
||||
},
|
||||
radiusTopRight: (d) => {
|
||||
if (d[y[0].value] && d[y[0].value] > 0) {
|
||||
return 4
|
||||
}
|
||||
return 0
|
||||
},
|
||||
radiusBottomLeft: (d) => {
|
||||
if (d[y[0].value] && d[y[0].value] < 0) {
|
||||
return 4
|
||||
}
|
||||
return 0
|
||||
},
|
||||
radiusBottomRight: (d) => {
|
||||
if (d[y[0].value] && d[y[0].value] < 0) {
|
||||
return 4
|
||||
}
|
||||
return 0
|
||||
},
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
title: x[0].name,
|
||||
labelFontSize: 12,
|
||||
labelAutoHide: {
|
||||
type: 'hide',
|
||||
keepHeader: true,
|
||||
keepTail: true,
|
||||
},
|
||||
labelAutoRotate: false,
|
||||
labelAutoWrap: true,
|
||||
labelAutoEllipsis: true,
|
||||
},
|
||||
y: {title: y[0].name},
|
||||
},
|
||||
scale: {
|
||||
x: {
|
||||
nice: true,
|
||||
},
|
||||
y: {
|
||||
nice: true,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
elementHighlight: {background: true},
|
||||
},
|
||||
tooltip: (data) => {
|
||||
if (series.length > 0) {
|
||||
return {
|
||||
name: data[series[0].value],
|
||||
value: `${data[y[0].value]}${_data.isPercent ? '%' : ''}`,
|
||||
}
|
||||
} else {
|
||||
return {name: y[0].name, value: `${data[y[0].value]}${_data.isPercent ? '%' : ''}`}
|
||||
}
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
text: (data) => {
|
||||
const value = data[y[0].value]
|
||||
if (value === undefined || value === null) {
|
||||
return ''
|
||||
}
|
||||
return `${value}${_data.isPercent ? '%' : ''}`
|
||||
},
|
||||
position: 'top',
|
||||
dy: -25,
|
||||
transform: [
|
||||
{type: 'contrastReverse'},
|
||||
{type: 'exceedAdjust'},
|
||||
{type: 'overlapHide'},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
if (series.length > 0) {
|
||||
options.transform = [{type: 'stackY'}]
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
module.exports = {getColumnOptions}
|
||||
@@ -0,0 +1,97 @@
|
||||
const {checkIsPercent} = require("./utils");
|
||||
|
||||
function getLineOptions(baseOptions, axis, data) {
|
||||
|
||||
const x = axis.filter((item) => item.type === 'x')
|
||||
const y = axis.filter((item) => item.type === 'y')
|
||||
const series = axis.filter((item) => item.type === 'series')
|
||||
|
||||
if (x.length === 0 || y.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const _data = checkIsPercent(y[0], data)
|
||||
|
||||
const options = {
|
||||
...baseOptions,
|
||||
type: 'view',
|
||||
data: _data.data,
|
||||
encode: {
|
||||
x: x[0].value,
|
||||
y: y[0].value,
|
||||
color: series.length > 0 ? series[0].value : undefined,
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
title: x[0].name,
|
||||
labelFontSize: 12,
|
||||
labelAutoHide: {
|
||||
type: 'hide',
|
||||
keepHeader: true,
|
||||
keepTail: true,
|
||||
},
|
||||
labelAutoRotate: false,
|
||||
labelAutoWrap: true,
|
||||
labelAutoEllipsis: true,
|
||||
},
|
||||
y: {title: y[0].name},
|
||||
},
|
||||
scale: {
|
||||
x: {
|
||||
nice: true,
|
||||
},
|
||||
y: {
|
||||
nice: true,
|
||||
},
|
||||
},
|
||||
children: [
|
||||
{
|
||||
type: 'line',
|
||||
encode: {
|
||||
shape: 'smooth',
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
text: (data) => {
|
||||
const value = data[y[0].value]
|
||||
if (value === undefined || value === null) {
|
||||
return ''
|
||||
}
|
||||
return `${value}${_data.isPercent ? '%' : ''}`
|
||||
},
|
||||
style: {
|
||||
dx: -10,
|
||||
dy: -12,
|
||||
},
|
||||
transform: [
|
||||
{type: 'contrastReverse'},
|
||||
{type: 'exceedAdjust'},
|
||||
{type: 'overlapHide'},
|
||||
],
|
||||
},
|
||||
],
|
||||
tooltip: (data) => {
|
||||
if (series.length > 0) {
|
||||
return {
|
||||
name: data[series[0].value],
|
||||
value: `${data[y[0].value]}${_data.isPercent ? '%' : ''}`,
|
||||
}
|
||||
} else {
|
||||
return {name: y[0].name, value: `${data[y[0].value]}${_data.isPercent ? '%' : ''}`}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'point',
|
||||
style: {
|
||||
fill: 'white',
|
||||
},
|
||||
tooltip: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
module.exports = {getLineOptions}
|
||||
@@ -0,0 +1,41 @@
|
||||
const {checkIsPercent} = require("./utils");
|
||||
|
||||
function getPieOptions(baseOptions, axis, data) {
|
||||
|
||||
const y = axis.filter((item) => item.type === 'y')
|
||||
const series = axis.filter((item) => item.type === 'series')
|
||||
|
||||
if (series.length === 0 || y.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const _data = checkIsPercent(y[0], data)
|
||||
|
||||
return {
|
||||
...baseOptions,
|
||||
type: 'interval',
|
||||
coordinate: {type: 'theta', outerRadius: 0.8},
|
||||
transform: [{type: 'stackY'}],
|
||||
data: _data.data,
|
||||
encode: {
|
||||
y: y[0].value,
|
||||
color: series[0].value,
|
||||
},
|
||||
legend: {
|
||||
color: {position: 'bottom', layout: {justifyContent: 'center'}},
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
position: 'outside',
|
||||
text: (data) =>
|
||||
`${data[series[0].value]}: ${data[y[0].value]}${_data.isPercent ? '%' : ''}`,
|
||||
},
|
||||
],
|
||||
tooltip: (data) => {
|
||||
return {name: y[0].name, value: `${data[y[0].value]}${_data.isPercent ? '%' : ''}`}
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = {getPieOptions}
|
||||
@@ -0,0 +1,37 @@
|
||||
const {filter, endsWith, replace} = require("lodash-es");
|
||||
|
||||
function checkIsPercent(valueAxis, data) {
|
||||
const result = {
|
||||
isPercent: false,
|
||||
data: [],
|
||||
}
|
||||
|
||||
const notEmptyData = filter(
|
||||
data,
|
||||
(d) =>
|
||||
d &&
|
||||
d[valueAxis.value] !== null &&
|
||||
d[valueAxis.value] !== undefined &&
|
||||
d[valueAxis.value] !== 0 &&
|
||||
d[valueAxis.value] !== '0'
|
||||
)
|
||||
if (notEmptyData.length > 0) {
|
||||
const v = notEmptyData[0][valueAxis.value] + ''
|
||||
if (endsWith(v.trim(), '%')) {
|
||||
result.isPercent = true
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const v = data[i]
|
||||
const _v = {...v}
|
||||
if (result.isPercent) {
|
||||
const formatValue = replace(v[valueAxis.value], '%', '')
|
||||
_v[valueAxis.value] = Number(formatValue)
|
||||
}
|
||||
result.data.push(_v)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
module.exports = {checkIsPercent}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "vite-project",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@antv/g2": "^5.3.3",
|
||||
"@antv/g2-ssr": "^0.1.0",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nan": "^2.22.2",
|
||||
"node-canvas": "^2.9.0",
|
||||
"nprogress": "^0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.6.3",
|
||||
"@types/nprogress": "^0.2.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user