HT for Web list and drag-and-drop application of 3D topology components, ht Topology
Many visual editors have more or less drag functions, such as dragging a node from a List to a topology component for modeling, in addition, a thumbnail of the dragged node is attached to the mouse position during the drag and drop process, so we can achieve this drag effect today.
First, we need to create a ListView List and add image information to the List so that the List is not so monotonous. Let's take a look.
Next, let's take a step to solve the ListView list. Here we will list one or two items:
var products = [ { ProductId : 1, ProductName : "Chai", QuantityPerUnit : "10 boxes x 20 bags", UnitPrice : 18.00, Description : "Soft drinks, coffees, teas, beers, and ales" }, { ProductId : 2, ProductName : "Chang", QuantityPerUnit : "24 - 12 oz bottles", UnitPrice : 19.00, Description : "Soft drinks, coffees, teas, beers, and ales" }, ……];
With the data, we can create the ListView component:
var listView = new ht.widget.ListView();var view = listView.getView();document.body.appendChild(view);
At this time, we created an empty ListView component and couldn't see anything in the browser. Then we should add the data we defined to the ListView component:
products.forEach(function(product){ var data = new ht.Data(); data.a(product); listView.dm().add(data);});
It is easy to add Data, but the content displayed on the ListView component is the Data name attribute or displayName attribute by default. when Data is created, the displayName or name attribute is not set for Data, so we can see an empty List component on the page at this time. Don't worry. We can make the text content displayed on the component without setting the displayName or name attribute, see:
listView.getLabel = function(data){ return data.a('ProductName') + ' - $' + data.a('UnitPrice').toFixed(2);};
Hey, the ListView component provides the getLabel Method for users to reload to customize the displayed text content. Now we can display the text content ~
Oh no ~ There is nothing. Is there anything missing ~ By the way, I forgot to add the style filled with the browser to the ListView component and added the style of Xiamen to the head label:
<style> html, body { padding: 0px; margin: 0px; } .main { margin: 0px; padding: 0px; position: absolute; top: 0px; bottom: 0px; left: 0px; right: 0px; }</style>
Next, specify the className attribute of the view:
view.className = 'main';
Oh ~ Finally came out ~
The row height is too small, and the background is too monotonous:
listView.setRowHeight(50);listView.drawRowBackground = function(g, data, selected, x, y, width, height){ if(this.isSelected(data)){ g.fillStyle = '#87A6CB'; } else if(this.getRowIndex(data) % 2 === 0){ g.fillStyle = '#F1F4F7'; } else{ g.fillStyle = '#FAFAFA'; } g.beginPath(); g.rect(x, y, width, height); g.fill();};
Use the setRowHeight () method to set the row height, and use the reload drawRowBackground () method to draw a cross background.
Hey, it looks a bit closer and closer ~ The icon is missing.
ht.Default.setImage('1', 40, 40, 'data:image/jpeg;base64,...');ht.Default.setImage('2', 40, 40, ‘data:image/jpeg;base64,...');……listView.setIndent(60);listView.getIcon = function(data){ return data.a('ProductId');};
Through ht. default. the setImage () method defines the image resources corresponding to ProductId, takes ProductId as the image alias, and then defines the icon position size as 60. The getIcon Method of the ListView is overloaded to return the ProductId attribute defined in the data, then you can see the icon.
The image shown on is circular. How can this problem be solved? Don't worry, we have a omnipotent vector, so we can't beat down any of the above images:
ht.Default.setImage('productIcon', { width: 50, height: 50, clip: function(g, width, height) { g.beginPath(); g.arc(width/2, height/2, Math.min(width, height)/2-3, 0, Math.PI * 2, true); g.clip(); }, comps: [ { type: 'image', stretch: 'uniform', rect: [0, 0, 50, 50], name: {func: function(data){return data.a('ProductId');}} } ]});
In the code, we define a vector named productIcon. In the vector, the clip attribute is used to define the cropping area. The effect is that content beyond the cropping area will be hidden. Now that the vector is defined, we only need to return the vector name we defined in the getIcon () method of ListView to implement the Circular icon:
listView.getIcon = function(data){ return 'productIcon';};
Here, the results are exactly the same ~ Next, we should create a 3D topology component. Let's take a look:
Simply put two cubes in the 3D topology:
var g3d = new ht.graph3d.Graph3dView();var node = new ht.Node();node.s3(30, 30, 30);node.p3(-30, 15, 0);node.s('all.color', '#87A6CB');g3d.dm().add(node);node = new ht.Node();node.s3(30, 30, 30);node.p3(30, 15, 0);node.s('all.color', '#87A6CB');node.setElevation(15);g3d.dm().add(node);
You will find that there is no grid effect as shown in the figure, and the angle of view is not correct. It's okay. I will add several attributes to it:
g3d.setEye(-100, 100, 80);g3d.setGridVisible(true);g3d.setGridColor(‘#F1F4F7');
This is exactly the same ~
ListView and 3D topology are two independent components. How can we combine these two components? At this time, I thought of the BorderPane component, put the List component on the left, and put the 3D topology component on the right:
var borderPane = new ht.widget.BorderPane();borderPane.setLeftView(listView, 350);borderPane.setCenterView(g3d);
Check that the two components are successfully merged, not far from the success. Next is the major event of today. How can we drag the nodes on the List to the 3D topology and absorb the node icons to the 3D topology elements.
First, let's take a look at the handleDragAndDrop () method of ListView. draganddrop has four statuses: prepare, begin, between, and end. These four statuses can be used for different business processing.
The first step is to implement the effect of the icon attached to the mouse. When you drag a ListView node, add a thumbnail of the node below the mouse:
The idea is as follows:
1. Obtain the ProductId attribute of the current drag-and-drop node in the prepare state, and call the ht. Default. toCanvas () method to combine the current drag-and-drop node with the vector productIcon to obtain a canvas object;
2. Set the left and top attributes of the canvas object based on the current cursor position during the begin state and add them to the DOM tree;
3. In the between state, You can reset the left and top attributes of the canvas object based on the mouse position information to keep the canvas object moving with the mouse;
4. In the end state, remove the canvas object from the DOM tree.
var dragImage = null, productId = null;listView.handleDragAndDrop = function(e, state) { if (state === 'prepare') { var data = listView.getDataAt(e); listView.sm().ss(data); if (dragImage && dragImage.parentNode) { document.body.removeChild(dragImage); } dragImage = ht.Default.toCanvas('productIcon', 30, 30, 'uniform', data); productId = data.a('ProductId'); } else if (state === 'begin') { if (dragImage) { var pagePoint = ht.Default.getPagePoint(e); dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px'; dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px'; document.body.appendChild(dragImage); } } else if (state === 'between') { if (dragImage) { var pagePoint = ht.Default.getPagePoint(e); dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px'; dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px'; } } else { if (dragImage) { if (dragImage.parentNode) { document.body.removeChild(dragImage); } dragImage = null; productId = null; } }};
In this way, when you drag the ListView node, you can see that there is a small icon that keeps moving with the mouse.
OK, next we will solve the element adsorption function. When you drag the ListView node to the 3D topology, set the icon of the node to the current texture of the element.
The idea is like this:
1. In the between status, use the ht. Default. containedInView () method to determine whether the cursor is on the 3D topology component;
2. If the mouse is on the 3D topology, use the g3d. getHitFaceInfo () method to obtain the element surface information under the current mouse based on the current mouse information;
3. if the current mouse is on a certain surface of the element, save the texture of the surface information of the element, and then set the texture of the current element to the image corresponding to the drag and drop node, finally, the surface information of the current element is cached. When the mouse leaves the surface, the texture of the element is restored;
4. In the end state, if the current mouse position is on the surface of an element, the image corresponding to the current drag-and-drop node is used as the texture map of the current element surface.
Then you need to make some slight changes to the handleDragAndDrop () method of the ListView component.
listView.handleDragAndDrop = function(e, state) { if (state === 'prepare') { var data = listView.getDataAt(e); listView.sm().ss(data); if (dragImage && dragImage.parentNode) { document.body.removeChild(dragImage); } dragImage = ht.Default.toCanvas('productIcon', 30, 30, 'uniform', data); productId = data.a('ProductId'); } else if (state === 'begin') { if (dragImage) { var pagePoint = ht.Default.getPagePoint(e); dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px'; dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px'; document.body.appendChild(dragImage); } } else if (state === 'between') { if (dragImage) { var pagePoint = ht.Default.getPagePoint(e); dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px'; dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px'; if (ht.Default.containedInView(e, g3d)) { if (lastFaceInfo) { lastFaceInfo.data.s(lastFaceInfo.face + '.image', lastFaceInfo.oldValue); lastFaceInfo = null; } var faceInfo = g3d.getHitFaceInfo(e); if (faceInfo) { faceInfo.oldValue = faceInfo.data.s(faceInfo.face + '.image'); faceInfo.data.s(faceInfo.face + '.image', productId); lastFaceInfo = faceInfo; } } } } else { if (dragImage) { if (lastFaceInfo) { lastFaceInfo.data.s(lastFaceInfo.face + '.image', lastFaceInfo.oldValue); lastFaceInfo = null; } if (ht.Default.containedInView(e, g3d)) { var faceInfo = g3d.getHitFaceInfo(e); if (faceInfo) { faceInfo.data.s(faceInfo.face + '.image', productId); } } if (dragImage.parentNode) { document.body.removeChild(dragImage); } dragImage = null; productId = null; } }};
Today, let's get there. There are a lot of content and a lot of knowledge points related to HT for Web. The following is the source code of this Demo. If you are interested, you can take a look at it, you are also welcome to leave a message to ask questions.
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.