Preface:

This project used some custom data visualization components, AND I selected a few typical ones to make a summary.

It is divided as follows:

  • SVG: animateMotion+ animateTransform: CSS3D
  • Map – SVG render + DIV hover + JS event
  • 2D pie chart (windmill) — Canvas: dragCircle, stopDragging
  • Triangular pyramid — Canvas + logarithmic arrangement
  • Cuboid — CSS3D + incremental growth
  • Windshield Wiper (fan pie chart) – Zrender

A picture of the planet’s orbit

Effect display:

Some of the images (such as the JPG GIF below) are too big, compressed and a little fuzzy (^_^).




My words (* ^ 3 ^) :


The reason why there are two versions: originally using SVG to implement a version, the result of my planet SVG and my colleagues other animation SVG conflict (⁎⁍̴̛ᴗ⁍̴̛⁎), a huge change, the SVG itself is smelly and long, too tired to change, simply use CSS3D to draw a new (´▽ ‘).

Steps:

Method 1: SVG animateMotion + animateTransform

/ / Example a planet <animateMotion dur="6s" begin="0" repeatCount="indefinite">
  <mpath xlinkHref="#Path-12"/> // </animateMotion> <animateTransform // Own animation, the planet gets bigger when you are close to me and smaller when you are away from me id="first"
  attributeType="XML"
  attributeName="transform"
  type="scale"
  begin="0; second.end "
  from="1"
  to="0.512"
  dur="3s"
  fill="freeze"
/>
<animateTransform
  id="second"
  attributeType="XML"
  attributeName="transform"
  type="scale"
  begin="first.end"
  from="0.512"
  to="1"
  dur="3s"
  fill="freeze"
/>Copy the code

Method two: CSS3D

Refer to the link: www.jianshu.com/p/2b85973ad…

  • html:

<! -- track --> <div class="orbit"> <! -- planet --> <div class="planet planet1"> <! -- <span class="name"></span> -->
  </div>
  <div class="planet planet2"> <! -- <span class="name"></span> -->
  </div>
</div>Copy the code
  • css:

