preface

This project is quite complicated, and it is expected to be divided into three parts. The project has not yet been completed, so I will forget it before and make a record here.

Project online experience address: Charts

The project source address is in the Library folder: source code

The technology used in the project

react-dnd

react-dnd-html5-backend

react

echarts

echarts-for-react

The data structure

Nested objects: The attributes of the outer objects are the IDS of each chart, and the inner objects hold the attributes of each chart.

Long like this:

chartsObj = {
    line1: {
        width: x,
        height: x,
        top: x,
        left: x,
    }
    ...
}
Copy the code

Here use the React hook: useReducer to create objects.

At first, I didn’t expect so many types, so I changed it to switch-case:

const [chartsObj, dispatch] = React.useReducer((state, action) = > {
    const { id, left, top, active, type, width, height, view, value } = action
    if (type === 'move') {
        return{... state, [id]: { ... state[id], left, top } } }if (type === "delete") {
        delete state[id]
        return { ...state }
    }
    if (type === 'activeClass') {
        Object.keys(state).map(item= > {
            if (item === id) {
                state[item].active = true
                return item
            }
            state[item].active = false
            return item
        })
        return { ...state }
    }
    if (type === 'changeview') {
        return{... state, [id]: { ... state[id], [view]: value } } }return { ...state, [id]: { id, type, active, left, top, width, height } }
}, {});
Copy the code

Create a chart

Generate the corresponding basic chart when clicking on the left menu bar: similar to clicking on a bar chart to generate a bar chart.

Ideas:

  1. Encapsulate the basic Echarts style of the corresponding chart.

  2. When an item is clicked, use Dispatch to notify State of the change.

  3. Data-driven views that generate corresponding charts.

Implementation:

Use echarts-for-react to introduce echarts into your project. If you have used echarts before, you will know that the main definition of echarts is the option property. If you do not know echarts, you can go to the echarts official website to learn. The official website API is very detailed: Echarts

import ReactEcharts from 'echarts-for-react';

<ReactEcharts
    option={option}
    theme="Imooc"
    style={{ width:` ${width}px`, height:` ${height}px`}}ref={chartRef}
/>
Copy the code

Once the chart is wrapped, the next step is to click on the event to change the data source, using the Dispatch provided by useReducer:

const createChart = (item) = > {
    switch (item.key) {
        case "lineBasic":
            dispatch({ type: 'lineBasic'.id: `lineBasicThe ${Object.keys(chartsObj).length}`.active: false.left: 20.top: 20.width: 300.height: 250 })
            break
        case "barBasic":
            dispatch({ type: 'barBasic'.id: `barBasicThe ${Object.keys(chartsObj).length}`.left: 20.top: 20.width: 300.height: 250 })
            break
        case "pieBasic":
            dispatch({ type: 'pieBasic'.id: `pieBasicThe ${Object.keys(chartsObj).length}`.left: 20.top: 20.width: 300.height: 250 })
            break
        default:
            return}}Copy the code

Iterate over state to generate a graph:

{Object.keys(chartsObj).map(v= > {
    const { left, top, id, type, active, width, height } = chartsObj[v]
    return (
        <Chart
            type={type}
            key={id}
            id={id}
            left={left}
            top={top}
            width={width}
            height={height}
            active={active}
            deleteChart={deleteChart}
            selectChart={selectChart}
        >

        </Chart>)})}Copy the code

Support drag and drop

React-beautiful-dnd and react-sortable-hoc were also tried. Finally, react-DND was found to be the most powerful.

React-dnd is a plugin that uses react DND. React DND is a plugin that uses react DND. An error will be reported if it is inconsistent with our React version. Solutions:

Configure alias in webpack.config.js resolve:

alias: {
    The '@': paths.appSrc,
    react: path.resolve('./node_modules/react'),        // Fix react versions
}
Copy the code

React-dnd relies on react-dnd-html5-Backend as an extension, and must be installed together.

  1. In the root directory of the project:
//app.js

import { useDrop, DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'


export default function RouteConfigExample () {
    return( <DndProvider backend={HTML5Backend}> <BrowserRouter> <Switch> {RouteGlobal.map((route, i) => ( <RouteWithSubRoutes key={i} {... route} /> ))} </Switch> </BrowserRouter> </DndProvider> ...Copy the code
  1. Within the component intended as a drag area:

    const [, drop] = useDrop({
        accept: 'box',
        drop (item, monitor) {
            const delta = monitor.getDifferenceFromInitialOffset()
            const left = Math.round(item.left + delta.x)
            const top = Math.round(item.top + delta.y)
            moveBox(item.id, left, top)
            return undefined}})const moveBox = (id, left, top) = > {
        dispatch({ type: 'move', id, left, top })

    }
    ...
    <div ref={drop} className="charts-middle">
        <Chart>
    </div
Copy the code
  1. Set the drag source:
    const [{ isDragging }, drag] = useDrag({
        item: { id, left, top, type: 'box' },
        collect: monitor= > ({
            isDragging: monitor.isDragging(), }), }) ... <div ref={drag} style={{ ... style, left, top }} ><ReactEcharts
            option={option}
            theme="Imooc"
            style={{ width:` ${width}px`, height:` ${height}px`}}ref={chartRef}
        />
    </div>
    
Copy the code

Full screen operation

Fullscreen operation mainly uses the requestFullscreen and exitFullScreen API, each browser compatibility is different:

const fullscreen = (a)= > {
        let ele = document.querySelector('.charts-box')
        if (ele.requestFullscreen) {
            ele.requestFullscreen();
        } else if (ele.mozRequestFullScreen) {
            ele.mozRequestFullScreen();
        } else if (ele.webkitRequestFullscreen) {
            ele.webkitRequestFullscreen();
        } else if (ele.msRequestFullscreen) {
            ele.msRequestFullscreen();
        }
        setFullFlag(true)}const exitFullscreen = (a)= > {
    if (document.exitFullScreen) {
        document.exitFullScreen();
    } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen();
    } else if (document.webkitExitFullscreen) {
        document.webkitExitFullscreen();
    } else if (document.msExitFullscreen) {
        document.msExitFullscreen();
    }
    setFullFlag(false)}... { fullFlag ? <Button className="charts-left-button" onClick={exitFullscreen}><Icon type="fullscreen-exit" /></Button> : <Button className="charts-left-button" onClick={fullscreen}><Icon type="fullscreen" /></Button> } ...Copy the code

The latter

Specific operations can be experienced in online demo, and the next step is to achieve:

Chart style support configuration;

Data sources can be configured to display real data using real data sources.