hyeditor-sdk v1.3.5
组件开发环境(SDK)
1.为什么要有这个?
帮助开发人员快速开发符合"海云可视化页面编辑器"规范的组件.
2.功能
本地编辑器编写代码后,浏览器自动刷新,可看见最新组件的效果.
提供常用工具函数 (todo)
自动打包
提供组件接口测试:
- Json,Excel,RESTful API,数据库 (todo)
- 基础样式 (todo)
- 属性 (todo)
- 事件 (todo)
3.目录结构
整体目录结构
sdk
|- components (编写组件的源码目录)
|- .components (组件编译后的目录)
|- .sdk (sdk代码目录))
|- package.json
components目录规范
components
|- /button (单个组件的目录)
|- /v1.0 (组件版本号)
|- index.js (组件入口)
|- preview.jpg (组件预览图)
...
|- v2.0
其中入口文件index后缀可为.js或.jsx
可引入模块(.js,.jsx)
可引入资源(json,图片,css)
单个组件的代码与资源必须在对应组件对应版本的文件夹之下
4.启动SDK
- 安装依赖
npm install
- 启动
在sdk根目录中执行
npm start
如果出现权限错误,请以管理员身份执行命令
sudo npm start
如果浏览器没有自动打开,请手动打开地址
http://localhost:3000
5.快速开始
编写一个简单的按钮组件
1. 建立组件目录
components
|- /button (组件名称)
|- /v1.0 (组件版本号)
|- index.jsx (组件入口)
|- preview.jpg (组件预览图)
2. 写一个component
海云可视化页面编辑器的组件都以React组件编写.
import React, { Component } from 'react';
class Button extends Component {
render() {
return (
<div style={this.props.style}>
<button>这是个按钮</button>
</div>
)
}
}
规范:
组件必须以一个div包裹,其style={this.props.style}
不能在最外层div使用ref
3. 写一个reducer和initialState
const initialState = {
name: '按钮',
style: {
width: '80px',
height: '35px',
}
};
function reducer(action, state = initialState) {
switch (action.type) {
default:
return state;
}
}
reducer: (其文档待完善)
完成编辑器与组件交互,返回的state会以props形式传递给组件
概念类似redux中的reducer
纯函数无副作用
返回plain object
initialState: (其文档待完善)
状态,会传递给组件
{
name: string // 组件名称
style: {
... // react格式的style
}
}
4. option(其文档待完善)
组件配置项
interface IState {
// 名称
name: string;
// 样式
style: Partial<React.CSSProperties & IBaseStyle>;
// 属性
property?: {
color?: string[] | string; // 颜色
title?: { // 标题
show: boolean; // 显示
text: string; // 标题文字
style: {
textAlign: 'left' | 'center' | 'right'; // 对齐
fontSize: string; // 字体大小
color: string; // 颜色
};
};
text?: { // 文本
value: string; // 文本文字
style: {
fontSize: string; // 字体大小
fontStyle: 'normal' | 'italic'; // 字体样式
fontWeight: 'normal' | 'lighter' | 'bold'; // 字体重量
textAlign: 'left' | 'center' | 'right'; // 对齐
lineHeight: string; // 行高
color: string; // 文字颜色
}
};
xAxis?: IAxis<'X'>; // x轴
yAxis?: IAxis<'Y'>; // y轴
img?: string; // 图片(路径)
video?: string; // 视频(路径)
};
// 数据
data?: {
type: 'json' | 'excel' | 'api' | 'database'; // 当前数据的格式 (兼容dataType)
json?: object; // json格式的数据
excel?: { // excel表格格式的数据
columns: Array<{ key: string; name: string }>; // 表头
rows: object[]; // 行
};
api?: { // api的配置
data: any, // api返回的数据
forms: {
url: string; // api路径
static: boolean; // 是否保存静态数据不再发起请求
fields?: string[]; // 字段
xAxis?: string; // x轴
yAxis?: Array<{ id: number | string; name: string; value: string[] }>; // y轴序列
}
}; // api格式的数据
database?: any; // 数据库格式的数据
};
}
5. 如何配置数据源面板
1.配置database
⑴. 配置initialState格式
const initialState={
//数据面板属性
data:{
type:'database', //数据类型
api?: { // api的配置
data: any, // api返回的数据
forms: {
url: string; // api路径
static: boolean; // 是否保存静态数据不再发起请求
fields?: string[]; // 字段
xAxis?: string; // x轴
yAxis?: Array<{ id: number | string; name: string;value?: string[] }>; // y轴序列
}
}, // api格式的数据
// 数据库格式的数据
database?: {
data:any, //数据库返回的数据
forms:{
xAxis?:string[]; //x轴
yAxis?:Array<{ id: number | string; name: string;value?: string[] }>; //y轴
fields?:boolean; //字段筛选
}
};
}
}
⑵. 将返回的查询数据与表单设置的条件进行过滤转换 以封装echart柱状图为例
// 数据源
data=[
{
name:"张三",
age:22,
job:"程序员"
},{
name:"李四",
age:25,
job:"运营"
}
]
//form条件
{
xAxis:'name',
yAxis:['age'],
fields:[] //一般用于饼图,雷达图等非笛卡尔坐标系图形
}
//数据转换
const {data,forms}=this.props.data.database
const {xAxis,yAxis}=forms
const chartOption={}
//处理x轴数据
const xAxisFields=data.map(c=>c[xAxis])
//处理y轴数据
const yAxisFields=[]
data.forEach(c=>{
for(let k in c){
if(yAxis.indexOf(k)!==-1){
yAxisFields.push({
name:k,
value:c[k]
})
}
}
})
//设置x轴
chartOption.xAxis={
type:"category",
data:xAxisFields
}
//遍历series
chartOption.series=yAxis.map(c=>{
return {
type:'bar',
data:yAxisFields.map(d=>{
if(d.name===c){
return d.value
}
})
}
})
myCharts.setOption(chartOption)
⑶.注意事项
⒈y轴数据必须为可量化的数据,一般为整数或浮点数
⒉数据源面板fields属性为统计类图形属性,返回当前分类汇总总数,一般用于饼图,雷达图,漏斗图等图形
2 配置api
//api的配置与database类似 只是initialState.data.forms 有所不同 多了url 和 static两个属性
const initialState={
//数据面板属性
data:{
type:'database', //数据类型
api?: { // api的配置
data: any, // api返回的数据
forms: {
url: string; // api路径
static: boolean; // 是否保存静态数据不再发起请求
fields?: string[]; // 字段
xAxis?: string; // x轴
yAxis?: Array<{ id: number | string; name: string;value?: string[] }>; // y轴序列
}
}, // api格式的数据
}
}
//组件数据合并参考database数据转换
3 配置json
const initialState={
data:{
type:'json',
json:[
{
name:'张三',
value:'22'
}
]
}
}
//组件数据合并参考database数据转换
4 配置excel
const initialState={
data:{
type:'json',
excel:{
columns: [{ key: 'date', name: '日期' }, { key: 'num', name: '数量' }], // 表头
rows: [{ // 行
date: 'Mon',
num: 820
}, {
date: 'Tue',
num: 932
}, {
date: 'Wed',
num: 901
}]
}
}
}
//组件数据合并参考database数据转换
6. 导出
默认导出
export default {
reducer: reducer,
component: Button,
option
};
完整代码
import React, { Component } from 'react';
const initialState = {
name: '按钮',
style: {
width: '80px',
height: '35px',
}
};
function reducer(action, state = initialState) {
switch (action.type) {
default:
return state;
}
}
const option = {
resizer: true,
widget: {
style: {
base: true
}
}
};
class Button extends Component {
render() {
return (
<div style={this.props.style}>
<button>这是个按钮</button>
</div>
)
}
}
export default {
reducer: reducer,
component: Button,
option
};
6.命名规范
class选择器与id选择器以 作者-组件名称-xxx命名
例如作者whj,组件名button:
<div className='whj-button-xxx'></div>
7.现支持的包
- d3
- echarts
- lodash
- react
- react-dom
- immutability-helper
- jquery
- echarts-gl
8.数据格式规范
- 文本格式
{
value: string
}
- 普通name/value数据格式(适用范围:圆环图、饼图、玫瑰图等)
[
{ name: '景洪港口', value: 10 },
{ name: '超市', value: 30 },
{ name: '飞机场', value: 15 },
{ name: '医院', value: 56 },
{ name: '法院', value: 70 },
{ name: '车站', value: 70 }
]
PS:该数据格式echarts原生支持,不需要做额外处理。如果需要,数组内的每个对象可以自定义属性,然后在组件内自行做数据处理,如:
[
{ name: '景洪港口', value: 10, value2: 22 },
{ name: '超市', value: 30, address: 'xxxxx' },
{ name: '飞机场', value: 15 },
{ name: '医院', value: 56 },
{ name: '法院', value: 70 },
{ name: '车站', value: 70 }
]
- 直角坐标系图表数据格式(适用范围:柱状图、折线图、面积图等)
[
{ axis: '10-01', data: [{ name: '全部', value: 10 }, { name: '分类一', value: 15 }, { name: '分类二', value: 13 }] },
{ axis: '10-08', data: [{ name: '全部', value: 16 }, { name: '分类一', value: 20 }, { name: '分类二', value: 14 }] },
{ axis: '10-15', data: [{ name: '全部', value: 13 }, { name: '分类一', value: 27 }, { name: '分类二', value: 20 }] },
{ axis: '10-22', data: [{ name: '全部', value: 16 }, { name: '分类一', value: 11 }, { name: '分类二', value: 17 }] },
{ axis: '10-29', data: [{ name: '全部', value: 19 }, { name: '分类一', value: 22 }, { name: '分类二', value: 15 }] },
{ axis: '11-05', data: [{ name: '全部', value: 14 }, { name: '分类一', value: 17 }, { name: '分类二', value: 21 }] }
]
PS:属性解释:
axis:解析为echarts
的 axis.type='category' 的一条轴(类目轴)的数据。(例如:如果是x轴,则柱状图表现于x轴;如果是y轴,则柱状图垂直于y轴)
data:图形数据集
name: 解析为图例数据,即 echarts.legend 的数据
value:解析为echarts
坐标系内生成图形的数据集。
该数据格式转换为echarts的option所需格式的函数:(仅供参考,写组件时请根据具体情况加以修改)
function dataSet() {
const { props } = this
const { json } = this.props.data
// 准备数据
const legend = []
const xAxis = []
const yAxis = []
const axisData1 = []
const axisData2 = []
const axisData3 = []
json.forEach((o, i) => {
xAxis.push(o.axis)
o.graphics.forEach((ov, oi) => {
legend[oi] = ov.name
if(oi === 0) {
axisData1[i] = ov.value
} else if(oi === 1) {
axisData2[i] = ov.value
} else {
axisData3[i] = ov.value
}
})
})
props.chartOpt.legend.data = legend
props.chartOpt.xAxis[0].data = xAxis
props.chartOpt.yAxis[0].data = yAxis
props.chartOpt.series[0].name = legend[0]
props.chartOpt.series[0].data = axisData1
props.chartOpt.series[1].name = legend[1]
props.chartOpt.series[1].data = axisData2
props.chartOpt.series[2].name = legend[2]
props.chartOpt.series[2].data = axisData3
}
- 地图数据格式
{
points: [ // 地图标点项,若没有标点请不要配置此项
{
name: 'name', // 该标点的名称
location: 'xx', // 该标点所在行政地域名称
coord: [124.03983, 42.999248], // 该标点的坐标,坐标可在http://api.map.baidu.com/lbsapi/getpoint/index.html拾取
id: 'ee02c217d34911e89c790235d2b38928', // 该点的uid,用于和后台交互数据使用
xxx: '' // 如需要,请自行在这里添加额外字段,并在组件内部做响应的逻辑处理
}
],
visualMap: { // echarts 的 visualMap
min: 0, // 最小值
max: 5, // 最大值
},
data: [ // 地图板块数据配置
{ name: '北京', value: 0 },
{ name: '天津', value: 2 },
{ name: '上海', value: 5 }
],
xxx: {} // 其他数据请在下面自行添加
}
PS: data
里面的name必须和 geoJson 文件里面的 name 属性相对应,否则地图数据不能匹配成功
- 水球图数据格式
[0.7, 0.6, 0.65]
PS:数组内的每一个0-1的小数表示一层波浪,需要几层波浪就设置几个小数,且第一个小数为水球图的值,且会显示到水球中央
- 极坐标系图表数据格式(适用:雷达图等)
{
indicator: [
{ name: '销售', max: 100 },
{ name: '管理', max: 100 },
{ name: '信息技术', max: 100 },
{ name: '客服', max: 100 },
{ name: '研发', max: 100 },
{ name: '市场', max: 100 }
],
data: [
{
type: '预算分配',
value: [
{ name: '销售', value: 45 },
{ name: '市场', value: 65 },
{ name: '研发', value: 84 },
{ name: '客服', value: 34 },
{ name: '信息技术', value: 65 },
{ name: '管理', value: 76 }
]
},
{
type: '实际开销',
value: [
{ name: '销售', value: 13 },
{ name: '市场', value: 34 },
{ name: '研发', value: 65 },
{ name: '客服', value: 87 },
{ name: '信息技术', value: 45 },
{ name: '管理', value: 62 }
]
}
]
}
PS:属性解释
indicator:极轴的文本和最大值
data: 极坐标系图形数据集
data.type: 极坐标系图例文本,处理数据后为echarts的legend
data.value: 极坐标系图形数据集,数组内的每个对象对应indicator所表示的每条极轴
该数据格式转换为echarts的option所需格式的函数:(仅供参考,写组件时请根据具体情况加以修改)
function renderChart() {
const { data: { json }, option } = this.props
const newOption = option
const legend = []
const data = []
json.data.map((o) => {
legend.push(o.type)
data.push({
name: o.type,
value: (() => {
const temp = []
json.indicator.map((oi, i) => {
o.value.map((ov) => {
if(oi.name === ov.name) {
temp[i] = ov.value
}
})
})
return temp
})()
})
})
newOption.radar.indicator = json.indicator
newOption.legend.data = legend
newOption.series[0].data = data
this.chart.setOption(newOption)
}
- 列表/表格数据格式
[
['时间', '标题', '地址'],
[
{
type: 'img',
src: 'http://xxx',
alt: 'alt',
text: 'text'
},
'text',
'text'
]
]
PS:
列表头的启用与否:[ array0, array1, ... ] 如果启用了表头则array[0]
为表头数据,否则为表格/列表主体的第一行
行/单元格表示方法:[ [] ] 表示行,[ [ string || object ] ]
表示单元格,即 [ 'text', 'text', 'text' ] 表示该行有三个string
类型的元素,渲染后该行将有三个单元格,文本为text
自动适配单元格数量:表头的单元格数量自动根据列表主体最多单元格的行来适配;每一行的单元格数量根据单元格最多的一行来自动适配,以确保每一行的单元格数量相同
单元格可用类型:单元格的类型除了为string
,还可以为object
,即 {...}, 'text', 'text' ],其中 {...}
对象表示除了字符串文本(string
)之外的页面元素,如图片(图标)
、checkbox
、radio
、link(a标签)
等。
单元格为object
时,对象的属性:
img
{
type: 'img', // 这个对象表示一张图片
src: 'http://xxx', // 图片的src
alt: 'alt', // 图片的alt属性
text: 'text' // 与图片配套的文本
}
渲染后的代码
<div class='list-cell'>
<img src='http://xxx' alt='alt' />
<span>text</span>
</div>
checkbox/radio
{
type: 'checkbox/radio', // 这个对象表示一个复选框或单选框
text: '', // 文本
uid: '234235345', // 该条数据的唯一标识,用于和后台交互用
name: 'checkbox' // name属性
}
渲染后的代码
<!-- checkbox -->
<div class='list-cell'>
<label>
<input type='checkbox' id='uid' name='checkbox' />
<span>text</span>
</label>
</div>
<!-- radio -->
<div class='list-cell'>
<label>
<input type='radio' id='uid' name='radio' />
<span>text</span>
</label>
</div>
link
{
type: 'link', // 这个对象表示一个链接(a标签)
text: '', // 文本
href: '#', // a标签的href属性
uid: '', // 该条数据的唯一标识,用于和后台交互用
}
渲染后的代码
<div class='list-cell'>
<a href='#' id='uid'>text</a>
</div>
9.注意事项
preview预览图片不可在组件里面import,如果要使用可以命名为其它名称
组件不能在componentDidMount生命周期中初始化大小,会导致初始边框位置大小错误
组件名称就是文件夹名称,所以不允许出现中文、特殊字符等,统一以骆驼峰命名
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago