xhload3d

www.hightopo.com

  Blog garden: :Home page: :Bo asked: :Flash memory: :New essays: :contact: :To subscribe to : :management: :
160 Essay :: 1 article :: 283 Comment :: 0 citation
< In June 2018 >
day one two three four five six
27 28 29 30 31 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
1 2 3 4 5 6 7

The announcement

xhload3d



Four years and five months



297



0
+ add attention

search




Commonly used links

  • My essay
  • My comments
  • I participate in
  • The latest comments
  • My label

My label

  • HTML5(134)
  • 3D(63)
  • WebGL(56)
  • Hightopo(49)
  • Industrial control (45)
  • Telecommunication Network Management (30)
  • The topology (30)
  • Telecom (26)
  • Canvas(26)
  • Topology (25)
  • More and more

Archives of essays

  • May 2018 (4)
  • April 2018 (4)
  • March 2018 (6)
  • February 2018 (3)
  • January 2018 (6)
  • December 2017 (6)
  • November 2017 (10)
  • October 2017 (4)
  • June 2017 (2)
  • May 2017 (2)
  • February 2017 (1)
  • December 2016 (1)
  • October 2016 (4)
  • September 2016 (6)
  • August 2016 (4)
  • July 2016 (4)
  • June 2016 (3)
  • February 2016 (3)
  • December 2015 (4)
  • November 2015 (11)
  • October 2015 (10)
  • September 2015 (4)
  • August 2015 (2)
  • July 2015 (3)
  • June 2015 (1)
  • May 2015 (3)
  • April 2015 (2)
  • March 2015 (5)
  • February 2015 (1)
  • January 2015 (3)
  • December 2014 (9)
  • November 2014 (7)
  • October 2014 (1)
  • September 2014 (2)
  • August 2014 (3)
  • July 2014 (1)
  • June 2014 (3)
  • May 2014 (1)
  • April 2014 (1)
  • March 2014 (3)
  • February 2014 (3)
  • December 2013 (4)

The latest comments

  • 1. Re: WebGL 3D Tetris based on HTML5
  • That’s amazing. Bow down
  • — Ordinary boy
  • 2. Re: Low-carbon industrial park monitoring system based on HTML5 WebGL
  • @Grey Wolf’s dream laughs me to death…
  • — Iron hand on the keyboard
  • 3. Re: Low-carbon industrial park monitoring system based on HTML5 WebGL
  • frigging awesome
  • – Guo Xiaozhai
  • Re: Monitoring system of low-carbon industrial park based on HTML5 WebGL
  • @13, See clearly? Is this developed in Java? .
  • Grey Wolf’s dream
  • Re: Monitoring system of low-carbon industrial park based on HTML5 WebGL
  • Java niubi, blogger niubi
  • – 13,

Reading leaderboards

  • 1. 3D Computer room monitoring application of TELECOM NETWORK Management based on HTML5 (16630)
  • 2. Hundreds of HTML5 examples to learn HT graphics components – Topology (13305)
  • 3. Hundreds of HTML5 examples of learning HT graphics components — WebGL 3D (4593)
  • 4. 100 lines JS implementation of HTML5 3D Snake game (4121)
  • 5. Rapid development of HTML5 interactive subway Line map (4049)

Review charts

  • 1. 3D Computer room monitoring application of Telecom NETWORK Management based on HTML5 (31)
  • 2. Rapid development of HTML5 interactive Subway Line map (18)
  • 3. Hundreds of HTML5 examples to learn HT graphics components – Topology (13)
  • 4. Power 3D Monitoring Application based on HTML5 Technology (IV) (11)
  • 5. HTML5 3D Snake game with 100 lines OF JS (9)

Recommended leaderboard

  • 1. Rapid development of HTML5 interactive Subway Line map (36)
  • 2. 3D Computer room Monitoring Application of Telecom NETWORK Management based on HTML5 (31)
  • 3. Hundreds of HTML5 examples to learn HT graphics components – Topology (27)
  • 4. Hundreds of HTML5 examples of learning HT graphics components — WebGL 3D (16)
  • 5. Application of HTML5 technology in wind power, photovoltaic and other new energy fields (13)

Implement GIS telecom resource management system based on HTML5 OpenLayers3

preface

