diff --git a/.editorconfig b/.editorconfig
index fb49a93..9e77100 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -6,7 +6,7 @@ root = true
charset = utf-8
end_of_line = lf
indent_style = space
-indent_size = 4
+indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
diff --git a/.eslintrc b/.eslintrc
deleted file mode 100644
index 9318c57..0000000
--- a/.eslintrc
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "env": {
- "browser": true,
- "es6": true
- },
- "plugins": [
- "react",
- "babel"
- ],
- "parserOptions": {
- "ecmaVersion": 6,
- "sourceType": "module",
- "ecmaFeatures": {
- "jsx": true,
- "experimentalObjectRestSpread":true
- }
- },
- "rules": {
- "camelcase": 2,
- "curly": 2,
- "eqeqeq": 2,
- "brace-style": [2, "1tbs"],
- "quotes": [2, "single"],
- "semi": [2, "always"],
- "space-infix-ops": 2,
- "no-param-reassign": 0,
- "prefer-spread": 2
- }
-}
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..2912627
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,71 @@
+'use strict';
+
+const OFF = 0;
+const WARNING = 1;
+const ERROR = 2;
+
+module.exports = {
+ 'extends': 'airbnb',
+ 'env': {
+ 'browser': true,
+ 'node': true,
+ 'es6': true,
+ 'mocha': true
+ },
+ globals: {
+ assert: true
+ },
+ 'parser': 'babel-eslint',
+ 'plugins': [
+ 'react',
+ 'babel'
+ ],
+ 'parserOptions': {
+ 'ecmaVersion': 6,
+ 'sourceType': 'module',
+ 'ecmaFeatures': {
+ 'jsx': true,
+ 'experimentalObjectRestSpread': true
+ }
+ },
+ 'rules': {
+ 'indent': [ERROR, 2, { 'SwitchCase': 1 }], //规定代码的缩进方式:2个空格
+ 'camelcase': ERROR, //强制驼峰法命名
+ 'curly': ERROR, //必须使用 if(){} 中的{}
+ 'eqeqeq': ERROR, //必须使用全等
+ 'brace-style': [ERROR, '1tbs'], //大括号风格
+ 'quotes': [ERROR, 'single'], //引号类型
+ 'semi': [ERROR, 'always'], //语句强制分号结尾
+ 'space-infix-ops': ERROR, //中缀操作符周围要不要有空格
+ 'no-param-reassign': OFF, //不允许对函数的形参进行赋值
+ 'prefer-spread': ERROR, //首选展开运算
+ 'comma-dangle': OFF, //不允许或强制在对象字面量或者数组属性的结尾使用逗号
+ 'padded-blocks': OFF, //规定代码块前后是否要加空行
+ 'prefer-const': OFF,
+ 'no-multi-spaces': ERROR,
+ 'no-var': OFF,
+ 'one-var': OFF,
+ 'class-methods-use-this': WARNING,
+ 'no-unused-expressions': [ERROR, { allowShortCircuit: true }],
+ /**
+ * https://github.com/airbnb/javascript/tree/master/react
+ */
+ 'react/prefer-es6-class': [WARNING, 'always'], //使用 class extends React.Component
+ 'react/jsx-pascal-case': ERROR, //骆驼式命名
+ 'react/jsx-closing-bracket-location': ERROR, //JSX语法缩进/格式
+ 'react/jsx-curly-spacing': ERROR, //JSX {} 引用括号里两边加空格
+ 'react/jsx-boolean-value': [OFF, 'always'], //如果属性值为 true, 可以直接省略
+ 'jsx-quotes': [ERROR, 'prefer-double'], //JSX属性值总是使用双引号(")
+ 'react/no-string-refs': ERROR, //Refs里使用回调函数
+ 'react/jsx-wrap-multilines': ERROR, //多行的JSX标签写在 ()里
+ 'react/self-closing-comp': ERROR, //没有子元素的标签来说总是自己关闭标签
+ 'react/jsx-no-bind': ERROR, //当在 render() 里使用事件处理方法时,提前在构造函数里把 this 绑定上去
+ 'react/no-is-mounted': ERROR, //不要再使用 isMounted
+ 'react/prop-types': [ERROR, { ignore: ['children', 'className', 'style'] }],
+ 'jsx-a11y/href-no-hash': OFF,
+ 'jsx-a11y/label-has-for': OFF,
+ 'react/jsx-filename-extension': OFF,
+ 'react/prefer-stateless-function': OFF,
+ 'react/require-default-props':OFF
+ }
+};
diff --git a/docs/gh-pages.js b/docs/gh-pages.js
new file mode 100644
index 0000000..8fa1d74
--- /dev/null
+++ b/docs/gh-pages.js
@@ -0,0 +1,6 @@
+var ghpages = require('gh-pages');
+var path = require('path');
+
+ghpages.publish(path.join(__dirname, '../assets'), function(err) {
+ console.log(err);
+});
diff --git a/docs/index.js b/docs/index.js
index 8c8843f..7ebb528 100644
--- a/docs/index.js
+++ b/docs/index.js
@@ -1,60 +1,60 @@
-import React from 'react';
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
-import ECharts, {dispatchAction} from '../src';
import { Markdown } from 'markdownloader';
+import ECharts from '../src';
import './style.less';
import './highlight.less';
-
import baseBarOptions from './data/bar-base';
-import mapOptions from './data/map.js';
+import mapOptions from './data/map';
import chinaJson from './data/china.json';
const events = {
- click:function(params){
- console.log(params);
- }
+ click(params) {
+ console.log(params);
+ }
};
-ECharts.registerMap('china',chinaJson);
+ECharts.registerMap('china', chinaJson);
-const App = React.createClass({
+class App extends Component {
- render() {
- let styles = Object.assign({
- width: '100%',
- height: '400px'
- }, this.props.style);
+ render() {
+ let styles = Object.assign({
+ width: '100%',
+ height: '400px'
+ }, this.props.style);
- return (
-
-
+ return (
+
+
-
-
RSuite ECharts
-
ECharts for React
-
+
+
RSuite ECharts
+
ECharts for React
+
-
Map
-
+
Map
+
-
- {require('./README.md') }
-
-
-
-
- );
- }
-});
+
+ {require('./README.md')}
+
+
+
+
+ );
+ }
+}
const rootElement = document.getElementById('app');
ReactDOM.render(,
- rootElement
+ rootElement
);
diff --git a/package.json b/package.json
index 63805f0..b67290e 100644
--- a/package.json
+++ b/package.json
@@ -4,17 +4,18 @@
"description": "ECharts for React",
"main": "lib/index.js",
"scripts": {
- "build": "rm -rf lib && babel src --out-dir lib",
- "dev": "NODE_ENV=development webpack-dev-server --hot --inline --progress --colors --port 3100",
- "docs": "NODE_ENV=production webpack --progress -colors ",
- "cp:docs": "cp -rf ./assets/* ../rsuite.github.io/rsuite-echarts/"
+ "dev": "NODE_ENV=development webpack-dev-server --inline --progress --colors --port 3000 --host 0.0.0.0 --devtool source-map ",
+ "docs": "rm -rf assets && NODE_ENV=production webpack ",
+ "build": "rm -rf lib && babel src --out-dir lib && cp -R src/less lib",
+ "publish-docs": "node docs/gh-pages.js"
},
"dependencies": {
"echarts": "^3.1.10",
"element-resize-event": "^2.0.5"
},
"peerDependencies": {
- "react": ">=0.14.0"
+ "react": "^0.14.9 || >=15.3.0",
+ "react-dom": ">=0.14.0"
},
"author": "simonguo.2009@gmail.com",
"license": "MIT",
@@ -22,33 +23,39 @@
"type": "git",
"url": "git@github.com:rsuite/rsuite-echarts.git"
},
+ "homepage": "https://github.com/rsuite/rsuite-echarts",
"devDependencies": {
- "react": "^0.14.2",
+ "react": "^15.4.2",
+ "react-dom": "^15.4.2",
+ "prop-types": "^15.5.10",
"babel-core": "^6.7.6",
"babel-loader": "^6.2.4",
+ "babel-eslint": "^6.1.2",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.3.13",
"babel-preset-stage-0": "^6.5.0",
"babel-standalone": "^6.7.7",
"css-loader": "^0.23.1",
"es5-shim": "^4.1.14",
- "eslint": "^2.8.0",
+ "eslint": "^3.19.0",
+ "eslint-config-airbnb": "^15.0.1",
"eslint-plugin-babel": "^3.2.0",
- "eslint-plugin-react": "^5.0.1",
- "extract-text-webpack-plugin": "^1.0.1",
+ "eslint-plugin-jsx-a11y": "^5.0.1",
+ "eslint-plugin-import": "^2.6.1",
+ "eslint-plugin-react": "^7.0.1",
+ "extract-text-webpack-plugin": "^2.0.0",
"highlight.js": "^9.5.0",
"html-loader": "^0.4.3",
"html-webpack-plugin": "^2.22.0",
"json-loader": "^0.5.4",
"less": "^2.7.1",
"less-loader": "^2.2.3",
- "markdown-loader": "^0.1.7",
+ "markdown-loader": "^2.0.0",
+ "markdownloader": "^1.0.5",
"marked": "^0.3.5",
- "react-dom": "^0.14.2",
"react-hot-loader": "^1.3.0",
"style-loader": "^0.13.1",
- "webpack": "^1.13.1",
- "webpack-dev-server": "^1.14.1",
- "markdownloader": "1.0.5"
+ "webpack": "^3.0.0",
+ "webpack-dev-server": "^2.2.0"
}
}
diff --git a/src/ECharts.js b/src/ECharts.js
index 7c0301a..00db757 100644
--- a/src/ECharts.js
+++ b/src/ECharts.js
@@ -1,103 +1,116 @@
-import React from 'react';
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
import echarts from 'echarts';
import onResize from 'element-resize-event';
-const ECharts = React.createClass({
- propTypes: {
- style: React.PropTypes.object,
- theme: React.PropTypes.oneOfType([
- React.PropTypes.string,
- React.PropTypes.object
- ]),
- group: React.PropTypes.string,
- option: React.PropTypes.object.isRequired,
- //是否不跟之前设置的option进行合并,默认为false,即合并
- notMerge: React.PropTypes.bool,
- //在设置完option后是否不立即刷新画布,默认为false,即立即刷新
- notRefreshImmediately: React.PropTypes.bool,
- onEvents: React.PropTypes.object
- },
- getDefaultProps() {
- return {
- notMerge: true,
- notRefreshImmediately: false,
- onEvents: {},
- style: {},
- theme: {}
- };
- },
- componentDidMount() {
- this.init();
- },
- componentDidUpdate() {
- this.renderEcharts();
- },
- componentWillUnmount() {
- this.dispose();
- },
- init() {
- this.chart = echarts.init(this.refs.container, this.props.theme);
- this.renderEcharts();
- this.initEvents();
- },
- initEvents() {
- let onEvents = this.props.onEvents;
- for (let eventName in onEvents) {
- this.chart.on(eventName, onEvents[eventName]);
- }
-
- onResize(this.refs.container, () => {
- this.chart.resize();
- });
- },
- dispose() {
- if (this.chart) {
- this.chart.dispose();
- this.chart = null;
- }
- },
- renderEcharts() {
-
- let { option, notMerge, notRefreshImmediately} = this.props;
- this.chart.showLoading();
- this.chart.setOption(option, notMerge, notRefreshImmediately);
- this.chart.hideLoading();
-
- },
- render() {
- let {
- id,
- option,
- style,
- className,
- ...props,
- } = this.props;
+const propTypes = {
+ style: PropTypes.object,
+ theme: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.object
+ ]),
+ group: PropTypes.string,
+ option: PropTypes.object.isRequired,
+ // 是否不跟之前设置的option进行合并,默认为false,即合并
+ notMerge: PropTypes.bool,
+ // 在设置完option后是否不立即刷新画布,默认为false,即立即刷新
+ notRefreshImmediately: PropTypes.bool,
+ onEvents: PropTypes.object
+};
+
+const defaultProps = {
+ notMerge: true,
+ notRefreshImmediately: false,
+ onEvents: {},
+ style: {},
+ theme: {}
+};
+
+class ECharts extends Component {
+
+ componentDidMount() {
+ this.init();
+ }
- let styles = Object.assign({
- width: '100%',
- height: '100%'
- }, style);
-
- return (
-
-
- );
+ componentDidUpdate() {
+ this.renderEcharts();
+ }
+
+ componentWillUnmount() {
+ this.dispose();
+ }
+
+ init() {
+ this.chart = echarts.init(this.container, this.props.theme);
+ this.renderEcharts();
+ this.initEvents();
+ }
+
+ initEvents() {
+ let onEvents = this.props.onEvents;
+ for (let eventName in onEvents) {
+ this.chart.on(eventName, onEvents[eventName]);
}
-});
+
+ onResize(this.container, () => {
+ this.chart.resize();
+ });
+ }
+
+ dispose() {
+ if (this.chart) {
+ this.chart.dispose();
+ this.chart = null;
+ }
+ }
+
+ renderEcharts() {
+
+ let { option, notMerge, notRefreshImmediately } = this.props;
+ this.chart.showLoading();
+ this.chart.setOption(option, notMerge, notRefreshImmediately);
+ this.chart.hideLoading();
+
+ }
+
+ render() {
+ let {
+ id,
+ option,
+ style,
+ className,
+ ...props,
+ } = this.props;
+
+ let styles = Object.assign({
+ width: '100%',
+ height: '100%'
+ }, style);
+
+ return (
+ {
+ this.container = ref;
+ }}
+ style={styles}
+ {...props}
+ />
+ );
+ }
+}
+
+ECharts.propTypes = propTypes;
+ECharts.defaultProps = defaultProps;
const APIS = ['getMap', 'connect', 'disConnect', 'getInstanceByDom', 'registerMap', 'registerTheme'];
APIS.forEach((api) => {
- ECharts[api] = echarts[api];
+ ECharts[api] = echarts[api];
});
ECharts.dispatchAction = function (echartsId, payload) {
- const chartInstance = echarts.getInstanceByDom(document.getElementById(echartsId));
- return chartInstance.dispatchAction(payload);
+ const chartInstance = echarts.getInstanceByDom(document.getElementById(echartsId));
+ return chartInstance.dispatchAction(payload);
};
diff --git a/src/index.js b/src/index.js
index 60c7e00..45e4715 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,5 +1,4 @@
import ECharts from './ECharts';
-import themes from './themes';
export default ECharts;
diff --git a/src/themes/pagurian.js b/src/themes/pagurian.js
index 93329a5..ebd3718 100644
--- a/src/themes/pagurian.js
+++ b/src/themes/pagurian.js
@@ -1,6 +1,6 @@
import echarts from 'echarts';
echarts.registerTheme('pagurian', {
- backgroundColor: '#f5f5f5',
- color: ['#fe8463', '#9bca63', '#fad860', '#60c0dd', '#0084c6', '#d7504b', '#c6e579', '#26c0c0', '#f0805a', '#f4e001', '#b5c334']
+ backgroundColor: '#f5f5f5',
+ color: ['#fe8463', '#9bca63', '#fad860', '#60c0dd', '#0084c6', '#d7504b', '#c6e579', '#26c0c0', '#f0805a', '#f4e001', '#b5c334']
});
diff --git a/webpack.config.js b/webpack.config.js
index d969163..1093adb 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -4,68 +4,103 @@ const HtmlwebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const markdownLoader = require('markdownloader').renderer;
+const { NODE_ENV } = process.env;
+const extractLess = new ExtractTextPlugin({
+ filename: '[name].[contenthash].css',
+ disable: NODE_ENV === 'development'
+});
-const output = {
- path: path.resolve(__dirname, 'assets'),
- filename: 'bundle.js'
-};
-
-const entry=[
- path.join(__dirname, 'docs/index'),
-]
-
-const jsloaders=[
- 'babel?babelrc'
+const docsPath = NODE_ENV === 'development' ? './assets' : './';
+const plugins = [
+ new webpack.HotModuleReplacementPlugin(),
+ new webpack.NamedModulesPlugin(),
+ new webpack.DefinePlugin({
+ 'NODE_ENV': JSON.stringify(NODE_ENV)
+ }),
+ extractLess,
+ new HtmlwebpackPlugin({
+ title: 'RSUITE Echarts',
+ filename: 'index.html',
+ template: 'docs/index.html',
+ inject: true,
+ hash: true,
+ path: docsPath
+ })
];
-if (process.env.NODE_ENV === 'development') {
- output.publicPath = '/assets/';
- entry.push('webpack/hot/dev-server');
- jsloaders.push('react-hot');
+if (process.env.NODE_ENV === 'production') {
+ plugins.push(new webpack.optimize.UglifyJsPlugin());
+ plugins.push(new webpack.BannerPlugin({ banner: `Last update: ${new Date().toString()}` }));
}
-
-const config = {
- entry,
- output,
- plugins: [
- new webpack.DefinePlugin({
- 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
- }),
- new webpack.optimize.UglifyJsPlugin({
- compress: {
- warnings: false
- }
- }),
- new ExtractTextPlugin('[name].css'),
- new HtmlwebpackPlugin({
- title: 'RSuite-ECharts',
- filename: 'index.html',
- template: 'docs/index.html',
- inject: true,
- hash: true
- }),
- ],
- module: {
- loaders: [
- {
- test: /\.js$/,
- loaders: jsloaders,
- exclude: /node_modules/
- }, {
- test: /\.less$/,
- loader: ExtractTextPlugin.extract('style-loader', 'css-loader!less-loader')
- }, {
- test: /\.md$/,
- loader: 'html!markdown'
- }, {
- test: /\.json$/,
- loader: 'json-loader'
- }
- ]
+const common = {
+ entry: path.resolve(__dirname, 'src/'),
+ devServer: {
+ hot: true,
+ contentBase: path.resolve(__dirname, ''),
+ publicPath: '/'
+ },
+ output: {
+ path: path.resolve(__dirname, 'assets'),
+ filename: 'bundle.js',
+ publicPath: './'
+ },
+ plugins,
+ module: {
+ rules: [{
+ test: /\.jsx?$/,
+ use: [
+ 'babel-loader'
+ ],
+ exclude: /node_modules/
},
- markdownLoader
-};
+ {
+ test: /\.less$/,
+ loader: extractLess.extract({
+ // use style-loader in development
+ fallback: 'style-loader',
+ use: [
+ 'css-loader',
+ 'less-loader'
+ ],
+ })
+ },
+ {
+ test: /\.css$/,
+ loader: ExtractTextPlugin.extract({
+ // use style-loader in development
+ fallback: 'style-loader',
+ use: [
+ 'css-loader',
+ ],
+ })
+ },
+ {
+ test: /\.md$/,
+ use: [{
+ loader: 'html-loader'
+ }, {
+ loader: 'markdown-loader',
+ options: {
+ pedantic: true,
+ renderer: markdownLoader.renderer
+ }
+ }
+ ]
+ }, {
+ test: /\.(woff|woff2|eot|ttf|svg)($|\?)/,
+ use: [{
+ loader: 'url-loader?limit=1&hash=sha512&digest=hex&size=16&name=resources/[hash].[ext]'
+ }]
+ }]
+ }
+};
-module.exports = config;
+module.exports = (env = {}) => {
+ return Object.assign({}, common, {
+ entry: [
+ path.resolve(__dirname, 'docs/index')
+ ]
+ });
+};