0x00 Project background

The project is for highway supervision. Highway supervision includes: highway equipment operation, equipment maintenance, road maintenance; Traffic flow analysis, traffic congestion analysis, congestion source tracing; Accident analysis, event information release, etc.

0 x01 design

At present, the project is mainly in the form of preview, so the design drawing level mainly uses the pictures provided by the customer. Our design team wasn’t very involved. The following is the client’s design drawing:



The design

0x02 Map the highway

The actual effect of highway is more complicated, for example, there are various lines on the highway (zebra crossing, yellow line, white line, solid line, dotted line, etc.). However, these are not the most important elements in the system, so consider ignoring them. So we simulated the path with the edge effect, which looks like this:



Effect of highway

The drawing logic is simple, first draw the path with a larger line width, then draw the path with a smaller line width and a different color. The rough drawing logic is as follows:

ctx.save();
        ctx.beginPath();
        ctx.lineJoin = 'round';
        // ctx.lineCap = 'round';
        points.forEach(({
            x,
            y
        }, index) => {
            ctx[index ? 'lineTo' : 'moveTo'](x, y);
        })
       
        ctx.lineWidth = width;
        ctx.strokeStyle = sideColor;
        ctx.stroke();
        ctx.shadowBlur = 0;
        ctx.globalCompositeOperation = 'source-over'; Ctx. lineWidth = width * 0.5; ctx.strokeStyle = midColor; ctx.stroke();Copy the code

In the editor, add a road component and click on the road component to start drawing the road:




Highway components

Edit the path through the dot, that is, you can edit the direction of the road. It is important to note that the auto-smoothing technique is used to smooth the originally sharp corners.

export functionCreateSmoothCurvePoints (points, tension = 0.5, closed =false,
  numberOfSegments = 16
) {
  if (points.length < 2) {
    returnpoints; } // Expand the array points = expandPointArr(points);let ps = points.slice(0), // clone array so we don't change the original
    result = [], // result points
    x,
    y, // our x,y coords
    t1x,
    t2x,
    t1y,
    t2y, // tension vectors
    c1,
    c2,
    c3,
    c4, // cardinal points
    st,
    t,
    i; // steps based on number of segments

  // The algorithm require a previous and next point to the actual point array.
  // Check if we will draw closed or open curve.
  // If closed, copy end points to beginning and first points to end
  // If open, duplicate first points to befinning, end points to end
  if (closed) {
    ps.unshift(points[points.length - 1]);
    ps.unshift(points[points.length - 2]);
    ps.unshift(points[points.length - 1]);
    ps.unshift(points[points.length - 2]);
    ps.push(points[0]);
    ps.push(points[1]);
  } else {
    ps.unshift(points[1]); // copy 1st point and insert at beginning
    ps.unshift(points[0]);
    ps.push(points[points.length - 2]); // copy last point and append
    ps.push(points[points.length - 1]);
  }

  // 1. loop goes through point array
  // 2. loop goes through each segment between the 2 points + 1e point before and after
  for (i = 2; i < ps.length - 4; i += 2) {
    // calculate tension vectors
    t1x = (ps[i + 2] - ps[i - 2]) * tension;
    t2x = (ps[i + 4] - ps[i - 0]) * tension;
    t1y = (ps[i + 3] - ps[i - 1]) * tension;
    t2y = (ps[i + 5] - ps[i + 1]) * tension;

    for (t = 0; t <= numberOfSegments; t++) {
      // calculate step
      st = t / numberOfSegments;

      // calculate cardinals
      c1 = 2 * Math.pow(st, 3) - 3 * Math.pow(st, 2) + 1;
      c2 = -(2 * Math.pow(st, 3)) + 3 * Math.pow(st, 2);
      c3 = Math.pow(st, 3) - 2 * Math.pow(st, 2) + st;
      c4 = Math.pow(st, 3) - Math.pow(st, 2);

      // calculate x and y cords with common control vectors
      x = c1 * ps[i] + c2 * ps[i + 2] + c3 * t1x + c4 * t2x;
      y = c1 * ps[i + 1] + c2 * ps[i + 3] + c3 * t1y + c4 * t2y;

      //store points in array
      result.push(x);
      result.push(y);
    }
  }
return contractPointArr(result);
Copy the code

0x03 Drawing of gate frame

The final effect of the door frame is shown below:




The door frame

You can see that the doorframe is composed of several cubes. We only need to understand the cube drawing logic, it is easy to understand the frame drawing logic.

Draw a cube

There are cube components in the editor itself:




Cube assembly

The display effect is as follows:




Cube effect

The idea of drawing a cube is not complicated, just using some three-dimensional ideas. First of all, with the help of the 3d projection transformation idea, of course, the orthographic projection is used here:

/** * @param {Object} point - 3d coordinates ** @param {Object} offset - @returns {Object} -2D coordinates */ getProjectionPoint(point) { const network = this._network, p = vec3.create(), itMat = network.getMVMatrix(); vec3.transformMat4( p, [point.x, point.y, point.z], itMat ); const { x, y } = this.getLocation()return {
      x: p[0] + x,
      y: -p[1] + y
    };
  }
Copy the code

Calculate the cube’s position in the plane for each of its eight vertices, and calculate the three faces that are now on the outside (note: no more than three faces will be shown on the outside). Then draw the values for the three faces:

 drawSide(ctx, points, isFill = false, color = "#00ccff") {
    ctx.save();
    ctx[isFill ? 'fillStyle' : 'strokeStyle'] = color;
    ctx.lineWidth = 1;
    ctx.beginPath();
    points.forEach(({
      x,
      y
    }, index) => {
      ctx[index ? 'lineTo' : 'moveTo'](x, y);
    })
    ctx.closePath();
    ctx[isFill ? 'fill' : 'stroke'] (); ctx.restore(); }Copy the code

The final drawing is shown in the image above.

The drawing of the gantry is the drawing of the combination of multiple cubes. One thing to be aware of is the order in which the cubes are drawn, which involves the correctness of the occlusion relationship.

In the editor, you can change its display by adjusting its length, width, height and Y-axis rotation Angle:




The door frame

0x04 Drawing of the marker

Signs are a common sight on highways. Used for various prompts, in this system, the display effect of the sign is as follows:




sign

Its drawing idea is similar to the front door frame, which is composed of cubes. Therefore, it will not be repeated here.

0x05 Mountain drawing

Because the mountain is a more complex model, the program directly uses the designer’s design graphics. As shown in the figure below:




mountain

Use the picture designed by the designer as the ne picture and drag it into the scene.

0x05 Diagram drawing

The editor integrates the common Echarts charts and extended charts. This can be directly dragged into the scene, such as the following screenshot of a section of the chart, including bar chart, pie chart, curve chart:




The chart component

Drag the diagram directly into the scene to generate the diagram effect, as shown below:




Effect of the chart

And you can configure the data of the chart in the property box, here for demonstration, the use of static data; Can also be connected to dynamic data on the two.

0x06 Final effect

Combining all the above effects, a demo page is finally edited, as shown below:




The final result

If you are interested in getting a demo, please send an email to [email protected]

Also welcome to follow the personal public account “ITman”