Through the combination of HTML5 and OpenLayers, it can be combined into a very good application of telecom map network topology map. The resulting effect can be used as a telecom resource management system, food positioning and sharing software, area housing, drawing railway lines and so on, which can be involved in various fields. Although this Demo is integrated with OpenLayers3, it can also be generalized to integrate with ArcGIS, baidu map, GoogleMap and many other GIS map engines.

www.hightopo.com/demo/openla…

Code generation

Create a map

OpenLayers is a JavaScript package for developing WebGIS clients. The Map sources supported by OpenLayers include Google Maps, Yahoo, Map, Microsoft Virtual Earth and other offline online Maps. The popular Online Map of Google Map is used here. Before using OpenLayers, only the relevant class libraries and CSS files need to be introduced:

<link rel="stylesheet" href="css/ol.css" type="text/css">
<script src="lib/ol.js"></script>Copy the code

To initialize a Map, place the Map in a div element, initialize an ol.Map Map class, which is essential in the entire telecom resource management system, and then set the parameters in this class:

var mapDiv = document.getElementById('mapDiv'); Map = new ol. map ({target: 'mapDiv',// map container: Ol.control.defaults ().extend([graphViewControl,// custom topology control new ol.control.overviewMap (),// map global view control new Ol.control.scaleline (),// Scale control new ol.control.zoomSlider (),// scale scale control new ol.control.zoomToextent ()// scale to global control]), Layers: [// layer new ol.layer.Tile({source: New ol. Source. XYZ ({/ / Google maps url: "http://www.google.cn/maps/vt/pb=! 1 m4! 1 m3! 1 I {} z! 2 I {x}! 3 I {} y! 2 m3! 1 e0! 2 sm! 3 i345013117! 3 m8! View: new ol.view ({// map view view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: {// map view: 'EPSG:3857',// Projection Center: ol.proj.fromlonlat ([106, 35]),// The initial center of the view is defined by the projection option zoom: 4// The zoom level is used to calculate the initial resolution of the view})});Copy the code

The above code should have no difficulty with the official API explanation for each line of code comments. If you’re interested, you might have noticed an unofficial control: the graphViewControl, which I customized to draw topology graphs on. The declaration and definition sections are in the graphViewControl.js file.

Custom control

To customize the OpenLayers controls, you simply inherit a class from ol.Control. control, and then override the parent class methods or add methods for different needs.

I passed an options parameter to declare the class by setting the container element of the control at class definition and rendering the control outside the VIEWport of the GIS map:

var view = graphView.getView(); // Get the topology component's div ol.control.control. call(this, {element: view,// control's container element target: options.target// render the control outside the viewport of the map});Copy the code

The graphView above is a new method added to the parent method via the GraphViewControl and initialized to hT.graph. graphView, the topological component of HT:

/ / get GraphViewControl GraphView object. The prototype. GetGraphView = function () {return enclosing _graphView; }; var graphView = this._graphView = new ht.graph.GraphView(); // Topology componentsCopy the code

I also added some event monitoring to the graphView topology component in the control. Since OpenLayers and HT are two different JS libraries with their own interactive systems and coordinate systems, First we’ll take some of the interaction events we need to do on HT and stop propagating them to OpenLayers:

Var stopGraphPropagation = function(e) {var data = graphView.getDataAt(e); / / graphView events captured nodes under var interaction = graphView. GetEditInteractor (); / / access to edit interaction, the if (data | | e.m etaKey | | e.c. with our fabrication: trlKey | | interaction && interaction. GvEditing) {e.s topPropagation (); This method stops the propagation of the event, preventing it from being dispatched to other Document nodes}} /** pointerDown When the pointer becomes an active event * For the mouse, it is triggered when the device transitions from a pressed button to at least one button being pressed. * For touch, it is triggered when physical contact is made with the digitizer. * For pens, it is triggered when the stylus makes physical contact with the digitizer. **/ view.addEventListener('pointerdown', stopGraphPropagation, false); view.addEventListener('touchstart', stopGraphPropagation, false); View. addEventListener(' mouseDown ', stopGraphPropagation, false); // Mouse click eventsCopy the code

The GraphViewControl class definition section also adds some interactive events for moving and editing nodes, It is mainly to convert the pixel coordinates of the node into the coordinates projected in the Ol. Cordinate map view of OpenLayers and store them in the business attributes of the node (an object of HT that can store arbitrary values). In this way, we can freely obtain and set the pixel coordinates of the node on the map by obtaining or setting the business attribute coord of the node.

Var position = data.getPosition(),// Get the coordinates of the selected node x = position.x + graphView.tx(),// the horizontal coordinate of the node +graphView y = position.y + graphView.ty(); / / node vertical ordinate + graphView translational value var coord = map. GetCoordinateFromPixel ((x, y)); // Get map view projection coordinates data.a('coord', coord);Copy the code

I will mention some basic features here, and leave the rest unexplained, just some extensions.

It is worth noting that we face in the nodes in the telecom GIS map view projection coordinates in data storage, but this method is not very suitable for Shape types of nodes, is commonly used for map points into regional surface, draw the outline of the outline of a country or a city, are not real-time keep size when scaling, Instead, the map is scaled according to the scale of the map, keeping it in a certain position on the telecom GIS map in real time. Therefore, I traversed all the points in the node of Shape type, set the business attribute pointCoord, and obtained the coordinates in the map view projection:

/ / to shape types of nodes of every point location is set to the longitude and latitude if (e.k ind = = = 'endEditPoint' | | e.k ind = = = 'endEditPoints' | | e.k ind = = =' endEditResize ' | | e.k ind = = = 'endMove') {if (data instanceof ht. The Shape) {/ / Shape data. The type of node getPoints (). The forEach (function (point, index) { var pointCoord = map.getCoordinateFromPixel([point.x, point.y]); // Get the coordinates of the given pixel data.a('pointCoord['+index+']', pointCoord); }); }}Copy the code

The layer stack

The structure of OpenLayers is complicated, while HT is much simpler, so I superimposed HT into the Viewport of OpenLayers Map. Here I subclass GraphViewControl by overloading the setMap method of ol.Control. control to add the TOPological component of HT to the OpenLayers viewPort. We know that HT components are always absolutely positioned, so we need to set the position and width properties in CSS:

var graphView = self._graphView; // = GraphViewControl.getGraphView() var view = graphView.getView(); // Get graphView component div var dataModel = graphView.getDatamodel (); // Get the graphView data container view.style.top = '0'; view.style.left = '0'; view.style.width = '100%'; view.style.height = '100%'; map.getViewport().insertBefore(view, map.getViewport().firstChild); InsertBefore Inserts a new child node before the specified child node.Copy the code

And monitor the events of adding and deleting changes to the data container. By monitoring the node type currently added to the data container, convert the pixel coordinates of the current node into coordinates in the map view projection and store them on the node’s business attribute coord:

DataModel. AddDataModelChangeListener (function (e) {/ / data container to add and delete changes to monitor the if (e.k ind = = = 'add' &&! (e.ata instanceof HT. Edge)) {// Add event && Event object not hT. Edge if (e.ata instanceof HT. Node) {var position = e.data.getPosition(); var coordPosition = map.getCoordinateFromPixel([position.x, position.y]); E.data. a('coord', coordPosition); } if (e.ata instanceof ht.Shape) {// Set the latitude and longitude of each point on the Shape node. About the type of shape index) {/ / node will all point coordinates to latitude and longitude var pointCoord = map. GetCoordinateFromPixel ([point. X, point. The y]); E.data. a('pointCoord['+index+']', pointCoord); }); }}});Copy the code

Finally, listen to the map update event and reset the topology:

map.on('postrender', function() { self.resetGraphView(); });Copy the code

Coordinate transformation

Resetting the topology here means taking the node coordinates of the topology from the pixel coordinates that we originally set in HT and resetting the map view projection coordinates to pixel coordinates on the node by zooming or moving the map. This is where the business property coord that we stored previously comes in. Remember, Shape nodes are the exception, or do we need to reset the coordinates for each point in them:

GraphViewControl. Prototype. ResetGraphView = function () {/ / reset graphView component state var graphView = this. _graphView; graphView.tx(0); // grpahView horizontal translation value graphView.ty(0); Each (function(data) {var coord = data.a('coord'); / / to get business property coord if (coord) {var position = map. GetPixelFromCoordinate (coord); SetPosition (position[0], position[1]); } if (data instanceof ht.shape) {var points = data.topoints (); // Build a new set of Shape points and return data.getpoints ().clear(); Data._points = new ht.list (); points.forEach(function(point, Index) {/ / give shape to setting the pixel coordinates of each point, x = map. GetPixelFromCoordinate (data) a (' pointCoord [" + index + "] ')) [0]. point.y = map.getPixelFromCoordinate(data.a('pointCoord['+ index +']'))[1]; data._points.add(point); }); data.setPoints(data._points); }}); graphView.validate(); // Refresh topology components}Copy the code

Scenario building

But as you can see from the screenshot above, in addition to the Map, there is a toolbar at the top (but I did it using the formPane form component), and a drag and drop Palette component on the left. Lay out the entire scene with HT’s borderPane Border panel component:

raphViewControl = new GraphViewControl(); / / custom controls, custom controls as openlayers map graphView = graphViewControl. GetGraphView (); Dm = graphView.getDatamodel (); // Get the data container palette in the topology = new ht.widget.palette (); // Create a component pane formPane = createFormPane(); // borderPane = new ht.widget.borderPane (); // borderPane. SetTopView (formPane); // Set the top component to formPane borderpane. setLeftView(Palette, 260); Borderpane.setcenterview (mapDiv); // Set the left component to palette. Parameter 2 sets the width of the view. // Set the intermediate component to mapDiv borderpane.addTodom (); // Add the panel component to the bodyCopy the code

So the layout and display of the whole scene is complete, very easy ~

The toolbar

HT has its own toolbar, but uses it because forms can be more flexible in layout and style.

var fp = new ht.widget.FormPane(); fp.setVGap(0); // Set the horizontal spacing of the form components to 6 fp.sethgap (0); // Set the vertical line spacing of the form to 6 fp.sethpadding (4); // Set the spacing between the left and right sides of the form and the content of the component. The default is 8 fp.setVPAdding (4); // Set the spacing between the top and the top of the form and the content of the component. The default is 8 fp.setheight (40); Var btBgColor = '# FFF ', btnIconColor = 'RGB (159, 159, 159)', btnSelectColor =' RGB (231, 231, 231)'; Fp. addRow([// add a '' at the beginning and end of each row, and the width is relative to 0.1, to center the middle part of the row ", {id: Button: {// ht.widget. button is the background of the button class: {// ht.widget. button is the background of the button class: BtBgColor, / / set the background color icon: '. / symbols/icon/select. Json ', / / Settings icon iconColor: btnIconColor, / / Settings icon color selectBackground: GroupId: 't',// Set the group number. Togglable buttons that belong to the same group are mutually exclusive. 'Edit ',// Sets the text tooltip. You can enable and disable the text tooltip with enableToolTip() and disableToolTip(). }}}, {id: 'pointLine', button: {background: btBgColor, icon: './symbols/icon/line.json', iconColor: btnIconColor, selectBackground: btnSelectColor, togglable: true, groupId: 't', toolTip: 'Connect ', onClicked: Function () {/** Perform Group, Edge, and SubGraph actions by default. * TouchInteractor implements Touch interaction on mobile devices * CreateEdgeInteractor is a custom wire interactor in the createedgeInteractor.js file * CreateShapeInteractor Is a custom polygon interactor for createshapeinteractor.js **/ GraphViet.setInterActor ([new) ht.graph.DefaultInteractor(graphView), new ht.graph.TouchInteractor(graphView, { selectable: False}), new CreateEdgeInteractor (graphView)]);}}}, ' '], [0.1, 36, 36, 0.1]);Copy the code

I only listed two functions for adding lines in the form above, one for editing and the other for drawing lines. Formpane. addRow is to add a row of elements. Parameter 1 is an array of elements, which can be strings, component parameter information described in JSON format, HTML elements, or null. Parameter 2 is an array of the width information of each element. Can also be 80+0.3 combination.

In order for the part I wanted to show to be right in the center of the toolbar, I set a blank on both the first and last items, with a relative width of 0.1 and the same ratio, so that the middle part would be right in the center.

The above code uses setInteractors to compose the desired interactors. DefaultInteractor implements Group, Edge and SubGraph element’s default double click response, hand grab graph pan, scroll wheel zoom, keyboard response and other functions; Touch Actor implements Touch interactive functions on mobile devices. The last CreateEdgeInteractor is a wire-creation Interactor that inherits from the HT.graph. Interactor. Take a closer look at this section so that you can modify or customize new interactions later.

Custom interactors

We define classes with HT.default. def(className, superClass, methods) and declare methods and variables in methods objects.

The setUp method is called when the object is created, as required to set some functions here. I set it to clear all selected nodes:

SetUp: the function () {/ / CreateEdgeInteractor object is created when the function called CreateEdgeInteractor. The superClass. SetUp. The call (this); this._graphView.sm().cs(); // Clear all checks}Copy the code

The tearDown method is called when the object ends the call. What if the drawing is not finished? The next drawing cannot continue with the previous drawing, so we need to clear all previous drawing points at the end of the call to this class:

TearDown: function () {/ / end call CreateEdgeInteractor object called function CreateEdgeInteractor. The superClass. TearDown. Call (this); This. _source = null; this._source = null; this._target = null; this._logicalPoint = null; }Copy the code

With regard to mouse events and touch events, I want them to operate identically, so I call the touch event method directly within the mouse event.

To draw a cable, select a node with the left mouse button, hold the left mouse button, and move the mouse pointer to the end node of the cable. At this time, a cable is created.

First, touchStart selects a node:

Handle_mousedown: function (e) {this.handle_touchStart (e); }, handle_touchstart: function (e) {touch this._sourcenode = this.getNodeat (e); If (this._sourcenode) {this._targetNode = null; // Initialize targetNode this.startdragging (e); this._graphView.addTopPainter(this); // Add top Layer Painter to the topology. This._graphview.sm ().ss(this._sourcenode); }}, getNodeAt: Function (e){if (ht.default.isleftButton (e) &&ht.default.gettouchCount (e) === 1) {// The left mouse button is pressed && Var data = this._graphView.getdataat (e); var data = this._graphView.getdataat (e); If (data instanceof ht.Node) return data; // Ht. Node} return null; }Copy the code

 

Then swipe your finger over touchMove:

handleWindowMouseMove: function (e) { this.handleWindowTouchMove(e); }, handleWindowTouchMove: function (e) {var graphView = this._graphView; // Topology component this.redraw(); / / if not to draw a rectangle area, easy cause dirty rectangle enclosing _logicalPoint = graphView. GetLogicalPoint (e); This._targetnode = this.getNodeat (e); If (this._targetNode) graphView.sm().ss([this._sourcenode, this._targetNode]); Else GraphView.sm ().ss([this._sourcenode]); Function () {var p1 = this._sourcenode.getPosition (); p2 = this._logicalPoint; if (p1 && p2) { var rect = ht.Default.unionPoint(p1, p2); // Combine the dots into rectangles ht.default. grow(rect, 1); // Change the size of rect, extend the size of this._graphView.redraw(rect), extend the size of this._graphview.redraw (rect); // Redraw the topology, redraw all primitives in the topology if rect is null, otherwise redraw primitives within the rectangle}}Copy the code

Finally, touchEnd creates the line:

handleWindowMouseUp: function (e) { this.handleWindowTouchEnd(e); }, handleWindowTouchEnd: function (e) { if (this._targetNode) { var edge = new ht.Edge(this._sourceNode, this._targetNode); If (this._edgeType) edge.s('edge.type', this._edgeType); // Set the type of the wire this._graphView.dm().add(edge); // Add the node to the data container this._graphView.sm().ss(edge); } editableFunc(); / / draw the article tool, select the "edit" after this. _graphView. RemoveTopPainter (this); // Remove the top brush}Copy the code

As for the wire before it is created (that is, the termination node is selected), the mouse will create a wire during dragging, which is drawn directly with canvas:

Draw: function (g) {var p1 = this._sourcenode.getPosition (), p2 = this._logicalPoint; if(p1 && p2){ g.lineWidth = 1; g.strokeStyle = '#1ABC9C'; g.beginPath(); g.moveTo(p1.x, p1.y); g.lineTo(p2.x, p2.y); g.stroke(); }}Copy the code

That’s the end of the custom wiring class!

Panel component

The left panel component hT.Widget.Palette supports custom styles, option and drag operations, which are driven by HT. DataModel. Ht. Group displays groups, and Ht. Node displays button elements.

To display a group, first create the group and the button element in the group:

Function initPalette(Palette) {// Load the palette from the palette component var nodeArray = ['city', 'equipment']; Var nameArray = [' city ', 'large ']; For (var I = 0; i < nodeArray.length; i++) { var name = nameArray[i]; nodeArray[i] = new ht.Group(); // Palette will be in "palette", and then add palette to "palette".dm().add(nodeArray[I]); // Add the Group primitive nodeArray[I].setExpanded(true) to the Palette component; NodeArray [I].setName(name); Var imageArray = []; switch(i){ case 0: ImageArray = ['symbols/5.json', 'Symbols /6.json',' Symbols/forklift. Json ', 'Symbols/bus. Json ',' Symbols/man. 'symbols/ person 2.json', 'symbols/ person 3.json', 'symbols/ tree. Json ', 'symbols/ tree 2.json']; break; case 1: ImageArray = [' Symbols/airplane. json', 'Symbols/crane. Json ',' Symbols/truck. Json ', 'Symbols/freighter. 'symbols/park. Json]; break; default: break; } setPaletteNode(imageArray, nodeArray[i], palette); }} function setPaletteNode(imageArray, array, Palette) {// Create a node in the Palette and set the name, display image, parent-child relationship for (var I = 0; i < imageArray.length; i++) { var imageName = imageArray[i], name = imageName.slice(imageName.lastIndexOf('/')+1, imageName.lastIndexOf('.')); // Get the last/and the last. The middle text, as the name createNode of the node (imageName, Name, Array, Palette); // Create a node, Function createNode(Image, name, parent, Palette) {// Create a node on the Palette component var node = new ht.node (); palette.dm().add(node); // Add the node to the data container in the palette node.setimage (image); // Set the image of the node node.setName(name); // Set the node name node.setparent (parent); // Set the node's parent node.s({// set the node's property 'draggable': True,// If the Node draggable is set to true, the Palette will handle the dragstart automatically, but the dragover and drop events will require 'image.stretch': 'centerUniform',// Render images in non-distortion mode}); return node; }Copy the code

Once created, we need to enable the simulated drag event handleDragAndDrop(e, state) :

palette = new ht.widget.Palette(); // Create a component palette var data; The palette. HandleDragAndDrop = function (e, state) {/ / the left panel component drag and drop function if (state = = = 'prepare') data = the palette. GetDataAt (e); else if( state === 'begin' || state === 'between' ) {} else { if (! ht.Default.containedInView(e, graphView)) return; Var node = new ht.node (); // Drag to graphView to create a new node to display on graphView node.setimage (data.getimage ()); // Set the node texture node.setName(data.getName()); // Set the name (for display in the property bar) node.s('label', ''); P (graphView.lp(e)); // The value of setName does not appear below the node in graphView. Graphview.dm ().add(node); // Set the position of the node to the logical coordinate in the topology under the graphView event. // Add a node to the graphView graphView.sm().ss(node); // Select graphView.setfocus (node) by default; // Set the focus to the node editableFunc(); // Set the node to editable and select edit from the navigation bar}}Copy the code

Now you can drag the node directly from the palette component on the left to the graphView topology on the map on the right.

We can edit the drawing nodes, draw lines, draw right angles and draw polygons on the graphView.

The last

On the basis of telecommunication resource management system based on GIS switch I tried to increase the function of the map, at the same time also on the navigation bar to add the “subway line diagram”, the subway line diagram to implement is very severe, next time I’ll on the subway route map for an explanation, there is not much explanation, to see the final results after I add:





www.hightopo.com/demo/openla…

If you have any suggestions or comments, please leave a message or send me a private message. You can also go to HT for Web (hightopo.com/) for related information.

 

xhload3d
The editor
collection


Refresh the comments
Refresh the page
Return to the top
The login
registered
access
More than 500,000 VC++ source code: large configuration industrial control, power simulation CAD and GIS source code library!



[Recommendation] Huawei Cloud 7 star products 0 yuan free use



【 Contest 】 The first “Indomitable Sky and Ground” AI Developer Contest in 2018




Latest IT News



Tiktok: I sincerely wish Tencent Weishi can dominate the world



Mobile officially launches eSIM One Dual Terminal: Open tutorial here



Tmall 618 got off to a great start: Mi 8 sold out in just 60 seconds and sold more clothes in 13 minutes than last year



Suning Automobile 618: Used car online channel online



Leshi received the valuation report of its subsidiaries, including Legrong Zhixin, which was valued at 9.66 billion yuan



More news…

Latest Knowledge Base articles



How do cloud, fog and haze computing work together



You can think of programming as a lifelong career



The Art of Reviewing — Talk about code reviews in the real world



How to Study effectively



What makes a good programmer?



More knowledge base articles…
Today in History:



User interaction based on HTML5 Canvas