Follow the subscription number “Doupi Fan er” and reply to “Add Group”

Join us and learn, day day up

Hi, bean skin fans! Just finished the year, last year’s year-end summary of any friends did not write? Have you written any resolutions for the New Year? What flags will 2021 set up?

This time, we invite you to read “Big Market Development from Getting Started to What YOU See is What you Get”, carefully produced by Bytedance’s “Little Blacksmith in Milan”, to see what you need to know in big market development, so that you don’t know the knowledge +1.

Main Contents of this paper

  1. The principle of drag
  2. Common drag and drop component library comparison
  3. React-DnD quick to get started
  4. Re-resizable for quick start
  5. How to achieve a simple drag system

Recently, I made a wySIWYG editor for our background system, and gained a lot. I wrote an article to make a comprehensive review

First, basic principles

The complete drag and drop process for a DOM element is divided into two parts: drag and drop

It’s easy to drag an element, just add a draggable=”true” attribute to the corresponding HTML node, and hyperlinks and images are dragable by default.

The real trouble is the place part, we need to listen to the onDragStart, onDragEnter, onDragover, onDragLeave and other drag events that happen on the element in each stage, and finally we need to process the onDrop event to complete the final place, we need to do a good job of data transfer, The identification of the placable area, the processing of the final position, the update of the page and so on a series of small and tedious work.

Fortunately, there are mature libraries to help us with these details, so we can just focus on the rendering logic.

Here are some common React drag-related libraries:

React DnD, developed by Redux author Dan Abramov, is a very old React drag tool library that provides a layer of encapsulation for the underlying drag and drop.

React-beautiful-dnd is a library of React drag-and-drop tools contributed by the Alassian team (yes, the team that developed Jira). Compared with React-DnD, it provides higher level of functionality encapsulation, such as animation, virtual list, mobile terminal, etc. It is also the most React drag library for Star on Github

React-grid-layout is open source by BitMex, a bitcoin exchange company. It is the best framework for Grid Layout. It supports zooming-in and zooming-out, automatic Layout, and has been used in AWS console and Grafana.

Because I don’t want to leave my fate to the Bitcoin company, I want to realize a whole set of drag logic from a lower level, so I choose the React-DND library to complete the development of page drag function.

React-dnd Quick Start

React-dnd contains four core concepts: Backend, monitor, Drag, and DROP.

Here is the simplest and most basic example:

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

function Drag() {
        const [collectedProps, drag] = useDrag({
                item: { values, type: 'KEY'}})return (
                <div ref={drag}>Drag</div>)}function Drop() {
        const [collectedProps, drop] = useDrop({
                accept: 'KEY'
        })
        return (
                <div ref={drop}>Drop Area</div>)}export default function Demo() {
        return (
        <DndProvider backend={HTML5Backend}>
                <Drag />
        <Drop />
          </DndProvider>)}Copy the code

1. Backend

Backend can be interpreted as the logic behind drag and drop. Backend is used to distinguish different event monitoring and processing methods on PC and mobile terminals. React-dnd-html5-backend is used for PC terminals. Otherwise use react-dnd-touch-backend. Note that DndProvider must be used in the outermost layer of Drag and Drop.

2. Monitor

Monitor is not easy to understand at first glance, but there really is no better word for it. Monitor is the total state data that monitors the entire Drag event. It is mainly divided into sourceMonitor and targetMonitor, which respectively represent the current state data of Drag and Drop elements, such as offset distance and whether they float on the upper layer. When we use useDrag and useDrop, we can use the corresponding Monitor data for state determination or preset switching and other rich functions.

3. Drag

Drag is a drag element (source). If the ref generated by useDrag points to a DIV, the DIV will be set to draggable=true, and all drag events will be monitored by us. The usage method can refer to the above example.

const [collectedProps, drag] = useDrag({item, canDrag, collect})
Copy the code

There are three elements in the array returned by useDrag. Let’s just say the first two:

CollectedProps collectedProps is a variable that represents the data to be listened to when a component is dragging, and that is, the Ref reference of the drag element is assigned to the DOM elementCopy the code

UseDrag function parameters are also many, here only pick the important ones to say:

CanDrag: mandatory, that is, the contained data object. The field type must correspond to the drop object. Only the same type can be placed in the canDrag: Select, (monitor) => Boolean, indicates whether drag can be used. This is useful in distinguishing edit mode from read-only mode. If (monitor) => object, the value returned by this method can be obtained from the above collectedProps. By using monitor to determine the state, we can return properties such as opacity and hightlighted to add styles to the drag elementsCopy the code

4. Drop

Drop is an element that can be dragged to (target). Its return array has two elements and is almost identical to the useDrag return value

const [collectedProps, drop] = useDrop({ accept, hover, drop, collect })
Copy the code

The parameters and return values are as follows:

CollectedProps: Object drop, which is the object drop returned by the COLLECT function. That is, the Ref reference of the element is assigned to the corresponding DOM elementCopy the code

UseDrop parameters are also many, we also select the key to illustrate:

Accept: Mandatory, supports a string or array of strings, corresponding to the drag type value, the same value can be dragged into this element hover: If (item, monitor) => void, select * from the drag object on which the drag object is drag; Collect: select, (item, monitor) => object, (monitor) => objectCopy the code

The basic concepts of React-DND have been introduced. As the saying goes, “A nine-layer platform starts from the ground, and a journey of a thousand miles begins with a single step”, all the interactions on the page are based on these basic functions. If you still feel abstracted, you may want to check out the Sandbox code in the Demo on the official website. Squeeze to experience ten bells, made will do me like, like a section of love tools!

