feat: 后端全量更新 - 含所有本次需求
- Contract.php: 返回合约账户余额(balance_contract) - My.php: 地址管理增加BTC/ETH - AppContract.php: 一键平仓(closeall) - AppProxy.php: 代理专属注册链接 + 分级权限(L1/L2) - site.php: 手续费减半(0.018→0.009) - agent_permission_setup.sql: 代理权限SQL - crypto_news_crawler.py: 新闻自动采集脚本
This commit is contained in:
Executable
+332
@@ -0,0 +1,332 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Belts</title>
|
||||
<!-- Copyright 1998-2020 by Northwoods Software Corporation. -->
|
||||
<meta name="description" content="Belts & gears: chains, pulleys, tensioners, conveyor belts, rollers." />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<script src="../release/go.js"></script>
|
||||
<script src="../assets/js/goSamples.js"></script> <!-- this is only for the GoJS Samples framework -->
|
||||
<script id="code">
|
||||
function init() {
|
||||
if (window.goSamples) goSamples(); // init for these samples -- you don't need to call this
|
||||
var $ = go.GraphObject.make;
|
||||
|
||||
myDiagram =
|
||||
$(go.Diagram, "myDiagramDiv",
|
||||
{
|
||||
"InitialLayoutCompleted": function(e) {
|
||||
updateBelts(); // changes the bounds of the "Belt"s
|
||||
e.diagram.alignDocument(go.Spot.Center, go.Spot.Center);
|
||||
},
|
||||
"animationManager.isEnabled": false,
|
||||
"undoManager.isEnabled": true,
|
||||
allowCopy: false,
|
||||
allowDelete: false,
|
||||
"draggingTool.moveParts": function(parts, offset, check) {
|
||||
go.DraggingTool.prototype.moveParts.call(this, parts, offset, check);
|
||||
updateBelts(); // this is inefficient if there are a lot of belts
|
||||
}
|
||||
});
|
||||
|
||||
function commonStyle() {
|
||||
return [
|
||||
new go.Binding("location", "xy", go.Point.parse).makeTwoWay(go.Point.stringify),
|
||||
{
|
||||
locationSpot: go.Spot.Center, locationObjectName: "GUIDE",
|
||||
selectionAdorned: false,
|
||||
dragComputation: function(node, newloc, snaploc) {
|
||||
// don't allow rollers or drums to overlap each other
|
||||
var oldloc = node.location;
|
||||
var noderad = node.findObject("GUIDE").actualBounds.width/2;
|
||||
var ok = true;
|
||||
var it = node.diagram.nodes.iterator;
|
||||
while (it.next()) {
|
||||
var n = it.value;
|
||||
if (n === node || n.category === "Belt") continue;
|
||||
var dist2 = newloc.distanceSquaredPoint(n.location);
|
||||
var rad = n.findObject("GUIDE").actualBounds.width/2;
|
||||
if (dist2 < (noderad+rad)*(noderad+rad)) { ok = false; break; }
|
||||
}
|
||||
return ok ? newloc : oldloc;
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
myDiagram.nodeTemplateMap.add("Roller",
|
||||
$(go.Node, "Spot", commonStyle(),
|
||||
$(go.Shape, "Circle",
|
||||
{ name: "GUIDE", fill: "lightgray", strokeWidth: 0, width: 20, height: 20 },
|
||||
new go.Binding("width", "diameter").makeTwoWay(),
|
||||
new go.Binding("height", "diameter")),
|
||||
$(go.TextBlock,
|
||||
{ font: "6pt sans-serif", stroke: "black" },
|
||||
new go.Binding("text", "key"))
|
||||
));
|
||||
|
||||
myDiagram.nodeTemplateMap.add("Drum",
|
||||
$(go.Node, "Spot", commonStyle(),
|
||||
$(go.Shape, "Circle",
|
||||
{ name: "GUIDE", fill: "lightgray", stroke: "gray", width: 80, height: 80 },
|
||||
new go.Binding("fill", "color")),
|
||||
$(go.TextBlock,
|
||||
{ font: "6pt sans-serif", stroke: "darkblue" },
|
||||
new go.Binding("text", "key"))
|
||||
));
|
||||
|
||||
myDiagram.nodeTemplateMap.add("Belt",
|
||||
$(go.Node,
|
||||
{ selectionAdorned: false, layerName: "Foreground", copyable: false, movable: false },
|
||||
$(go.Shape,
|
||||
{ name: "BELT", fill: null, stroke: "gray", strokeWidth: 2, strokeDashArray: [4, 2] },
|
||||
new go.Binding("stroke", "color"))
|
||||
));
|
||||
|
||||
load();
|
||||
} // end init
|
||||
|
||||
function updateBelts(coll) {
|
||||
if (!coll) coll = myDiagram.nodes;
|
||||
myDiagram.startTransaction();
|
||||
coll.each(updateBelt);
|
||||
myDiagram.commitTransaction("updated belts");
|
||||
}
|
||||
|
||||
function updateBelt(node) {
|
||||
if (node.category !== "Belt") return;
|
||||
var belt = node.findObject("BELT");
|
||||
var diagram = node.diagram;
|
||||
var guideinfos = node.data.guides;
|
||||
if (!Array.isArray(guideinfos)) throw new Error("data.guides is not an Array for Belt node: " + node.data.key);
|
||||
|
||||
// gather basic information about each guide node
|
||||
var guides = []; // holds Objects with handy information
|
||||
for (var i = 0; i < guideinfos.length; i++) {
|
||||
var info = guideinfos[i];
|
||||
var guidenode = diagram.findNodeForKey(info.k);
|
||||
if (guidenode !== null && guidenode.location.isReal()) {
|
||||
var loc = guidenode.location;
|
||||
var cyl = guidenode.findObject("GUIDE");
|
||||
var radius = (cyl !== null) ? cyl.measuredBounds.width / 2 : 10;
|
||||
if (guides.length > 0) {
|
||||
var prevguide = guides[guides.length - 1];
|
||||
var prevloc = prevguide.location;
|
||||
var prevradius = prevguide.radius;
|
||||
var dist = Math.sqrt(prevloc.distanceSquaredPoint(loc));
|
||||
if (dist < Math.abs(prevradius-radius)) { // one is completely inside the other
|
||||
if (prevradius > radius) {
|
||||
continue; // skip this smaller guide
|
||||
} else {
|
||||
guides.pop(); // skip the previous guide, which was smaller
|
||||
}
|
||||
}
|
||||
}
|
||||
guides.push({
|
||||
node: guidenode,
|
||||
location: guidenode.location.copy(),
|
||||
radius: radius + belt.strokeWidth/2,
|
||||
outside: !!info.outside,
|
||||
from: null, // these Points will be computed by computeContacts
|
||||
to: null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// handle some degenerate cases
|
||||
if (guides.length < 2) {
|
||||
if (guides.length === 1) {
|
||||
node.location = guides[0].location;
|
||||
}
|
||||
if (belt !== null) {
|
||||
belt.geometry = new go.Geometry(go.Geometry.Ellipse);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// compute the contact points
|
||||
// assume guides are listed in clockwise order
|
||||
for (var i = 0; i < guides.length; i++) {
|
||||
var guide = guides[i];
|
||||
var next = guides[(i + 1) % guides.length];
|
||||
computeContacts(guide, next);
|
||||
}
|
||||
|
||||
// skip any guides that should not contact the Belt, because they're cannot touch the path
|
||||
var i = 0;
|
||||
while (guides.length > 2 && i < guides.length) {
|
||||
var guide = guides[i];
|
||||
var next = guides[(i + 1) % guides.length];
|
||||
var follow = guides[(i + 2) % guides.length];
|
||||
// is NEXT on the wrong side of the line from GUIDE to FOLLOW?
|
||||
var wrongside = comparePointWithLine(guide.from.x, guide.from.y, follow.to.x, follow.to.y, next.to.x, next.to.y) < 0;
|
||||
if (next.outside) wrongside = !wrongside;
|
||||
if (wrongside) {
|
||||
computeContacts(guide, follow);
|
||||
// get rid of NEXT
|
||||
if (i + 1 < guides.length) {
|
||||
guides.splice(i + 1, 1);
|
||||
} else {
|
||||
guides.splice(0, 1);
|
||||
}
|
||||
// now also need to check whether GUIDE has become on the wrong side!
|
||||
if (i > 0) i--;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// construct the Geometry for the belt Shape
|
||||
var geo = new go.Geometry();
|
||||
var fig = null;
|
||||
for (var i = 0; i < guides.length; i++) {
|
||||
var guide = guides[i];
|
||||
var next = guides[(i + 1) % guides.length];
|
||||
if (fig === null) {
|
||||
fig = new go.PathFigure(guide.from.x, guide.from.y, true);
|
||||
geo.add(fig);
|
||||
}
|
||||
fig.add(new go.PathSegment(go.PathSegment.Line, next.to.x, next.to.y));
|
||||
var startang = next.location.directionPoint(next.to);
|
||||
var endang = next.location.directionPoint(next.from);
|
||||
var sweep = (endang > startang) ? endang-startang : (360 - startang) + endang;
|
||||
if (next.outside) { // go counter-clockwise
|
||||
fig.add(new go.PathSegment(go.PathSegment.Arc, startang, sweep - 360, next.location.x, next.location.y, next.radius, next.radius));
|
||||
} else { // positive sweep angle
|
||||
fig.add(new go.PathSegment(go.PathSegment.Arc, startang, sweep, next.location.x, next.location.y, next.radius, next.radius));
|
||||
}
|
||||
}
|
||||
|
||||
// update the Belt's Shape.geometry
|
||||
if (belt !== null) {
|
||||
var pos = geo.normalize();
|
||||
belt.geometry = geo;
|
||||
// account for the thickness of the belt shape's stroke
|
||||
node.position = new go.Point(-pos.x - belt.strokeWidth / 2, -pos.y - belt.strokeWidth / 2);
|
||||
node.ensureBounds();
|
||||
}
|
||||
} // end updateBelt
|
||||
|
||||
function comparePointWithLine(a1x, a1y, a2x, a2y, p1x, p1y) {
|
||||
var x2 = a2x - a1x;
|
||||
var y2 = a2y - a1y;
|
||||
var px = p1x - a1x;
|
||||
var py = p1y - a1y;
|
||||
var ccw = px * y2 - py * x2;
|
||||
if (ccw === 0) {
|
||||
ccw = px * x2 + py * y2;
|
||||
if (ccw > 0) {
|
||||
px -= x2;
|
||||
py -= y2;
|
||||
ccw = px * x2 + py * y2;
|
||||
if (ccw < 0) ccw = 0;
|
||||
}
|
||||
}
|
||||
return (ccw < 0) ? -1 : ((ccw > 0) ? 1 : 0);
|
||||
}
|
||||
|
||||
function computeContacts(guideA, guideB) {
|
||||
var locA = guideA.location;
|
||||
var x1 = locA.x;
|
||||
var y1 = locA.y;
|
||||
var r1 = guideA.radius;
|
||||
var locB = guideB.location;
|
||||
var x2 = locB.x;
|
||||
var y2 = locB.y;
|
||||
var r2 = guideB.radius;
|
||||
|
||||
// this assumes that belts only go clockwise
|
||||
var g = Math.atan2(y2 - y1, x2 - x1);
|
||||
var d = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
|
||||
|
||||
var bb = ((guideA.outside === guideB.outside) ? (r2 - r1) : (r2 + r1)) / d;
|
||||
if (bb < -1) bb = -1; else if (bb > 1) bb = 1;
|
||||
var b = Math.asin(bb);
|
||||
|
||||
if (guideB.outside) {
|
||||
if (guideA.outside) { // both outside
|
||||
var a = Math.PI / 2 - b - g;
|
||||
var cosa = Math.cos(a);
|
||||
var sina = Math.sin(a);
|
||||
guideA.from = new go.Point(x1 - r1 * cosa, y1 + r1 * sina);
|
||||
guideB.to = new go.Point(x2 - r2 * cosa, y2 + r2 * sina);
|
||||
} else { // inside A, outside B
|
||||
var a = Math.PI / 2 - Math.abs(b) - g;
|
||||
var cosa = Math.cos(a);
|
||||
var sina = Math.sin(a);
|
||||
guideA.from = new go.Point(x1 + r1 * cosa, y1 - r1 * sina);
|
||||
guideB.to = new go.Point(x2 - r2 * cosa, y2 + r2 * sina);
|
||||
}
|
||||
} else {
|
||||
if (guideA.outside) { // outside A, inside B
|
||||
var a = Math.abs(b) - Math.PI / 2 - g;
|
||||
var cosa = Math.cos(a);
|
||||
var sina = Math.sin(a);
|
||||
guideA.from = new go.Point(x1 + r1 * cosa, y1 - r1 * sina);
|
||||
guideB.to = new go.Point(x2 - r2 * cosa, y2 + r2 * sina);
|
||||
} else { // both inside
|
||||
var a = Math.PI / 2 + b - g;
|
||||
var cosa = Math.cos(a);
|
||||
var sina = Math.sin(a);
|
||||
guideA.from = new go.Point(x1 + r1 * cosa, y1 - r1 * sina);
|
||||
guideB.to = new go.Point(x2 + r2 * cosa, y2 - r2 * sina);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show the diagram's model in JSON format that the user may edit
|
||||
function save() {
|
||||
document.getElementById("mySavedModel").value = myDiagram.model.toJson();
|
||||
myDiagram.isModified = false;
|
||||
}
|
||||
|
||||
var beltAnimation = null;
|
||||
function load() {
|
||||
myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
|
||||
|
||||
// Animate the flow in the pipes
|
||||
if (beltAnimation) beltAnimation.stop();
|
||||
var animation = new go.Animation();
|
||||
animation.easing = go.Animation.EaseLinear;
|
||||
myDiagram.nodes.each(function(node) {
|
||||
if (node.category !== "Belt") return;
|
||||
animation.add(node.findObject("BELT"), "strokeDashOffset", 36, 0)
|
||||
});
|
||||
// Run indefinitely
|
||||
animation.runCount = Infinity;
|
||||
animation.start();
|
||||
beltAnimation = animation;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<div id="sample">
|
||||
<div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>
|
||||
<button id="SaveButton" onclick="save()">Save</button>
|
||||
<button onclick="load()">Load</button>
|
||||
Diagram Model saved in JSON format:
|
||||
<textarea id="mySavedModel" style="width:100%;height:300px">
|
||||
{ "class": "go.GraphLinksModel",
|
||||
"nodeDataArray": [
|
||||
{"key":"P111", "category":"Roller", "xy":"450 610"},
|
||||
{"key":"P112", "category":"Roller", "xy":"400 660"},
|
||||
{"key":"P113", "category":"Roller", "xy":"350 725"},
|
||||
{"key":"P114", "category":"Roller", "xy":"305 800"},
|
||||
{"key":"P115", "category":"Roller", "xy":"280 705"},
|
||||
{"key":"P116", "category":"Roller", "xy":"200 720"},
|
||||
{"key":"P117", "category":"Roller", "xy":"200 620"},
|
||||
{"key":"D1", "category":"Drum", "xy":"300 540"},
|
||||
{"key":"D2", "category":"Drum", "xy":"300 622"},
|
||||
{"key":"B1", "category":"Belt", "color":"blue",
|
||||
"guides":[ {"k":"D2"},{"k":"P111"},{"k":"P112", "outside":true},{"k":"P113", "outside":true},{"k":"P114"},{"k":"P115", "outside":true},{"k":"P116"},{"k":"P117"} ]},
|
||||
{"key":"P211", "category":"Roller", "xy":"100 750"},
|
||||
{"key":"P212", "category":"Roller", "xy":"150 800"},
|
||||
{"key":"B2", "category":"Belt", "color":"green",
|
||||
"guides":[ {"k":"P211"},{"k":"P116"},{"k":"P212"} ]}
|
||||
],
|
||||
"linkDataArray": []}
|
||||
</textarea>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user