Author: Han Yonghao mobile development department front-end development engineer

In early November this year, our company participated in the “Asia Early Childhood Education Annual Conference (APEAC) 2017” and achieved very good results. I have the honor to be responsible for the front-end development of this presentation page, and I hereby record the key links in the development process.

The display page is divided into three modules: data display, dynamic display and map display. The effect is as follows:

The data show

This module shows our company’s data to date, updated regularly via asynchronous requests.

The dynamic effect of the digit transition is similar to the effect of a slot machine, where the new number of the corresponding digit replaces the old number from the bottom up, and there is no transition effect if the number of that digit has not changed.

To achieve this effect, the first step is to split the numbers by position:

// Separate each numberfunction split(num) {
    return (num || 0).toString().split(' ');
Copy the code

Then, add the thousandths, that is, start from the ones place, insert a comma every three places, the implementation code is as follows:

function toThousands(num) {
    var num = (num || 0).toString(), result = ' ';
    while (num.length > 3) {
        result = ', ' + num.slice(-3) + result;
        num = num.slice(0, num.length - 3);
    if (num) { result = num + result; }
    return result;
Copy the code

Finally, use style to control the transition animation, the key code is as follows:

<ul id="main" class="number">

	<li class="group">
	    <span class="old">1</span>
		<span class="new">1</span>

	<li class="group">
		<span class="old">,</span>
		<span class="new">,</span>

	<li class="group">
	    <span class="old">4</span>
	    <span class="new">1</span>

	<li class="group">
		<span class="old">5</span>
		<span class="new">5</span>

	<li class="group">
		<span class="old">6</span>
		<span class="new">2</span>

Copy the code
.number li {width: 0.18rem; Height: 0.24 rem; The line - height: 0.24 rem; display: inline-block; overflow: hidden; } .number li span { display: block; transform: translateY(0%); }.number span {animation: move 0.5s; animation-fill-mode: forwards; } @keyframes move {from {transform: translateY(0); } to { transform: translateY(-100%); }}Copy the code
var $main = document.querySelector('#main'); // Fill the numberfunctionUpdate (fromArr, toArr) {fromArr = fromarr.reverse (); toArr = toArr.reverse();if (fromArr.length > toArr.length) {
        toArr.length = fromArr.length
    } else{ fromArr.length = toArr.length } fromArr = fromArr.reverse(); toArr = toArr.reverse(); // Render the node and activate the animation var numberHTML =' '
    for(var i = 0; i < toArr.length; I++) {// if the number of bits has not changed, there is no transition effectif(formArr[i] ! == toArr[i]) { numberHTML += ('<li class="group active">' +
                '<span class="old">' + formArr[i] || ' ' + '</span>' +
                '<span class="new">' + toArr[i] || ' ' + '</span>' +
        } else {
            numberHTML += ('<li class="group">' +
                '<span class="old">' + formArr[i] || ' ' + '</span>' +
                '<span class="new">' + toArr[i] || ' ' + '</span>' +
            '</li>'); }}if (numberHTML) {
        $main.innerHTML = numberHTML; }}Copy the code

Dynamic display

This module is an area for visitors to interact on site. As long as you scan the QR code and click “like”, a new dynamic will be added. While the page is running, more than one person may be sending messages at the same time, so a thread should periodically request data and store it in a queue:

At the same time, another thread should read the queue for rendering:

The key code is as follows:

var cacheList = []; Var CHECK_INTERVAL = 2000; Var UPDATE_INTERVAL = 1000; Var MIN_CACHE = 10; // Check the queuefunction checkCache() {
    if(cachelist.length < MIN_CACHE) {// Asynchronously request data ajax(function(res) {
            if(res && res.length) { cacheList = cacheList.concat(res); // Merge the new data into the queue listsetTimeout(checkCache, CHECK_INTERVAL); // Polling check data}}}} // Start loadingfunction loadData() {
    if (cacheList.length > 0) {
        cacheList = cacheList.splice(0, 1);
    setTimeout(start, UPDATE_INTERVAL); } loadData(); // Data start checkCache(); // Start the queueCopy the code

The map shows

This module consists of a map of China, fixed blips, flickering blips and dynamic bubbles. Since both the blip and the bubble are associated with a geographic location (down to the province), each province must first be divided on the map. However, the occupation of provinces is irregular, divided up will have a certain difficulty. The initial idea was that each province would have a fixed number of spots, and that bubbles and blips would only appear at those spots. Although the effect can be achieved, it looks rather stiff and does not achieve the design effect. So there was another alternative. Calculus calculates the area of an irregular figure by dividing a large irregular figure into smaller rectangles that cover the entire irregular figure. Similarly, you just need to draw several small rectangles corresponding to each province and record them, and you can make the spots and bubbles appear in the corresponding province according to these coordinates. To make it easy to draw these little rectangles, I made a little tool that looks like this:

Since the page ADAPTS its width and height to the screen resolution, the map’s size on the page is not fixed (but the scale is fixed), so a little adjustment is made to generate coordinates as percentages rather than pixel values. Such as:

Var positionData = {startX: [{startX:'6.7164179104477615%',
    		endX: '34.07960199004975%',
    		startY: '8.602941176470589%',
    		endY: '19.77941176470588%'
    		startX: '25.37313432835821%',
    		endX: '35.69651741293532%',
    		startY: '3.5049019607843137%',
    		endY: '8.602941176470589%'},... ] , Guangdong: [{...}...] . };Copy the code

Finally, all you need to do is to select a piece of the small rectangle, and then randomly select a point from the area of the small rectangle to show the spot and bubble:

/ var/map$map = document.querySelector('#map'); // Get a random pointfunctionGetPosition (type) {// Get a random rectangle in the provincefunction getPositionArea(areaArray) {
    	returnareaArray[Math.round(Math.random() * areaArray.length)]; Var area = getPositionArea(positionData[province]); var x = parseFloat(area.endX) - parseFloat(area.startX); var y = parseFloat(area.endY) - parseFloat(area.startY);return {
       x: parseFloat(area.startX) + (Math.random() * x) + The '%',
       y: parseFloat(area.startY) + (Math.random() * y) + The '%'}; } // Get a new spotfunction getPoint($point, province) {
    if (!$point) {
        $point = document.createElement('div'); // If the animation ends, remove the blip and start again$point.addEventListener('animationend'.function() {
            start($point); }); } var position = getPosition(provice); .return $point; } // Refresh the style and randomly add the mapfunction start($point) {
    $point = getPoint($point);
    setTimeout(function() {
        $point.classList('active'); }, math.round (math.radom () * 1000))} var POINT_COUNT = 600;for (var i = 0; i < POINT_COUNT; i++) {
Copy the code

And we’re done.

Emergency treatment

As can be seen above, the data and animation on the page are very large, and the equipment of the exhibition may not be able to meet such performance requirements. If you run into a machine with low performance, you need to reduce the data or soften the animation. This page supports specifying performance options as URL parameters for easy adjustment by field workers. Such as:

/exhibition? pointCount=300Copy the code

The pointCount parameter is used to modify the number of points, which defaults to 600. There are other parameters that I won’t list one by one. Finally, check out the results!