Re-Resizable and wide – height adsorption

Now that we’ve talked about dragging, let’s talk about stretching.

Stretching is supported by specifying resize in CSS properties. For example, the common textarea has this property built in by default. However, browsers do not provide an API for resize like drag, so most libraries listen for mousedown, Mousemove, Mouseup is a bit of a hack.

Re-resizable is also a library that supports stretching under React. This library is very easy to get started with and can be easily understood by reading the official documentation.

We can set value(size) and onChange(onRisizeStop) just like the form component to complete the function of stretching. The trouble is that if enable is specified, all eight directions need to be specified once.

It is worth mentioning how to do the auxiliary adsorption of width and height. The simple point is to use grid to set the step size, but if you want to make customized alignment, it will be troublesome. Here is an idea to share: We can obtain the offset position through parameters in onResize or onResizeStop. At this point, the offset position can be calculated and rounded to ensure a proportional change.

If you want to do similar Photoshop (not PS) or CAD that adsorption of transverse and longitudinal axis, you can refer to the document. The elementFromPoint (x, y) method, through constant step iterative methods should be able to find the nearest child elements and obtain the corresponding high wide.

How to realize the minimum set of a drag system?

I divided the entire drag system into four parts:

  1. Drag source container area, 2. Drag source component area, 3. Container area on canvas, 4. Components on the canvas.

The following TYPE is the value of TYPE in useDrag, and ACCEPT is the value of ACCEPT in useDrop.

1. Drag the source container area

TYPE=”Container”

The drag-and-drop source container is all the container layouts that the user can drag onto the canvas. All components should be placed into the container for layout management, which is not necessary if the components can achieve good layout management.

2. Drag the source component area

TYPE=”Widget”

That is, the actual business needs to display components, this part is to support secondary development, and use the form-render support to generate component configuration Form in the Form of configuration items, components only need to pay attention to the business logic, configuration items will be automatically injected in.

3. Canvas container area

TYPE=”PaintContainer” ACCEPT=[“Container”, “PaintContainer”]

When dragging a Drag source onto a canvas, it creates a container area of the canvas. You can also use a new TYPE to quickly distinguish between the Drag source and the movement of a module on the canvas. If you want a DOM to support Drag & Drop, you can do this:

const ref = useRef();
const [,drop] = useDrop({});
const [,drag] = useDrag({});
drop(drag(ref));

return <div ref={ref}> Both Can Drag & Drop </div>
Copy the code

4. Canvas component area

TYPE=”PaintWidget” ACCEPT=[“Widget”, “PaintWidget”]

This can also be distinguished by two different types, one to fill in the data and the other to swap the subscripts of the two positions, to distinguish between dragging in from the source and dragging in from somewhere else on the canvas.

Finally, data structures

The canvas area is maintained using an array of JS elements roughly structured as follows:

{ uuid: string; // block id width,height... // Children: {uuid: string; Span: number; // Display component width widgetId: string; Config: object; config: object; // Personalize item value}[]}Copy the code

React Render(data) => View is a great way to Render a canvas. Every time you change the data structure, React automatically renders the canvas based on the data structure.

5. Other issues

1. How to fill 0 for date data?

This generally happens when making line charts, DB data is not available every day, especially when drawing multiple line charts:

[{data: '2020-09-01'.type: 'A'.count: 5 },
        { data: '2020-09-03'.type: 'A'.count: 15 },
        { data: '2020-09-03'.type: 'B'.count: 10 },
        { data: '2020-09-06'.type: 'C'.count: 20},]Copy the code

The data above, missing September 2, September 4, September 5 data, if you do not fill in the vacancy time, the horizontal axis interval will be strange.

And because there are multiple polylines, each date needs the data corresponding to each type, otherwise the polyline will break.

There are three ways to add 0:

  1. The database is updated daily, with redundant data inserted, depending on the business scenario and the role of the table
  2. Creating a date table and doing a LEFT JOIN each time a query is simple, but performance may be slightly worse
  3. So the back end or the front end is going to add 0, because hereIt’s too cumbersome to write in goConsidering to reduce the back-end calculation pressure and network transmission pressure, put into the front end

Select * from responseData; select * from responseData; select * from responseData;

Step 1: Use the DayJS tool to generate a dateList array from query start time to query end time

Step 2: Generate an empty result array resultList according to the Echarts specification. The format of this array is {type: value[]}, where type is the status value, value is the subscript of the date, and value is the count data

The subscript pointer I points to the 0th element of the dateList and the subscript pointer j points to the 0th element of the responseData

Step 4: don’t compare, first traverse M all status, give resultList [Enum (M)] [I] value assignment resultList [Enum (M)] [I] | | 0

Step 5: Compare dateList[I] and responseData[j] to see if dateList[I] and responseData[j] correspond to the same date. If so, go to step 6

ResponseData [j]. Type = responseData[j]. Type = responseData[j]. Type = responseData[j]. Type = responseData[j]

Step 7: no data for this date exists in the result, because the default value was assigned in step 4, so i++, and then return step 4

Step 8: Terminate the loop when I exceeds the dateList length

Six, also defect what

After all, it was built in two weeks, and there are still a lot of imperfections in the implementation:

1. Drag and drop interaction

Drag and drop interactions require a lot of detail judgment if you want to increase motion, preview, and so on

2. Layout

Currently enforces line-first layout, enforces four-square and eight-square layout, and may need to support layout in column direction

3. Component library construction

The core of CMS system is template + component library. Currently, there is no concept of version of the component, which is hardcoded into the code, which needs to be broken down into asynchronous references, and also needs to be adapted to the width and height of the container in which it is located.

The End