.orbit {// border: 5px solid red; transform-style: preserve-3d; padding: 65px; width: 500px; height: 500px; border-radius: 50%; animation: orbit-rotate 10s linear infinite; }.planet {/ / planet rotation width: 50px; height: 50px; background: url('.. /.. /img/ball1.png') no-repeat; background-size: 100% 100%; border-radius: 50%; animation: self-rotate 10s linear infinite; } // (1) rotateX is used to make the whole face tilt, and translateZ is used to prevent the border from being jagged because of the tilt. Five spheres, according to 360/5=72, write five different classes about orbit, // 0 + 72,.... Rotate class @keyframes orbit-rotate {0% {transform: rotate class @keyframes orbit-rotate {0%} rotateX(70deg) rotateZ(0deg) translateZ(0); } 100% { transform: rotateX(70deg) rotateZ(-360deg) translateZ(0); } } @keyframes self-rotate { 0% { transform: rotateX(-90deg) rotateY(360deg) rotateZ(0deg); } 100% { transform: rotateX(-90deg) rotateY(0deg) rotateZ(0deg); }}. Planet1 {/ / Determine the starting position of the planet position: absolute; top: 65px; right: 65px; }.planet2 {/ / Determine the starting position of the planet position: absolute; bottom: 65px; right: 65px; }Copy the code

Improved version: size and light with gap control, near large far small, near light far dark.

const orbitStyle = {
  transform: `rotateX(70deg) rotateZ(${activeCircle * - 72.}deg) translateZ(0)`};const planetStyle = (index, l) = > {
  // l is the length of array
  const average = l / 2; // Calculate the average
  const gap = 0.8 ** (average - Math.abs(Math.abs(index - (activeCircle % l)) - average)); // First calculate the absolute value of different balls at different times to calculate the distance between points in the interval, and then calculate the change value according to the distance
  return {
    transform: `rotateX(-90deg) rotateY(The ${360 -
      activeCircle * 72}deg) rotateZ(0deg) scale(${gap}) `.opacity: gap,
  };
};
Copy the code

O (≧∇≦) O─ —


The map

Effect display:



My words (* ^ 3 ^) :


The need for weirdness (゚o゚; , because Party A thinks baidu Map and other locations are inaccurate, and the API of Baidu Map and Autademap are not allowed to be used, and they are not satisfied with the style of Map Heaven and Earth, we adopt the plan to draw the map in UI, export SVG, and then let the front end do various effects display according to SVG.

Steps:

  • The file content

The map files are as follows: the index.js main file contains hover events, the index.less style file, mapstyle. js holds the background map, and the pathstyle. js array format holds the path representing the small pieces on the map





  • Apply colours to a drawing map

The code is as follows:



According to the data given by the interface, fill different paths with different colors according to the five color systems

        const colorMap = [
          'rgba (89, 126, 247, 0.8)'.'rgba (0, 121, 254, 0.8)'.'rgba (0, 121, 254, 0.8)'.'rgba (38, 168, 254, 0.8)'.'rgba (192, 228, 253, 0.8)',];Copy the code

  • Increase suspension event

The render code looks like this:



Mouse over events:



Mouse out event:



O (≧∇≦) O─ —


Two-dimensional pie chart (windmill chart)

Effect display:



My words (* ^ 3 ^) :


Because echarts pie chart is a parameter latitude pie chart, and this UI requires two parameters latitude pie chart, can only draw (´; Omega. `). Because I used canvas to draw pie charts before, I thought it was simple, but party A’s father saw the results and said to add custom suspension events (which PRD did not have at the beginning), so I spent three days to draw a suitable version.

Add-on: Some people say echarts can also be implemented, I went to try, Echarts ZRender can be implemented.

Steps:

  • Incoming parameters
Option. push=[{color: color[I], // revenueTaxAvg radius: item.revenueTaxAvg, // revenueTaxAvg radius: item.domainName, // revenueTaxAvg radius: item.domainName, // revenueTaxAvg radius: item. Item.com panyCnt, // Pie block Angle}];Copy the code


  • DrawPieCanvas (‘econComposChart’, option);
How to draw a pie chart? Please refer to an article I wrote earlier: juejin.cn/post/684490…
== / * Note * / ==

This article is drawing Angle one latitude, just add another latitude radius.

Text and pictures drawn on canvas will be blurred to a certain extent. Solution: Double the width and height of canvas.


  • Suspended events

For collision detection, determine the mouse suspension is falling between which radian pie block, if no longer pie block inside the suspension style disappeared.


The main logic of judgment in mathematics is as follows:

If (distance from point to center < maximum radius of circle

Distance from the point && to the center of the circle > minimum radius of the circle

The Angle of the line from the point && to the center of the circle > the starting Angle of the sector

Angle of line from && point to center of circle < end Angle of sector){

The point is in the sector


}


// Use Pythagorean theorem to calculate the distance between the point and the center of the circle. DistanceFromCenter = math.sqrt (math.pow (circ.x -clickx, 2) + math.pow (circ.y -clicky, 2) 2)) // alpha (radians) = L (arc length)/r(radius), but I can't figure out the arc length. The range I mainly use is sine of x, as follows. Judge the value of sin (x) in different intervals, and infer what the value of the suspended region is.Copy the code



O (≧∇≦) O─ —


Triangular pyramid

Effect display:



Steps:

Main principle: two triangles + a circle = three pyramid



canvas.width = canvas.offsetWidth; Canvas. height = canvas.offsetHeight; ctx.clearRect(0, 0, canvas.width, canvas.height); Const {height} = canvas; CTX. MoveTo (100, 0); // Calculate the height of an equilateral triangle. // start from A (100,0) ctx.lineTo(0, height); // start from A(100,0) and end with B (0,height) ctx.lineTo(144, height); // B(0,height) -c (144, height) // second triangle a-c-d ctx.moveto (100, 0); // start from A (100,0) ctx.lineTo(143, height); // A-C ctx.lineTo(210, height); Arc (100, 23, 23, 0, math.pi * 2,false); // Draw circle <canvas id={' pyramid${id}'} height={itemHeight} /> // calculates itemHeightCopy the code

Logarithmic growth — Calculation of triangular pyramid height:



Suppose data = [0, 1, 2, 3, 4, 5], where x is any value; MaxHeight is the maximum height. ItemHeight (0 <= itemHeight< maxHeight), Const Max = Max (data) const Max = Max (data) const Max = Max (data) const Max = Max (data) const Max = Max (data MaxHeight < maxHeight = logmax(x) * maxHeight = loge(x)/loge(Max) // const Max =data.reduce((a, b) => {return a > b ? a : b;
}, 0);
itemHeight = x===0 ? 0 : Math.log(x) / Math.log(max) * maxHeight


Copy the code
== / * Note * / ==

The Y-axis calculation uses exponential growth, because any Max to the 0 power = 1, so the case of I <= 0 is judged separately

 i > 0 ? Math.round(max ** (i * 0.25)) : 0

cuboid

Effect display:



Steps:

html

<div id="cube">
        <figure class="front">1</figure>
        <figure class="back">2</figure>
        <figure class="right">3</figure>
        <figure class="left">4</figure>
        <figure class="top">5</figure>
        <figure class="bottom">6</figure>
 </div>Copy the code

css

#box.show-front { transform: translateZ( -50px ) rotateY( 0deg ); }
#box.show-back { transform: translateZ( -50px ) rotateX( -180deg ); }
#box.show-right { transform: translateZ( -150px ) rotateY( -90deg ); }
#box.show-left { transform: translateZ( -150px ) rotateY( 90deg ); }
#box.show-top { transform: translateZ( -100px ) rotateX( -90deg ); }
#box.show-bottom { transform: translateZ( -100px ) rotateX( 90deg ); }Copy the code

ItemHeight = itemHeight

Const sum =data.reduce((a, b) => {// Const sum =data.reduce((a, b) => {return a + b;
}, 0);
itemHeight = x <= min ? min : min + (max-min) * x /sum;Copy the code


O (≧∇≦) O─ —


Windshield wiper (fan pie chart)

Effect display:



Steps:

(1) Incoming transmission

Percent / / shareCopy the code

(2) Draw circles of different colors

 const circles = [
      { r: 37, stroke: '#0A63D6', lineWidth: 1 },
      { r: 43, stroke: 'rgba(79, 4, 175, 1)', lineWidth: 10 },
      { r: 53, stroke: '#0A63D6', lineWidth: 15 },
      { r: 63, stroke: '#0088F3', lineWidth: 20 },
      { r: 70, stroke: 'rgba (11, 84, 166, 0.5)', lineWidth: 70 },
    ];
const startAngle = 0.5 * Math.PI;
const endAngle = Math.PI * 2 * percent + startAngle;
   
for (const item of circles) {
      const { r, stroke, lineWidth } = item;
      const circle = new zrender.Arc({
        shape: {
          cx,
          cy,
          r,
          startAngle,
          endAngle,
        },
        style: {
          fill: 'transparent',
          stroke,
          lineWidth,
        },
      });
      zr.add(circle);
    }
Copy the code

(3) The blue edge outside the garden: The first position is fixed, and the first and second lines are realized by rotating the corresponding Angle

Const borderStyle={shape: {x1: cx, y1: cy + 37, x2: cx, y2: cy + 103.5,}, style: {stroke:'#0A63D6', lineWidth: 1, }, } const path1 = new zrender.Line(borderStyle); const path2 = new zrender.Line({ origin: [cx, cy], rotation: -Math.PI * 2 * percent, ... borderStyle });Copy the code

conclusion

Added: ak47 schematic item and loot added: This is the first time I wrote so many words summarizing the technical article. Most of the content is actually very simple, basically using junior high school, high school inside the most basic mathematics (actually difficult, I also won’t _φ(· _ ·).

Shamelessly, I may not be very good at writing, but THE main idea of each example should be conveyed.

Finally, see in my first time to write so many words, give a thumbs up (/// /▽///).