adjust to webgl2
This commit is contained in:
parent
284bb4bd1a
commit
f200110407
239
package-lock.json
generated
239
package-lock.json
generated
@ -10,10 +10,14 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"element-plus": "^2.5.6",
|
"element-plus": "^2.5.6",
|
||||||
|
"lodash.get": "^4.4.2",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
|
"onml": "^2.1.0",
|
||||||
"stream": "^0.0.2",
|
"stream": "^0.0.2",
|
||||||
"vue": "^3.2.13",
|
"vue": "^3.2.13",
|
||||||
"vue-i18n": "^9.9.1"
|
"vue-i18n": "^9.9.1",
|
||||||
|
"w3c-keyname": "^2.2.8",
|
||||||
|
"waveql": "^1.8.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.12.16",
|
"@babel/core": "^7.12.16",
|
||||||
@ -1820,6 +1824,62 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@codemirror/autocomplete": {
|
||||||
|
"version": "6.15.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@codemirror/autocomplete/-/autocomplete-6.15.0.tgz",
|
||||||
|
"integrity": "sha512-G2Zm0mXznxz97JhaaOdoEG2cVupn4JjPaS4AcNvZzhOsnnG9YVN68VzfoUw6dYTsIxT6a/cmoFEN47KAWhXaOg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.17.0",
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.0.0",
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/commands": {
|
||||||
|
"version": "6.3.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@codemirror/commands/-/commands-6.3.3.tgz",
|
||||||
|
"integrity": "sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.4.0",
|
||||||
|
"@codemirror/view": "^6.0.0",
|
||||||
|
"@lezer/common": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/language": {
|
||||||
|
"version": "6.10.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@codemirror/language/-/language-6.10.1.tgz",
|
||||||
|
"integrity": "sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.23.0",
|
||||||
|
"@lezer/common": "^1.1.0",
|
||||||
|
"@lezer/highlight": "^1.0.0",
|
||||||
|
"@lezer/lr": "^1.0.0",
|
||||||
|
"style-mod": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/state": {
|
||||||
|
"version": "6.4.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@codemirror/state/-/state-6.4.1.tgz",
|
||||||
|
"integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A=="
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/view": {
|
||||||
|
"version": "6.26.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.26.0.tgz",
|
||||||
|
"integrity": "sha512-nSSmzONpqsNzshPOxiKhK203R6BvABepugAe34QfQDbNDslyjkqBuKgrK5ZBvqNXpfxz5iLrlGTmEfhbQyH46A==",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.4.0",
|
||||||
|
"style-mod": "^4.1.0",
|
||||||
|
"w3c-keyname": "^2.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@ctrl/tinycolor": {
|
"node_modules/@ctrl/tinycolor": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
||||||
@ -2047,6 +2107,27 @@
|
|||||||
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
|
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@lezer/common": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@lezer/common/-/common-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ=="
|
||||||
|
},
|
||||||
|
"node_modules/@lezer/highlight": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@lezer/highlight/-/highlight-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@lezer/lr": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@lezer/lr/-/lr-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
|
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
|
||||||
"version": "5.1.1-v1",
|
"version": "5.1.1-v1",
|
||||||
"resolved": "https://registry.npmmirror.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
|
"resolved": "https://registry.npmmirror.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
|
||||||
@ -7410,6 +7491,11 @@
|
|||||||
"integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==",
|
"integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.get": {
|
||||||
|
"version": "4.4.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||||
|
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
|
||||||
|
},
|
||||||
"node_modules/lodash.kebabcase": {
|
"node_modules/lodash.kebabcase": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
|
||||||
@ -8227,6 +8313,14 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/onml": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/onml/-/onml-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-fvaSZRzprpwLFge/mcwE0CItfniNisVNamDdMK1FQUjh4ArQZ8ZWSkDaJbZc3XaANKZHq0xIa8NJpZ2HSe3oXA==",
|
||||||
|
"dependencies": {
|
||||||
|
"sax": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/open": {
|
"node_modules/open": {
|
||||||
"version": "8.4.2",
|
"version": "8.4.2",
|
||||||
"resolved": "https://registry.npmmirror.com/open/-/open-8.4.2.tgz",
|
"resolved": "https://registry.npmmirror.com/open/-/open-8.4.2.tgz",
|
||||||
@ -9593,6 +9687,11 @@
|
|||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/sax": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/sax/-/sax-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
|
||||||
|
},
|
||||||
"node_modules/schema-utils": {
|
"node_modules/schema-utils": {
|
||||||
"version": "2.7.1",
|
"version": "2.7.1",
|
||||||
"resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-2.7.1.tgz",
|
"resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-2.7.1.tgz",
|
||||||
@ -10166,6 +10265,11 @@
|
|||||||
"acorn": "^8.10.0"
|
"acorn": "^8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/style-mod": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/style-mod/-/style-mod-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="
|
||||||
|
},
|
||||||
"node_modules/stylehacks": {
|
"node_modules/stylehacks": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/stylehacks/-/stylehacks-5.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/stylehacks/-/stylehacks-5.1.1.tgz",
|
||||||
@ -11087,6 +11191,11 @@
|
|||||||
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
|
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/w3c-keyname": {
|
||||||
|
"version": "2.2.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||||
|
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
|
||||||
|
},
|
||||||
"node_modules/watchpack": {
|
"node_modules/watchpack": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz",
|
"resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz",
|
||||||
@ -11100,6 +11209,22 @@
|
|||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/waveql": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/waveql/-/waveql-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-TDC4rzwLAGm5qCXV2bBw0TLMlCZ7mNnYqQE/V428E2mAiU8NZrZH0aiTX91Nptfz5sSzn42dQwkJZKqbx2cZFQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/autocomplete": "^6.12.0",
|
||||||
|
"@codemirror/commands": "^6.3.3",
|
||||||
|
"@codemirror/language": "^6.10.0",
|
||||||
|
"@codemirror/state": "^6.4.0",
|
||||||
|
"@codemirror/view": "^6.23.0",
|
||||||
|
"@lezer/highlight": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/wbuf": {
|
"node_modules/wbuf": {
|
||||||
"version": "1.7.3",
|
"version": "1.7.3",
|
||||||
"resolved": "https://registry.npmmirror.com/wbuf/-/wbuf-1.7.3.tgz",
|
"resolved": "https://registry.npmmirror.com/wbuf/-/wbuf-1.7.3.tgz",
|
||||||
@ -12948,6 +13073,56 @@
|
|||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@codemirror/autocomplete": {
|
||||||
|
"version": "6.15.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@codemirror/autocomplete/-/autocomplete-6.15.0.tgz",
|
||||||
|
"integrity": "sha512-G2Zm0mXznxz97JhaaOdoEG2cVupn4JjPaS4AcNvZzhOsnnG9YVN68VzfoUw6dYTsIxT6a/cmoFEN47KAWhXaOg==",
|
||||||
|
"requires": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.17.0",
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@codemirror/commands": {
|
||||||
|
"version": "6.3.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@codemirror/commands/-/commands-6.3.3.tgz",
|
||||||
|
"integrity": "sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==",
|
||||||
|
"requires": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.4.0",
|
||||||
|
"@codemirror/view": "^6.0.0",
|
||||||
|
"@lezer/common": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@codemirror/language": {
|
||||||
|
"version": "6.10.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@codemirror/language/-/language-6.10.1.tgz",
|
||||||
|
"integrity": "sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==",
|
||||||
|
"requires": {
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.23.0",
|
||||||
|
"@lezer/common": "^1.1.0",
|
||||||
|
"@lezer/highlight": "^1.0.0",
|
||||||
|
"@lezer/lr": "^1.0.0",
|
||||||
|
"style-mod": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@codemirror/state": {
|
||||||
|
"version": "6.4.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@codemirror/state/-/state-6.4.1.tgz",
|
||||||
|
"integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A=="
|
||||||
|
},
|
||||||
|
"@codemirror/view": {
|
||||||
|
"version": "6.26.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.26.0.tgz",
|
||||||
|
"integrity": "sha512-nSSmzONpqsNzshPOxiKhK203R6BvABepugAe34QfQDbNDslyjkqBuKgrK5ZBvqNXpfxz5iLrlGTmEfhbQyH46A==",
|
||||||
|
"requires": {
|
||||||
|
"@codemirror/state": "^6.4.0",
|
||||||
|
"style-mod": "^4.1.0",
|
||||||
|
"w3c-keyname": "^2.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@ctrl/tinycolor": {
|
"@ctrl/tinycolor": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
||||||
@ -13136,6 +13311,27 @@
|
|||||||
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
|
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@lezer/common": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@lezer/common/-/common-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ=="
|
||||||
|
},
|
||||||
|
"@lezer/highlight": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@lezer/highlight/-/highlight-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==",
|
||||||
|
"requires": {
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@lezer/lr": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@lezer/lr/-/lr-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg==",
|
||||||
|
"requires": {
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@nicolo-ribaudo/eslint-scope-5-internals": {
|
"@nicolo-ribaudo/eslint-scope-5-internals": {
|
||||||
"version": "5.1.1-v1",
|
"version": "5.1.1-v1",
|
||||||
"resolved": "https://registry.npmmirror.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
|
"resolved": "https://registry.npmmirror.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
|
||||||
@ -17458,6 +17654,11 @@
|
|||||||
"integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==",
|
"integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"lodash.get": {
|
||||||
|
"version": "4.4.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||||
|
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
|
||||||
|
},
|
||||||
"lodash.kebabcase": {
|
"lodash.kebabcase": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
|
||||||
@ -18118,6 +18319,14 @@
|
|||||||
"mimic-fn": "^2.1.0"
|
"mimic-fn": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"onml": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/onml/-/onml-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-fvaSZRzprpwLFge/mcwE0CItfniNisVNamDdMK1FQUjh4ArQZ8ZWSkDaJbZc3XaANKZHq0xIa8NJpZ2HSe3oXA==",
|
||||||
|
"requires": {
|
||||||
|
"sax": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"open": {
|
"open": {
|
||||||
"version": "8.4.2",
|
"version": "8.4.2",
|
||||||
"resolved": "https://registry.npmmirror.com/open/-/open-8.4.2.tgz",
|
"resolved": "https://registry.npmmirror.com/open/-/open-8.4.2.tgz",
|
||||||
@ -19132,6 +19341,11 @@
|
|||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"sax": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/sax/-/sax-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
|
||||||
|
},
|
||||||
"schema-utils": {
|
"schema-utils": {
|
||||||
"version": "2.7.1",
|
"version": "2.7.1",
|
||||||
"resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-2.7.1.tgz",
|
"resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-2.7.1.tgz",
|
||||||
@ -19622,6 +19836,11 @@
|
|||||||
"acorn": "^8.10.0"
|
"acorn": "^8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"style-mod": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/style-mod/-/style-mod-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="
|
||||||
|
},
|
||||||
"stylehacks": {
|
"stylehacks": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/stylehacks/-/stylehacks-5.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/stylehacks/-/stylehacks-5.1.1.tgz",
|
||||||
@ -20335,6 +20554,11 @@
|
|||||||
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
|
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"w3c-keyname": {
|
||||||
|
"version": "2.2.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||||
|
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
|
||||||
|
},
|
||||||
"watchpack": {
|
"watchpack": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz",
|
"resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz",
|
||||||
@ -20345,6 +20569,19 @@
|
|||||||
"graceful-fs": "^4.1.2"
|
"graceful-fs": "^4.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"waveql": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/waveql/-/waveql-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-TDC4rzwLAGm5qCXV2bBw0TLMlCZ7mNnYqQE/V428E2mAiU8NZrZH0aiTX91Nptfz5sSzn42dQwkJZKqbx2cZFQ==",
|
||||||
|
"requires": {
|
||||||
|
"@codemirror/autocomplete": "^6.12.0",
|
||||||
|
"@codemirror/commands": "^6.3.3",
|
||||||
|
"@codemirror/language": "^6.10.0",
|
||||||
|
"@codemirror/state": "^6.4.0",
|
||||||
|
"@codemirror/view": "^6.23.0",
|
||||||
|
"@lezer/highlight": "^1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"wbuf": {
|
"wbuf": {
|
||||||
"version": "1.7.3",
|
"version": "1.7.3",
|
||||||
"resolved": "https://registry.npmmirror.com/wbuf/-/wbuf-1.7.3.tgz",
|
"resolved": "https://registry.npmmirror.com/wbuf/-/wbuf-1.7.3.tgz",
|
||||||
|
@ -13,7 +13,11 @@
|
|||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"stream": "^0.0.2",
|
"stream": "^0.0.2",
|
||||||
"vue": "^3.2.13",
|
"vue": "^3.2.13",
|
||||||
"vue-i18n": "^9.9.1"
|
"vue-i18n": "^9.9.1",
|
||||||
|
"waveql": "^1.8.0",
|
||||||
|
"lodash.get": "^4.4.2",
|
||||||
|
"onml": "^2.1.0",
|
||||||
|
"w3c-keyname": "^2.2.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.12.16",
|
"@babel/core": "^7.12.16",
|
||||||
|
111
public/vcd.css
111
public/vcd.css
@ -2,9 +2,12 @@
|
|||||||
--display-signal-info-height: 50px;
|
--display-signal-info-height: 50px;
|
||||||
--signal-default-color: #4CAF50;
|
--signal-default-color: #4CAF50;
|
||||||
--main-color: #CB81DA;
|
--main-color: #CB81DA;
|
||||||
|
--main-dark-color: #2D323B;
|
||||||
|
--main-light-color: var(--main-color);
|
||||||
--sidebar-width: 280px;
|
--sidebar-width: 280px;
|
||||||
--right-nav-width: 60px;
|
--right-nav-width: 60px;
|
||||||
--time-scale-height: 50px;
|
--time-scale-height: 50px;
|
||||||
|
--render-scale-x: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
@ -87,4 +90,112 @@ body::-webkit-scrollbar {
|
|||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--main-color);
|
color: var(--main-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-container {
|
||||||
|
--right-panel-width: 0px;
|
||||||
|
width: calc(100% - var(--right-panel-width));
|
||||||
|
transition: width .3s ease-out;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-grid {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-view {
|
||||||
|
position: absolute;
|
||||||
|
top: 24px;
|
||||||
|
bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-values {
|
||||||
|
position: absolute;
|
||||||
|
top: 24px;
|
||||||
|
bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-waveql {
|
||||||
|
position: absolute;
|
||||||
|
top: 24px;
|
||||||
|
bottom: 24px;
|
||||||
|
width: 100%;
|
||||||
|
transition: width .3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-cursor {
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-values text {
|
||||||
|
font-size: 14px;
|
||||||
|
text-anchor: middle;
|
||||||
|
fill: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
line.wd-cursor-line {
|
||||||
|
stroke-dasharray: 12 4;
|
||||||
|
stroke: var(--main-color);
|
||||||
|
stroke-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
line.wd-grid-time {
|
||||||
|
stroke: #333;
|
||||||
|
stroke-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
line.gap {
|
||||||
|
stroke: #fff;
|
||||||
|
stroke-dasharray: 4 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
text.wd-grid-time {
|
||||||
|
text-anchor: middle;
|
||||||
|
fill: var(--sidebar-item-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
text.wd-cursor-time {
|
||||||
|
font-size: 20px;
|
||||||
|
fill: var(--sidebar);
|
||||||
|
text-anchor: middle;
|
||||||
|
z-index: 55;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.wd-cursor-time {
|
||||||
|
fill: var(--main-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.wd-progress {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
text.xred {
|
||||||
|
fill: hsl(0, 100%, 50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
text.zxviolet {
|
||||||
|
fill: hsl(287, 100%, 67%);
|
||||||
|
}
|
||||||
|
|
||||||
|
text.pc {
|
||||||
|
text-anchor: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
tspan.pc-addr {
|
||||||
|
fill: hsl(202 100% 71%);
|
||||||
|
}
|
||||||
|
|
||||||
|
tspan.pc-opcode {
|
||||||
|
|
||||||
}
|
}
|
45
src/App.vue
45
src/App.vue
@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { onMounted, reactive } from 'vue';
|
import { onMounted, reactive } from 'vue';
|
||||||
import { getVcdStream, readVcdFile } from '@/hook/utils';
|
import { getVcdStream, readVcdFile, numberOrString, gcd, normaliseUsingGCD, parseTimescale } from '@/hook/utils';
|
||||||
import { emitter, globalLookup, globalSetting, signalValues } from '@/hook/global';
|
import { emitter, globalLookup, globalSetting, signalValues } from '@/hook/global';
|
||||||
|
import { makeWaveView } from '@/hook/render';
|
||||||
|
|
||||||
import Sidebar from '@/components/sidebar.vue';
|
import Sidebar from '@/components/sidebar.vue';
|
||||||
import RightNav from '@/components/right-nav.vue';
|
import RightNav from '@/components/right-nav.vue';
|
||||||
@ -56,20 +57,36 @@ export default {
|
|||||||
document.body.style.setProperty('--el-color-info-light-8', 'var(--vscode-focusBorder)');
|
document.body.style.setProperty('--el-color-info-light-8', 'var(--vscode-focusBorder)');
|
||||||
document.body.style.setProperty('--el-bg-color-overlay', 'transplant');
|
document.body.style.setProperty('--el-bg-color-overlay', 'transplant');
|
||||||
|
|
||||||
|
|
||||||
// signal height
|
// signal height
|
||||||
document.body.style.setProperty('--display-signal-info-height', globalSetting.displaySignalHeight + 'px');
|
document.body.style.setProperty('--display-signal-info-height', globalSetting.displaySignalHeight + 'px');
|
||||||
|
|
||||||
|
|
||||||
const uint8array = await readVcdFile();
|
const uint8array = await readVcdFile();
|
||||||
const vcdstream = await getVcdStream();
|
const vcdstream = await getVcdStream();
|
||||||
|
|
||||||
|
let tgcd;
|
||||||
|
// 使用 vcdstream 的 any 回调获取波形数据,并按照正确的格式进行解码和存储
|
||||||
|
// 这段处理来自 https://github.com/wavedrom/vcd 的 vcd-pipe-deso.js 的 58 行
|
||||||
|
// 请严格对准转换规则
|
||||||
vcdstream.change.any((id, time, cmd, value, mask) => {
|
vcdstream.change.any((id, time, cmd, value, mask) => {
|
||||||
if (signalValues[id] === undefined) {
|
const time53 = Number(time);
|
||||||
signalValues[id] = [];
|
tgcd = gcd(tgcd, time53);
|
||||||
}
|
signalValues[id] = signalValues[id] || { kind: '', wave: [] };
|
||||||
|
|
||||||
|
if (cmd >= 14 && cmd <= 28) {
|
||||||
|
signalValues[id].kind = 'bit';
|
||||||
|
signalValues[id].wave.push([time53, cmd - 14]);
|
||||||
|
} else {
|
||||||
|
signalValues[id].kind = 'vec';
|
||||||
|
const point = [time53, numberOrString(value)];
|
||||||
|
if (mask !== 0n) {
|
||||||
|
point.push(numberOrString(mask));
|
||||||
|
}
|
||||||
|
signalValues[id].wave.push(point);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
vcdstream.on('$enddefinitions', () => {
|
||||||
|
|
||||||
signalValues[id].push({time, cmd, value, mask});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const maxChunkLength = 1 << 17;
|
const maxChunkLength = 1 << 17;
|
||||||
@ -81,14 +98,20 @@ export default {
|
|||||||
for (const topModule of vcdstream.info.wires.body) {
|
for (const topModule of vcdstream.info.wires.body) {
|
||||||
VcdInfo.topModules.push(topModule);
|
VcdInfo.topModules.push(topModule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
globalLookup.status = vcdstream.info.status;
|
globalLookup.status = vcdstream.info.status;
|
||||||
globalLookup.version = vcdstream.info.version;
|
globalLookup.version = vcdstream.info.version;
|
||||||
globalLookup.timescale = vcdstream.info.timescale;
|
globalLookup.timescale = parseTimescale(vcdstream.info.timescale);
|
||||||
globalLookup.date = vcdstream.info.date;
|
globalLookup.date = vcdstream.info.date;
|
||||||
globalLookup.t0 = vcdstream.info.t0;
|
globalLookup.t0 = vcdstream.info.t0 || 0;
|
||||||
|
|
||||||
|
globalLookup.tgcd = tgcd;
|
||||||
|
globalLookup.time = Number(vcdstream.getTime());
|
||||||
|
globalLookup.chango = signalValues;
|
||||||
|
normaliseUsingGCD(globalLookup, signalValues);
|
||||||
|
|
||||||
|
makeWaveView();
|
||||||
|
|
||||||
|
console.log('duration time', globalLookup.time);
|
||||||
emitter.emit('meta-ready', null);
|
emitter.emit('meta-ready', null);
|
||||||
|
|
||||||
// 这一步时,已经加载完成
|
// 这一步时,已经加载完成
|
||||||
|
@ -1,28 +1,30 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vertical-cursor-wrapper"
|
<div>
|
||||||
@click="makeCursor"
|
<div class="vertical-cursor-wrapper"
|
||||||
:style="`left: ${currentX}px`">
|
@click="makeCursor"
|
||||||
<div class="current-display-cursor-up">
|
:style="`left: ${currentX}px`">
|
||||||
<div class="current-time-value">{{ currentX }} px</div>
|
<div class="current-display-cursor-up">
|
||||||
<div class="cursor-down-arrow"></div>
|
<div class="current-time-value">{{ currentX }} px</div>
|
||||||
|
<div class="cursor-down-arrow"></div>
|
||||||
|
</div>
|
||||||
|
<div class="vertical-line"></div>
|
||||||
|
<div class="current-display-cursor-down">
|
||||||
|
<div class="current-time-value">{{ currentX }} px</div>
|
||||||
|
<div class="cursor-up-arrow"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="vertical-line"></div>
|
|
||||||
<div class="current-display-cursor-down">
|
|
||||||
<div class="current-time-value">{{ currentX }} px</div>
|
|
||||||
<div class="cursor-up-arrow"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-show="showFixedOne"
|
<div v-show="showFixedOne"
|
||||||
class="vertical-cursor-wrapper"
|
class="vertical-cursor-wrapper"
|
||||||
@click="makeCursor"
|
@click="makeCursor"
|
||||||
:style="`left: ${fixedLeft}px`">
|
:style="`left: ${fixedLeft}px`">
|
||||||
<div class="fix-current-display-cursor-up">
|
<div class="fix-current-display-cursor-up">
|
||||||
{{ globalLookup.view.currentX }} px
|
{{ globalLookup.view.currentX }} px
|
||||||
</div>
|
</div>
|
||||||
<div class="fix-vertical-line"></div>
|
<div class="fix-vertical-line"></div>
|
||||||
<div class="fix-current-display-cursor-down">
|
<div class="fix-current-display-cursor-down">
|
||||||
{{ globalLookup.view.currentX }} px
|
{{ globalLookup.view.currentX }} px
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<VerticalCursor></VerticalCursor>
|
<!-- <VerticalCursor></VerticalCursor> -->
|
||||||
<TimeScale></TimeScale>
|
<!-- <TimeScale></TimeScale> -->
|
||||||
|
<div
|
||||||
<div class="vcd-render-wrapper" >
|
class="vcd-render-wrapper"
|
||||||
|
>
|
||||||
<div style="height: var(--time-scale-height);"></div>
|
<div style="height: var(--time-scale-height);"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -18,14 +19,15 @@ import TimeScale from '@/components/render/time-scale.vue';
|
|||||||
export default {
|
export default {
|
||||||
name: 'main-render',
|
name: 'main-render',
|
||||||
components: {
|
components: {
|
||||||
VerticalCursor,
|
// VerticalCursor,
|
||||||
TimeScale
|
// TimeScale
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const cursorX = ref(0);
|
const cursorX = ref(0);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cursorX
|
cursorX,
|
||||||
|
globalLookup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,7 +40,7 @@ export default {
|
|||||||
width: 98vw;
|
width: 98vw;
|
||||||
cursor: crosshair;
|
cursor: crosshair;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
transition: .3s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.render-canvas {
|
.render-canvas {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
import { onMounted, reactive } from 'vue';
|
import { onMounted, reactive } from 'vue';
|
||||||
import { globalLookup, emitter } from '@/hook/global';
|
import { globalLookup, emitter } from '@/hook/global';
|
||||||
import { handleTimeScale } from '@/hook/utils';
|
import { handleTimeScale } from '@/hook/utils';
|
||||||
|
import { wheelScale } from '@/hook/wheel';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'time-scale',
|
name: 'time-scale',
|
||||||
@ -42,30 +43,29 @@ export default {
|
|||||||
|
|
||||||
// 此时有关波形的元信息已经加载完毕
|
// 此时有关波形的元信息已经加载完毕
|
||||||
emitter.on('meta-ready', () => {
|
emitter.on('meta-ready', () => {
|
||||||
const { scale, unit } = handleTimeScale(globalLookup.timescale);
|
// const { scale, unit } = handleTimeScale(globalLookup.timescale);
|
||||||
timeScaleManage.scale = scale;
|
// timeScaleManage.scale = scale;
|
||||||
timeScaleManage.unit = unit;
|
// timeScaleManage.unit = unit;
|
||||||
|
|
||||||
console.log(timeScaleManage.unit);
|
// console.log(timeScaleManage.unit);
|
||||||
|
|
||||||
const viewInfo = globalLookup.view;
|
// const viewInfo = globalLookup.view;
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('wheel', event => {
|
// document.addEventListener('wheel', event => {
|
||||||
if ((event.wheelDelta && event.ctrlKey) || event.detail) {
|
// if ((event.wheelDelta && event.ctrlKey) || event.detail) {
|
||||||
event.preventDefault();
|
// event.preventDefault();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (event.ctrlKey) {
|
// if (event.ctrlKey) {
|
||||||
// console.log(event.wheelDelta);
|
// // console.log(event.wheelDelta);
|
||||||
console.log('deltaX', event.deltaX);
|
// wheelScale(event);
|
||||||
console.log('deltaY', event.deltaY);
|
// } else if (event.shiftKey) {
|
||||||
} else if (event.shiftKey) {
|
// // console.log(event.wheelDelta);
|
||||||
// console.log(event.wheelDelta);
|
// console.log('deltaX', event.deltaX);
|
||||||
console.log('deltaX', event.deltaX);
|
// console.log('deltaY', event.deltaY);
|
||||||
console.log('deltaY', event.deltaY);
|
// }
|
||||||
}
|
// }, { capture: false, passive: false });
|
||||||
}, { capture: false, passive: false });
|
|
||||||
|
|
||||||
|
|
||||||
const currentX = 300;
|
const currentX = 300;
|
||||||
|
@ -62,9 +62,9 @@ export default {
|
|||||||
.add-signal-button {
|
.add-signal-button {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
padding: 10px 25px;
|
padding: 10px 25px;
|
||||||
background-color: var(--color-deepPurple);
|
background-color: var(--main-color);
|
||||||
border-radius: 0 0 .8em .8em;
|
border-radius: 0 0 .8em .8em;
|
||||||
color: var(--sidebar-item-text);
|
color: var(--sidebar);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
|
@ -7,15 +7,17 @@
|
|||||||
v-model="searchManage.content"
|
v-model="searchManage.content"
|
||||||
input-style="font-size: 16px;"
|
input-style="font-size: 16px;"
|
||||||
@input="safeSearch"
|
@input="safeSearch"
|
||||||
|
@focus="searchManage.displayResult = true"
|
||||||
|
@blur="searchManage.displayResult = false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="search-result-wrapper" v-if="searchManage.content.trim().length > 0">
|
<div class="search-result-wrapper" v-if="searchManage.displayResult">
|
||||||
<div class="search-result">
|
<div class="search-result">
|
||||||
<div v-if="searchManage.searchResult.length > 0">
|
<div v-if="searchManage.searchResult.length > 0">
|
||||||
<div v-for="(searchResult, index) in searchManage.searchResult"
|
<div v-for="(searchResult, index) in searchManage.searchResult"
|
||||||
:key="index"
|
:key="index"
|
||||||
:class="globalLookup.currentWires.has(searchResult.module) ? 'vcd-treeview-selected' : ''"
|
:class="globalLookup.currentWires.has(searchResult.module) ? 'vcd-treeview-selected' : ''"
|
||||||
@click="clickItem(searchResult.module)">
|
@click="toggleRender(searchResult.module)">
|
||||||
<div v-html="searchResult.htmlString" class="search-result-item"></div>
|
<div v-html="searchResult.htmlString" class="search-result-item"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -34,6 +36,7 @@ import { reactive } from 'vue';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { globalSetting, globalLookup, emitter } from '@/hook/global';
|
import { globalSetting, globalLookup, emitter } from '@/hook/global';
|
||||||
import { debounceWrapper, makeSearchResultItem } from '@/hook/utils';
|
import { debounceWrapper, makeSearchResultItem } from '@/hook/utils';
|
||||||
|
import { toggleRender } from '@/hook/render';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'tree-view-search',
|
name: 'tree-view-search',
|
||||||
@ -42,15 +45,20 @@ export default {
|
|||||||
|
|
||||||
const searchManage = reactive({
|
const searchManage = reactive({
|
||||||
content: '',
|
content: '',
|
||||||
|
displayResult: false,
|
||||||
searchResult: []
|
searchResult: []
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function search() {
|
function search() {
|
||||||
const searchString = searchManage.content.trim();
|
const searchString = searchManage.content.trim();
|
||||||
if (searchString.length === 0) {
|
if (searchString.length === 0) {
|
||||||
|
searchManage.displayResult = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
searchManage.displayResult = true;
|
||||||
searchManage.searchResult = [];
|
searchManage.searchResult = [];
|
||||||
|
|
||||||
const stacks = [ { name: '', body: globalLookup.topModules } ];
|
const stacks = [ { name: '', body: globalLookup.topModules } ];
|
||||||
@ -75,18 +83,6 @@ export default {
|
|||||||
searchManage.searchResult.push(searchResultItem);
|
searchManage.searchResult.push(searchResultItem);
|
||||||
});
|
});
|
||||||
|
|
||||||
function clickItem(signal) {
|
|
||||||
console.log(signal);
|
|
||||||
if (!signal.link) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (globalLookup.currentWires.has(signal)) {
|
|
||||||
globalLookup.currentWires.delete(signal);
|
|
||||||
} else {
|
|
||||||
globalLookup.currentWires.add(signal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const safeSearch = debounceWrapper(search, 500);
|
const safeSearch = debounceWrapper(search, 500);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -95,7 +91,7 @@ export default {
|
|||||||
globalLookup,
|
globalLookup,
|
||||||
debounceWrapper,
|
debounceWrapper,
|
||||||
t,
|
t,
|
||||||
clickItem
|
toggleRender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<div class="vcd-signal-signals-display">
|
<div class="vcd-signal-signals-display">
|
||||||
<div v-for="(signal, index) in signals.content" :key="index"
|
<div v-for="(signal, index) in signals.content" :key="index"
|
||||||
@click="clickItem(signal)"
|
@click="toggleRender(signal)"
|
||||||
class="vcd-signal-signal-item"
|
class="vcd-signal-signal-item"
|
||||||
:class="globalLookup.currentWires.has(signal) ? 'vcd-treeview-selected' : ''">
|
:class="globalLookup.currentWires.has(signal) ? 'vcd-treeview-selected' : ''">
|
||||||
<div><span :class="`iconfont ${makeIconClass(signal)}`"></span> {{ signal.name }}</div>
|
<div><span :class="`iconfont ${makeIconClass(signal)}`"></span> {{ signal.name }}</div>
|
||||||
@ -24,7 +24,7 @@ import { useI18n } from 'vue-i18n';
|
|||||||
|
|
||||||
import { emitter, globalLookup } from '@/hook/global';
|
import { emitter, globalLookup } from '@/hook/global';
|
||||||
import { makeIconClass } from '@/hook/utils';
|
import { makeIconClass } from '@/hook/utils';
|
||||||
import { makeWaveCanvas, removeWaveCanvas } from '@/hook/render';
|
import { toggleRender } from '@/hook/render';
|
||||||
|
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export default {
|
export default {
|
||||||
@ -47,19 +47,9 @@ export default {
|
|||||||
return signal.size === 1 ? '' : `${signal.size - 1}:0`;
|
return signal.size === 1 ? '' : `${signal.size - 1}:0`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clickItem(signal) {
|
|
||||||
if (globalLookup.currentWires.has(signal)) {
|
|
||||||
globalLookup.currentWires.delete(signal);
|
|
||||||
removeWaveCanvas(signal);
|
|
||||||
} else {
|
|
||||||
globalLookup.currentWires.add(signal);
|
|
||||||
makeWaveCanvas(signal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
signals,
|
signals,
|
||||||
clickItem,
|
toggleRender,
|
||||||
globalLookup,
|
globalLookup,
|
||||||
makeSignalCaption,
|
makeSignalCaption,
|
||||||
t,
|
t,
|
||||||
|
48
src/hook/canvas.js
Normal file
48
src/hook/canvas.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
|
||||||
|
class LineDrawer {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {CanvasRenderingContext2D} ctx
|
||||||
|
*/
|
||||||
|
constructor(ctx) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.lastColor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
beginPath() {
|
||||||
|
this.ctx.beginPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {number} x
|
||||||
|
* @param {number} y
|
||||||
|
*/
|
||||||
|
moveTo(x, y) {
|
||||||
|
this.ctx.moveTo(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {number} x
|
||||||
|
* @param {number} y
|
||||||
|
* @param {string} color
|
||||||
|
*/
|
||||||
|
lineTo(x, y, color) {
|
||||||
|
const ctx = this.ctx;
|
||||||
|
ctx.lineTo(x, y);
|
||||||
|
|
||||||
|
if (this.lastColor === null) {
|
||||||
|
ctx.strokeStyle = color;
|
||||||
|
this.lastColor = color;
|
||||||
|
} else if (this.lastColor !== color) {
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.strokeStyle = color;
|
||||||
|
this.lastColor = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
LineDrawer
|
||||||
|
}
|
@ -22,16 +22,34 @@ const globalLookup = reactive({
|
|||||||
timescale: '',
|
timescale: '',
|
||||||
// 初始时间,一般都是 0
|
// 初始时间,一般都是 0
|
||||||
t0: 0,
|
t0: 0,
|
||||||
|
// 最长持续时间
|
||||||
|
maxTime: 0n,
|
||||||
|
time: 0,
|
||||||
|
|
||||||
// 当前视图的左上角的坐标
|
// 优化视图的最大公约数
|
||||||
view : {
|
tgcd: null,
|
||||||
x: 0,
|
// 其实就是 signalValues
|
||||||
y: 0,
|
chango: {},
|
||||||
gridGap: 300,
|
// 初始化时会被定义
|
||||||
currentBaseUnit: 100,
|
render: () => {},
|
||||||
currentX: 0,
|
|
||||||
currentScale: 1
|
hasHistory: false,
|
||||||
},
|
isRO: false,
|
||||||
|
|
||||||
|
// 当前展示的波形
|
||||||
|
view: [],
|
||||||
|
|
||||||
|
xScale: 1,
|
||||||
|
|
||||||
|
// // 当前视图的左上角的坐标
|
||||||
|
// view : {
|
||||||
|
// x: 0,
|
||||||
|
// y: 0,
|
||||||
|
// gridGap: 300,
|
||||||
|
// currentBaseUnit: 100,
|
||||||
|
// currentX: 0,
|
||||||
|
// currentScaleX: 1
|
||||||
|
// },
|
||||||
|
|
||||||
initcurrentModule(module) {
|
initcurrentModule(module) {
|
||||||
if (this.currentModule === undefined && module) {
|
if (this.currentModule === undefined && module) {
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import { globalLookup, globalSetting, signalValues } from "./global";
|
import { globalLookup, globalSetting, signalValues } from "./global";
|
||||||
|
import { LineDrawer } from './canvas';
|
||||||
|
import { domContainer, pluginRenderTimeGrid, pluginRenderValues, mountTree,
|
||||||
|
genOnWheel, genKeyHandler, keyBindo } from './wave-view';
|
||||||
|
|
||||||
|
import { createCodeMirrorState, mountCodeMirror6 } from 'waveql';
|
||||||
|
|
||||||
let mainRenderEl = null;
|
let mainRenderEl = null;
|
||||||
const canvasMap = {};
|
const canvasMap = new Map();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -59,7 +64,7 @@ function makeWaveCanvas(signal) {
|
|||||||
canvas.height = globalSetting.displaySignalHeight;
|
canvas.height = globalSetting.displaySignalHeight;
|
||||||
|
|
||||||
mainRender.appendChild(canvas);
|
mainRender.appendChild(canvas);
|
||||||
canvasMap[signal] = canvas;
|
canvasMap.set(signal, canvas);
|
||||||
|
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
const datas = signalValues[signal.link];
|
const datas = signalValues[signal.link];
|
||||||
@ -71,6 +76,101 @@ function makeWaveCanvas(signal) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{
|
||||||
|
* kind: 'var' | 'scope',
|
||||||
|
* type: 'wire' | 'reg' | 'module',
|
||||||
|
* name: string,
|
||||||
|
* size: number,
|
||||||
|
* link: string
|
||||||
|
* }} signal
|
||||||
|
*/
|
||||||
|
function makeWaveSvg(signal) {
|
||||||
|
const mainRender = getMainRenderEl();
|
||||||
|
const height = globalSetting.displaySignalHeight;
|
||||||
|
const width = document.body.clientWidth;
|
||||||
|
const draw = SVG().addTo(mainRender).size(width, height);
|
||||||
|
const datas = signalValues[signal.link];
|
||||||
|
|
||||||
|
if (signal.size === 1) {
|
||||||
|
drawSimpleSignalSvg(draw, datas);
|
||||||
|
} else {
|
||||||
|
// adwa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Svg} ctx
|
||||||
|
* @param {Array<{
|
||||||
|
* time: BigInt,
|
||||||
|
* cmd: number,
|
||||||
|
* value?: BigInt,
|
||||||
|
* mask?: BigInt
|
||||||
|
* }>} signals
|
||||||
|
*/
|
||||||
|
function drawSimpleSignalSvg(ctx, signals) {
|
||||||
|
let lastData = null;
|
||||||
|
let lastX = 300;
|
||||||
|
let lastColor = '';
|
||||||
|
|
||||||
|
// ctx.lineWidth = 3;
|
||||||
|
// ctx.lineJoin = 'round';
|
||||||
|
|
||||||
|
// const drawer = new LineDrawer(ctx);
|
||||||
|
// drawer.beginPath();
|
||||||
|
for (const data of signals) {
|
||||||
|
if (lastData === null) {
|
||||||
|
lastData = data;
|
||||||
|
lastX = 300;
|
||||||
|
lastColor = getDataRenderColor(data);
|
||||||
|
let lastY = Math.max((15 - data.cmd) * 30, 0) + 10;
|
||||||
|
// drawer.moveTo(last_x, last_y);
|
||||||
|
ctx.move(lastX, lastY);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 高阻态
|
||||||
|
const start = lastData.time;
|
||||||
|
const end = data.time;
|
||||||
|
console.log(lastData, isBlocked(lastData));
|
||||||
|
let lastY = Math.max((15 - lastData.cmd) * 30, 0) + 10;
|
||||||
|
|
||||||
|
const duration = parseInt(end - start);
|
||||||
|
const currentX = lastX + 100;
|
||||||
|
const currentColor = getDataRenderColor(data);
|
||||||
|
console.log(currentX, lastY, duration);
|
||||||
|
|
||||||
|
const line = ctx.line(lastX, lastY, currentX, lastY);
|
||||||
|
|
||||||
|
if (currentColor !== lastColor) {
|
||||||
|
ctx.stroke({ color: lastColor, linecap: 'round', width: 3 });
|
||||||
|
}
|
||||||
|
// drawer.lineTo(current_x, last_y, color);
|
||||||
|
|
||||||
|
if (lastData.cmd !== data.cmd) {
|
||||||
|
let currentY = Math.max((15 - data.cmd) * 30, 0) + 10;
|
||||||
|
const color = getDataRenderColor(data);
|
||||||
|
ctx.line(currentX, lastY, currentX, currentY);
|
||||||
|
// drawer.lineTo(current_x, current_y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastData = data;
|
||||||
|
lastX = currentX;
|
||||||
|
lastColor = currentColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 last_data 的时间不足最长时间,就用最后一个时刻的去补足
|
||||||
|
ctx.stroke({ color: lastColor, linecap: 'round', width: 3 });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getDataRenderColor(data) {
|
||||||
|
return isBlocked(data) ? 'rgb(224,108,117)' : 'rgb(10, 200, 10)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {{
|
* @param {{
|
||||||
* kind: 'var' | 'scope',
|
* kind: 'var' | 'scope',
|
||||||
@ -81,7 +181,7 @@ function makeWaveCanvas(signal) {
|
|||||||
* }} signal
|
* }} signal
|
||||||
*/
|
*/
|
||||||
function removeWaveCanvas(signal) {
|
function removeWaveCanvas(signal) {
|
||||||
const canvas = canvasMap[signal];
|
const canvas = canvasMap.get(signal);
|
||||||
if (canvas instanceof HTMLCanvasElement) {
|
if (canvas instanceof HTMLCanvasElement) {
|
||||||
canvas.parentNode.removeChild(canvas);
|
canvas.parentNode.removeChild(canvas);
|
||||||
}
|
}
|
||||||
@ -101,46 +201,133 @@ function removeWaveCanvas(signal) {
|
|||||||
function drawSimpleSignal(ctx, signals) {
|
function drawSimpleSignal(ctx, signals) {
|
||||||
let last_data = null;
|
let last_data = null;
|
||||||
let last_x = 300;
|
let last_x = 300;
|
||||||
|
|
||||||
ctx.lineWidth = 3;
|
ctx.lineWidth = 3;
|
||||||
ctx.lineJoin = 'round';
|
ctx.lineJoin = 'round';
|
||||||
|
const drawer = new LineDrawer(ctx);
|
||||||
|
|
||||||
ctx.beginPath();
|
drawer.beginPath();
|
||||||
for (const data of signals) {
|
for (const data of signals) {
|
||||||
console.log(data);
|
|
||||||
if (last_data === null) {
|
if (last_data === null) {
|
||||||
last_data = data;
|
last_data = data;
|
||||||
last_x = 300;
|
last_x = 300;
|
||||||
let last_y = Math.max((15 - last_data.cmd) * 30, 0) + 10;
|
let last_y = Math.max((15 - last_data.cmd) * 30, 0) + 10;
|
||||||
ctx.moveTo(last_x, last_y);
|
drawer.moveTo(last_x, last_y);
|
||||||
} else {
|
} else {
|
||||||
// 高阻态
|
// 高阻态
|
||||||
const start = last_data.time;
|
const start = last_data.time;
|
||||||
const end = data.time;
|
const end = data.time;
|
||||||
ctx.strokeStyle = isBlocked(last_data) ? 'rgb(224,108,117)' : 'rgb(10, 200, 10)';
|
console.log(last_data, isBlocked(last_data));
|
||||||
|
|
||||||
let last_y = Math.max((15 - last_data.cmd) * 30, 0) + 10;
|
let last_y = Math.max((15 - last_data.cmd) * 30, 0) + 10;
|
||||||
|
|
||||||
const duration = parseInt(end - start);
|
const duration = parseInt(end - start);
|
||||||
const current_x = last_x + 100;
|
const current_x = last_x + 100;
|
||||||
|
|
||||||
console.log(current_x, last_y, duration);
|
console.log(current_x, last_y, duration);
|
||||||
ctx.lineTo(current_x, last_y);
|
|
||||||
|
const color = getDataRenderColor(last_data);
|
||||||
|
drawer.lineTo(current_x, last_y, color);
|
||||||
|
|
||||||
if (last_data.cmd !== data.cmd) {
|
if (last_data.cmd !== data.cmd) {
|
||||||
ctx.strokeStyle = isBlocked(data) ? 'rgb(224,108,117)' : 'rgb(10, 200, 10)';
|
|
||||||
let current_y = Math.max((15 - data.cmd) * 30, 0) + 10;
|
let current_y = Math.max((15 - data.cmd) * 30, 0) + 10;
|
||||||
ctx.lineTo(current_x, current_y);
|
const color = getDataRenderColor(data);
|
||||||
|
drawer.lineTo(current_x, current_y, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
last_data = data;
|
last_data = data;
|
||||||
last_x = current_x;
|
last_x = current_x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果 last_data 的时间不足最长时间,就用最后一个时刻的去补足
|
||||||
|
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pluginLocalStore(desc, pstate /* , els */) {
|
||||||
|
const pstateJsonString = JSON.stringify({
|
||||||
|
// yOffset: pstate.yOffset,
|
||||||
|
xOffset: pstate.xOffset,
|
||||||
|
xScale: pstate.xScale
|
||||||
|
});
|
||||||
|
localStorage.setItem('dide', pstateJsonString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} parentElement
|
||||||
|
*/
|
||||||
|
function makeWaveView(parentElement) {
|
||||||
|
if (!parentElement) {
|
||||||
|
parentElement = getMainRenderEl();
|
||||||
|
}
|
||||||
|
const container = domContainer({
|
||||||
|
elemento: mountTree.defaultElemento,
|
||||||
|
layers: mountTree.defaultLayers,
|
||||||
|
renderPlugins: [
|
||||||
|
pluginRenderTimeGrid,
|
||||||
|
pluginRenderValues,
|
||||||
|
pluginLocalStore
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
parentElement.appendChild(container.pstate.container);
|
||||||
|
container.start(globalLookup);
|
||||||
|
|
||||||
|
globalLookup.hasHistory = true;
|
||||||
|
globalLookup.isRO = true;
|
||||||
|
globalLookup.updater = ( /* str */ ) => {
|
||||||
|
console.log('updater');
|
||||||
|
};
|
||||||
|
|
||||||
|
const cmState = createCodeMirrorState(globalLookup, container.pstate);
|
||||||
|
|
||||||
|
const cm = mountCodeMirror6(
|
||||||
|
cmState,
|
||||||
|
container.elo.waveqlPanel,
|
||||||
|
globalLookup,
|
||||||
|
container.pstate
|
||||||
|
);
|
||||||
|
|
||||||
|
cm.view.dispatch({changes: {from: 0, insert: ' '}});
|
||||||
|
cm.view.dispatch({changes: {from: 0, to: 1, insert: ''}});
|
||||||
|
|
||||||
|
container.elo.container.addEventListener('keydown', genKeyHandler.genKeyHandler(parentElement, container.pstate, globalLookup, cm, keyBindo));
|
||||||
|
container.elo.container.addEventListener('wheel', genOnWheel(parentElement, container.pstate, globalLookup, cm, keyBindo));
|
||||||
|
// console.log(cm);
|
||||||
|
cm.view.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{
|
||||||
|
* kind: 'var' | 'scope',
|
||||||
|
* type: 'wire' | 'reg' | 'module',
|
||||||
|
* name: string,
|
||||||
|
* size: number,
|
||||||
|
* link: string
|
||||||
|
* }} signal
|
||||||
|
*/
|
||||||
|
function toggleRender(signal) {
|
||||||
|
if (globalLookup.currentWires.has(signal)) {
|
||||||
|
globalLookup.currentWires.delete(signal);
|
||||||
|
// removeWaveCanvas(signal);
|
||||||
|
globalLookup.render();
|
||||||
|
} else {
|
||||||
|
// makeWaveSvg(signal);
|
||||||
|
const lane = { ref: signal.link };
|
||||||
|
|
||||||
|
globalLookup.currentWires.add(signal);
|
||||||
|
globalLookup.view.push(lane);
|
||||||
|
globalLookup.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getMainRenderEl,
|
getMainRenderEl,
|
||||||
makeWaveCanvas,
|
makeWaveCanvas,
|
||||||
removeWaveCanvas
|
makeWaveSvg,
|
||||||
|
removeWaveCanvas,
|
||||||
|
makeWaveView,
|
||||||
|
toggleRender
|
||||||
}
|
}
|
@ -158,6 +158,81 @@ function handleTimeScale(timescale) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} timescale
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function parseTimescale(timescale) {
|
||||||
|
if (typeof timescale !== 'string') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const str1 = timescale.trim();
|
||||||
|
const m = str1.match(/^(\d+)\s*(\w+)$/);
|
||||||
|
const res1 = ({ 1: 0, 10: 1, 100: 2 })[m[1]];
|
||||||
|
const res2 = ({ s: 0, ms: -3, us: -6, ns: -9, ps: -12, fs: -15 })[m[2]];
|
||||||
|
return res1 + res2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {BigInt} val
|
||||||
|
* @returns {string | number}
|
||||||
|
*/
|
||||||
|
function numberOrString(val) {
|
||||||
|
if (val < MAX_SAFE_INTEGER) {
|
||||||
|
return Number(val);
|
||||||
|
}
|
||||||
|
return '0x' + val.toString(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {number} a
|
||||||
|
* @param {number} b
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
function gcd(a, b) {
|
||||||
|
if (a === undefined) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
let r;
|
||||||
|
while (b !== 0) {
|
||||||
|
r = a % b;
|
||||||
|
a = b;
|
||||||
|
b = r;
|
||||||
|
}
|
||||||
|
return (a < 0) ? -a : a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function normaliseUsingGCD(globalLookup, signalValues) {
|
||||||
|
// const { tgcd, chango } = o;
|
||||||
|
|
||||||
|
const tgcd = globalLookup.tgcd;
|
||||||
|
|
||||||
|
// 使用全局最大公约数缩小时间倍率
|
||||||
|
globalLookup.t0 /= tgcd;
|
||||||
|
globalLookup.time /= tgcd;
|
||||||
|
|
||||||
|
for (const id of Reflect.ownKeys(signalValues)) {
|
||||||
|
// point[0] 是当前这个点的时间点
|
||||||
|
signalValues[id].wave.map(point => { point[0] /= tgcd });
|
||||||
|
}
|
||||||
|
|
||||||
|
const exp = Math.log10(tgcd) | 0;
|
||||||
|
if (exp > 0) {
|
||||||
|
const scale = Math.pow(10, exp);
|
||||||
|
const scaleGcd = tgcd / scale;
|
||||||
|
if (scaleGcd === (scaleGcd | 0)) {
|
||||||
|
globalLookup.tgcd = scaleGcd;
|
||||||
|
globalLookup.timescale += exp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const scopes = new Set(['begin', 'fork', 'function', 'module', 'task']);
|
const scopes = new Set(['begin', 'fork', 'function', 'module', 'task']);
|
||||||
const variables = new Set(['event', 'integer', 'parameter', 'real', 'realtime', 'reg', 'supply0',
|
const variables = new Set(['event', 'integer', 'parameter', 'real', 'realtime', 'reg', 'supply0',
|
||||||
'supply1', 'time', 'tri', 'triand', 'trior', 'trireg', 'tri0', 'tri1',
|
'supply1', 'time', 'tri', 'triand', 'trior', 'trireg', 'tri0', 'tri1',
|
||||||
@ -172,6 +247,8 @@ function isVariable(wire) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getVcdStream,
|
getVcdStream,
|
||||||
readVcdFile,
|
readVcdFile,
|
||||||
@ -182,5 +259,9 @@ export {
|
|||||||
isVariable,
|
isVariable,
|
||||||
makeIconClass,
|
makeIconClass,
|
||||||
scopes,
|
scopes,
|
||||||
variables
|
variables,
|
||||||
|
parseTimescale,
|
||||||
|
numberOrString,
|
||||||
|
gcd,
|
||||||
|
normaliseUsingGCD
|
||||||
};
|
};
|
107
src/hook/wave-view/bracer.js
Normal file
107
src/hook/wave-view/bracer.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const getX = require('./get-x.js');
|
||||||
|
const surferer = require('./surferer.js');
|
||||||
|
|
||||||
|
const skipT = (wave, iStart, tLimit) => {
|
||||||
|
let iRes = iStart;
|
||||||
|
let [tRes, vRes] = wave[iStart];
|
||||||
|
for (let i = iStart; i < wave.length; i++) {
|
||||||
|
const [t, v] = wave[i];
|
||||||
|
if (t >= tLimit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iRes = i;
|
||||||
|
tRes = t;
|
||||||
|
vRes = v;
|
||||||
|
}
|
||||||
|
return [iRes, vRes, tRes];
|
||||||
|
};
|
||||||
|
|
||||||
|
const bracer = (lane, desc, pstate) => {
|
||||||
|
const body = lane.body;
|
||||||
|
const { yStep } = pstate;
|
||||||
|
let { clock, valid, ready, up } = body;
|
||||||
|
up = up || 1;
|
||||||
|
|
||||||
|
const res = [];
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
if (clock && clock.ref) {
|
||||||
|
const clockWave = desc.chango[clock.ref].wave;
|
||||||
|
const clockEr = surferer(clockWave, pstate);
|
||||||
|
let tPrevClock = 0;
|
||||||
|
|
||||||
|
if (valid && valid.ref) {
|
||||||
|
const validWave = desc.chango[valid.ref].wave;
|
||||||
|
let iValid = 0;
|
||||||
|
let vValid;
|
||||||
|
|
||||||
|
if (ready && ready.ref) {
|
||||||
|
const readyWave = desc.chango[ready.ref].wave;
|
||||||
|
let iReady = 0;
|
||||||
|
let vReady;
|
||||||
|
|
||||||
|
for (const iClock of clockEr) {
|
||||||
|
const [tClock, vClock] = clockWave[iClock];
|
||||||
|
if (vClock) {
|
||||||
|
[iValid, vValid] = skipT(validWave, iValid, tClock);
|
||||||
|
[iReady, vReady] = skipT(readyWave, iReady, tClock);
|
||||||
|
const xClock = getX(pstate, tClock);
|
||||||
|
const xPrevClock = getX(pstate, tPrevClock);
|
||||||
|
const width = xClock - xPrevClock;
|
||||||
|
const height = up * yStep;
|
||||||
|
if (xClock > 0 && xPrevClock > 0 && width > 0) {
|
||||||
|
if (vValid) {
|
||||||
|
if (width >= 1) {
|
||||||
|
if (vReady) {
|
||||||
|
res.push(['rect', {fill: 'url(\'#valid&ready\')', width: Math.round(width), height, x: Math.round(xPrevClock), y: -height}]);
|
||||||
|
} else {
|
||||||
|
res.push(['rect', {fill: 'url(\'#valid&~ready\')', width: Math.round(width), height, x: Math.round(xPrevClock), y: -height}]);
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
count += 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tPrevClock = tClock;
|
||||||
|
if (count > 500) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const iClock of clockEr) {
|
||||||
|
const [tClock, vClock] = clockWave[iClock];
|
||||||
|
if (vClock) {
|
||||||
|
[iValid, vValid] = skipT(validWave, iValid, tClock);
|
||||||
|
const xClock = getX(pstate, tClock);
|
||||||
|
const xPrevClock = getX(pstate, tPrevClock);
|
||||||
|
const width = xClock - xPrevClock;
|
||||||
|
const height = up * yStep;
|
||||||
|
if (xClock > 0 && xPrevClock > 0 && width > 0) {
|
||||||
|
if (vValid) {
|
||||||
|
if (width >= 1) {
|
||||||
|
res.push(['rect', {fill: 'url(\'#valid\')', width: Math.round(width), height, x: Math.round(xPrevClock), y: -height}]);
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
count += 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tPrevClock = tClock;
|
||||||
|
if (count > 500) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = bracer;
|
||||||
|
|
||||||
|
/* eslint complexity: [1, 55] */
|
171
src/hook/wave-view/dom-container.js
Normal file
171
src/hook/wave-view/dom-container.js
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const genRenderWavesGL = require('./gen-render-waves-gl.js');
|
||||||
|
const renderCursor = require('./render-cursor.js');
|
||||||
|
const genResizeHandler = require('./gen-resize-handler.js');
|
||||||
|
const mTree = require('./mount-tree.js');
|
||||||
|
|
||||||
|
const setTime = (pstate, str) => {
|
||||||
|
// const { sidebarOffset, time, timescale, tgcd, xOffset } = pstate;
|
||||||
|
// pstate.xOffset = .5; // (2 * (pstate.width - pstate.sidebarWidth)) / pstate.time;
|
||||||
|
const m = str.match(/(\d+)(\w+)/); if (m) {
|
||||||
|
// const time1 = parseInt(m[1]);
|
||||||
|
// const timescale1 = ({s: 0, ms: -3, us: -6, ns: -9, ps: -12, fs: -15})[m[2]] || 0;
|
||||||
|
// pstate.xOffset = -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mouseMoveHandler = (cursor, content, pstate /* , render */) => {
|
||||||
|
const xmargin = 160;
|
||||||
|
const fontHeight = 20;
|
||||||
|
const fontWidth = fontHeight / 2;
|
||||||
|
const handler = event => {
|
||||||
|
const x = pstate.xCursor = event.clientX;
|
||||||
|
cursor.style.left = (x - xmargin) + 'px';
|
||||||
|
cursor.innerHTML = renderCursor({ xmargin, fontWidth, fontHeight }, pstate);
|
||||||
|
};
|
||||||
|
handler({ clientX: pstate.width / 2 });
|
||||||
|
content.addEventListener('mousemove', handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const getFullView = desc => {
|
||||||
|
console.log(desc);
|
||||||
|
if (desc.waveql) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const arr = [];
|
||||||
|
|
||||||
|
const rec = ero => {
|
||||||
|
if (ero.kind === 'scope') {
|
||||||
|
arr.push(ero.name);
|
||||||
|
ero.body.map(rec);
|
||||||
|
arr.push('..');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ero.kind === 'var') {
|
||||||
|
arr.push(ero.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.error(ero);
|
||||||
|
throw new Error();
|
||||||
|
// Object.keys(obj).map(name => {
|
||||||
|
// const ref = obj[name];
|
||||||
|
// if (typeof ref === 'object') {
|
||||||
|
// arr.push(name);
|
||||||
|
// rec(ref);
|
||||||
|
// arr.push('..');
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (typeof ref !== 'string') {
|
||||||
|
// throw new Error();
|
||||||
|
// }
|
||||||
|
// arr.push(name);
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
rec(desc.wires);
|
||||||
|
|
||||||
|
desc.waveql = arr.join('\n');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const domContainer = (obj) => {
|
||||||
|
|
||||||
|
const sidebarWidth = 256;
|
||||||
|
|
||||||
|
const fontHeight = 16;
|
||||||
|
|
||||||
|
const elo = mTree.createElemento(obj.elemento);
|
||||||
|
const container = mTree.createContainer(elo, obj.layers);
|
||||||
|
elo.container.tabIndex = '0';
|
||||||
|
if (obj.pluginRightPanel) {
|
||||||
|
obj.pluginRightPanel(elo);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pstate = {
|
||||||
|
fontHeight,
|
||||||
|
width: 1024, // [px] window width
|
||||||
|
height: 1024, // [px] window height
|
||||||
|
xScaleMax: 1000,
|
||||||
|
xScaleMin: 0.001,
|
||||||
|
topBarHeight: fontHeight * 1.5, // [px]
|
||||||
|
botBarHeight: fontHeight * 1.5, // [px]
|
||||||
|
xOffset: sidebarWidth,
|
||||||
|
yOffset: 0, // [px]
|
||||||
|
yStep: fontHeight * 1.5, // = 24 // [px] wave lane height
|
||||||
|
yDuty: 0.7,
|
||||||
|
sidebarWidth,
|
||||||
|
container
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
elo,
|
||||||
|
pstate,
|
||||||
|
start: (deso /* , opt */) => {
|
||||||
|
|
||||||
|
// content.appendChild(container);
|
||||||
|
// content.appendChild(elo.rightPanel);
|
||||||
|
// getFullView(deso);
|
||||||
|
|
||||||
|
deso.t0 = deso.t0 || 0;
|
||||||
|
// desc.xScale |= 8;
|
||||||
|
|
||||||
|
Object.assign(pstate, {
|
||||||
|
tgcd: deso.tgcd,
|
||||||
|
timescale: deso.timescale,
|
||||||
|
xScale: deso.xScale || 8,
|
||||||
|
numLanes: deso.view.length,
|
||||||
|
t0: deso.t0,
|
||||||
|
time: deso.time
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const str = localStorage.getItem('dide');
|
||||||
|
const obj = JSON.parse(str);
|
||||||
|
Object.assign(pstate, obj);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// const {timetopSVG, timebotSVG} = timeline(deso);
|
||||||
|
|
||||||
|
if (deso.timeOpt) {
|
||||||
|
setTime(pstate, deso.timeOpt.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let render2 = genRenderWavesGL(elo);
|
||||||
|
let render1 = render2(deso);
|
||||||
|
let render = render1(pstate, obj.renderPlugins);
|
||||||
|
deso.render = render;
|
||||||
|
|
||||||
|
const resizeHandler = genResizeHandler(pstate);
|
||||||
|
|
||||||
|
const resizeObserver = new ResizeObserver(entries => {
|
||||||
|
|
||||||
|
for (let entry of entries) {
|
||||||
|
// TODO : 使用更新的属性替换 contentRect
|
||||||
|
// 未来版本 contentRect 可能会被丢弃
|
||||||
|
let { width, height } = entry.contentRect;
|
||||||
|
// height = height || 888;
|
||||||
|
// console.log('resizeObserver', width, height);
|
||||||
|
resizeHandler(width, height);
|
||||||
|
}
|
||||||
|
deso.render();
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(elo.container);
|
||||||
|
resizeObserver.observe(document.body);
|
||||||
|
|
||||||
|
// pinchAndZoom(els.container, content, pstate, render);
|
||||||
|
resizeHandler(elo.container.clientWidth, elo.container.clientHeight);
|
||||||
|
mouseMoveHandler(elo.cursor, elo.container, pstate, deso.render);
|
||||||
|
deso.render();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = domContainer;
|
||||||
|
|
||||||
|
/* eslint-env browser */
|
11
src/hook/wave-view/format-time.js
Normal file
11
src/hook/wave-view/format-time.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const formatTime = (t, expo) => {
|
||||||
|
const prefixes = ['T', 'G', 'M', 'k', '', 'm', 'µ', 'n', 'p', 'f', 'a', 'z', 'y'];
|
||||||
|
const ts1 = 14 - expo;
|
||||||
|
const prefix = prefixes[(ts1 / 3) |0];
|
||||||
|
const mult = ([100, 10, 1])[ts1 % 3];
|
||||||
|
return (t * mult).toLocaleString() + ' ' + prefix + 's';
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = formatTime;
|
143
src/hook/wave-view/format.js
Normal file
143
src/hook/wave-view/format.js
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const format = (fmt, len) => {
|
||||||
|
len = BigInt(len);
|
||||||
|
{
|
||||||
|
const m = fmt.match(/^%(?<sign>[s])?(?<radix>[bodh])(?<elen>\d+)?$/);
|
||||||
|
if (m) {
|
||||||
|
const radix = ({b: 2, o: 8, d: 10, h: 16, H: 16})[m.groups.radix];
|
||||||
|
if (m.groups.sign) {
|
||||||
|
return (val, pos) => {
|
||||||
|
if ((val >> (len - 1n)) & 1n) {
|
||||||
|
val = val - (2n ** len);
|
||||||
|
}
|
||||||
|
let txtOrig = val.toString(radix);
|
||||||
|
if (txtOrig.length <= pos) {
|
||||||
|
return txtOrig;
|
||||||
|
}
|
||||||
|
const sign = (val < 0) ? '-' : '+';
|
||||||
|
if (pos === 1) {
|
||||||
|
return sign;
|
||||||
|
}
|
||||||
|
if (pos === 2) {
|
||||||
|
return sign + '\u205D';
|
||||||
|
}
|
||||||
|
return sign + '\u205D' + txtOrig.slice(2 - pos);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (Number(m.groups.elen) > 0) {
|
||||||
|
const elen = BigInt(m.groups.elen);
|
||||||
|
return (val, pos) => {
|
||||||
|
let txtRes = [];
|
||||||
|
for (let i = 0n; i < len; i += elen) {
|
||||||
|
const chunk = (val >> i) & (2n ** elen - 1n);
|
||||||
|
txtRes.unshift(chunk.toString(radix));
|
||||||
|
}
|
||||||
|
txtRes = '{' + txtRes.join(', ') + '}';
|
||||||
|
if (txtRes.length <= pos) {
|
||||||
|
return txtRes;
|
||||||
|
}
|
||||||
|
if (pos === 1) {
|
||||||
|
return '\u205D';
|
||||||
|
}
|
||||||
|
return '\u205D' + txtRes.slice(1 - pos);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return (val, pos) => {
|
||||||
|
let txtOrig = val.toString(radix);
|
||||||
|
if (txtOrig.length <= pos) {
|
||||||
|
return txtOrig;
|
||||||
|
}
|
||||||
|
if (pos === 1) {
|
||||||
|
return '\u205D';
|
||||||
|
}
|
||||||
|
return '\u205D' + txtOrig.slice(1 - pos);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
const m = fmt.match(/^%a$/);
|
||||||
|
if (m) {
|
||||||
|
return (val, pos) => {
|
||||||
|
let txtRes = '';
|
||||||
|
for (let i = 0n; i < len; i += 8n) {
|
||||||
|
txtRes = String.fromCharCode(Number((val >> i) & 0xffn)) + txtRes;
|
||||||
|
}
|
||||||
|
txtRes = txtRes.trim();
|
||||||
|
if (txtRes.length <= pos) {
|
||||||
|
return txtRes;
|
||||||
|
}
|
||||||
|
txtRes = txtRes.slice(0, pos - 1) + '\u205D';
|
||||||
|
return txtRes;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
const m = fmt.match(/^%(?<form>[fe])(?<elen>32|64)$/);
|
||||||
|
if (m) {
|
||||||
|
const buf = new ArrayBuffer(8);
|
||||||
|
const bufBInt = new BigInt64Array(buf);
|
||||||
|
const elen = BigInt(m.groups.elen);
|
||||||
|
const bufFloat = new ((elen === 32n) ? Float32Array : Float64Array)(buf);
|
||||||
|
const mask = (elen === 32n) ? 0xffffffffn : 0xffffffffffffffffn;
|
||||||
|
if (m.groups.form === 'f') {
|
||||||
|
if (len > elen) {
|
||||||
|
return (val, pos) => {
|
||||||
|
let txtRes = [];
|
||||||
|
for (let i = 0n; i < len; i += elen) {
|
||||||
|
bufBInt[0] = (val >> i) & mask;
|
||||||
|
const fval = bufFloat[0];
|
||||||
|
txtRes.unshift(fval.toString());
|
||||||
|
}
|
||||||
|
txtRes = '{' + txtRes.join(', ') + '}';
|
||||||
|
if (txtRes.length <= pos) {
|
||||||
|
return txtRes;
|
||||||
|
}
|
||||||
|
if (pos === 1) {
|
||||||
|
return '\u205D';
|
||||||
|
}
|
||||||
|
return '\u205D' + txtRes.slice(1 - pos);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return (val, pos) => {
|
||||||
|
bufBInt[0] = val & mask;
|
||||||
|
const fval = bufFloat[0];
|
||||||
|
let txtOrig;
|
||||||
|
txtOrig = fval.toString();
|
||||||
|
if (txtOrig.length <= pos) {
|
||||||
|
return txtOrig;
|
||||||
|
}
|
||||||
|
for (let i = pos; i >= 0; i--) {
|
||||||
|
txtOrig = fval.toPrecision(i + 1);
|
||||||
|
if (txtOrig.length <= pos) {
|
||||||
|
return txtOrig;
|
||||||
|
}
|
||||||
|
txtOrig = fval.toExponential(i);
|
||||||
|
if (txtOrig.length <= pos) {
|
||||||
|
return txtOrig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (val < 0) ? '-' : '+';
|
||||||
|
};
|
||||||
|
} else {// e
|
||||||
|
return (val, pos) => {
|
||||||
|
bufBInt[0] = val & mask;
|
||||||
|
const fval = bufFloat[0];
|
||||||
|
let txtOrig;
|
||||||
|
txtOrig = fval.toExponential();
|
||||||
|
if (txtOrig.length <= pos) {
|
||||||
|
return txtOrig;
|
||||||
|
}
|
||||||
|
for (let i = 4; i <= pos; i++) {
|
||||||
|
txtOrig = fval.toExponential(pos - i);
|
||||||
|
if (txtOrig.length <= pos) {
|
||||||
|
return txtOrig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (val < 0) ? '-' : '+';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return () => '?';
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = format;
|
31
src/hook/wave-view/gen-key-handler.js
Normal file
31
src/hook/wave-view/gen-key-handler.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const {keyName} = require('w3c-keyname');
|
||||||
|
|
||||||
|
const executeKeyHandler = (key, keyBindo, pstate, cm) => {
|
||||||
|
return (keyBindo[key] || keyBindo.nop).fn(pstate, cm);
|
||||||
|
};
|
||||||
|
|
||||||
|
const genKeyHandler = (div, pstate, deso, cm, keyBindo, plugins) => {
|
||||||
|
return event => {
|
||||||
|
|
||||||
|
const modifier = (
|
||||||
|
(event.ctrlKey ? 'Ctrl+' : '') +
|
||||||
|
(event.shiftKey ? 'Shift+' : '') +
|
||||||
|
(event.altKey ? 'Alt+' : '')
|
||||||
|
);
|
||||||
|
// const key = modifier + event.key;
|
||||||
|
const key = modifier + keyName(event);
|
||||||
|
|
||||||
|
if (executeKeyHandler(key, keyBindo, pstate, cm)) {
|
||||||
|
event.stopPropagation();
|
||||||
|
if (plugins != undefined) {
|
||||||
|
plugins.map(fn => fn(key, event));
|
||||||
|
}
|
||||||
|
deso.render();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.executeKeyHandler = executeKeyHandler;
|
||||||
|
exports.genKeyHandler = genKeyHandler;
|
30
src/hook/wave-view/gen-on-wheel.js
Normal file
30
src/hook/wave-view/gen-on-wheel.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const genOnWheel = (element, pstate, deso, cm, keyBindo, plugins) =>
|
||||||
|
event => {
|
||||||
|
const {deltaY} = event;
|
||||||
|
if (event.ctrlKey) {
|
||||||
|
const key = (deltaY < 0)
|
||||||
|
? 'Ctrl+icon:scrollUp'
|
||||||
|
: ((deltaY > 0) ? 'Ctrl+icon:scrollDown' : 'nop');
|
||||||
|
if (keyBindo[key].fn(pstate)) {
|
||||||
|
if (plugins != undefined) {
|
||||||
|
plugins.map(fn => fn(key, event));
|
||||||
|
}
|
||||||
|
deso.render();
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
} else
|
||||||
|
if (event.shiftKey) {
|
||||||
|
const key = (deltaY < 0) ? 'Shift+icon:scrollUp' : ((deltaY > 0) ? 'Shift+icon:scrollDown' : 'nop');
|
||||||
|
if (keyBindo[key].fn(pstate)) {
|
||||||
|
if (plugins != undefined) {
|
||||||
|
plugins.map(fn => fn(key, event));
|
||||||
|
}
|
||||||
|
deso.render();
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = genOnWheel;
|
353
src/hook/wave-view/gen-render-waves-gl.js
Normal file
353
src/hook/wave-view/gen-render-waves-gl.js
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const cColors = new Float32Array([
|
||||||
|
0, 0, 0, 0, // 0:
|
||||||
|
0, 0, 1, 1, // 1: (Z) high impedance
|
||||||
|
|
||||||
|
0, 1, 0, 1, // 2: strong 0
|
||||||
|
0, 1, 1, 1, // 3: strong 1
|
||||||
|
1, 0, 0, 1, // 4: (x X) strong unknown
|
||||||
|
|
||||||
|
.5, 1, 1, 1, // 5: vec
|
||||||
|
1, 1, 0, 1, // 6: yellow
|
||||||
|
1, 0, 1, 1, // 7: strange purple
|
||||||
|
|
||||||
|
0, 1, 0, .5, // 8: (l L) weak 0
|
||||||
|
0, 1, 1, .5, // 9: (h H) weak 1
|
||||||
|
1, 0, 0, .5, // 10: (w W) weak unknown
|
||||||
|
|
||||||
|
0, 0, 0, 0, // 11:
|
||||||
|
0, 0, 0, 0, // 12:
|
||||||
|
0, 0, 0, 0, // 13:
|
||||||
|
0, 0, 0, 0, // 14:
|
||||||
|
0, 0, 0, 0 // 15:
|
||||||
|
]);
|
||||||
|
|
||||||
|
const cTilts = new Float32Array([ // 14
|
||||||
|
0, 0, // 0
|
||||||
|
1, -1, // 1
|
||||||
|
1, 0, // 2
|
||||||
|
1, 1, // 3
|
||||||
|
-1, -1, // 4
|
||||||
|
-1, 0, // 5
|
||||||
|
-1, 1 // 6
|
||||||
|
]);
|
||||||
|
|
||||||
|
const shaderer = (kind, src) => gl => {
|
||||||
|
const vShader = gl.createShader(gl[kind]);
|
||||||
|
gl.shaderSource(vShader, src);
|
||||||
|
gl.compileShader(vShader);
|
||||||
|
return vShader;
|
||||||
|
};
|
||||||
|
|
||||||
|
const vertexShaderScalar = shaderer('VERTEX_SHADER', `#version 300 es
|
||||||
|
in uvec3 pos;
|
||||||
|
out vec4 v_color;
|
||||||
|
uniform vec2 scale;
|
||||||
|
uniform vec2 offset;
|
||||||
|
uniform vec4 colors[16];
|
||||||
|
uniform vec2 tilts[7];
|
||||||
|
uniform float tilt;
|
||||||
|
void main() {
|
||||||
|
v_color = colors[pos.z];
|
||||||
|
vec2 node = tilts[pos.y];
|
||||||
|
gl_Position = vec4(
|
||||||
|
float(pos.x) * scale.x + offset.x + node[1] * tilt,
|
||||||
|
float(node[0]) * scale.y + offset.y,
|
||||||
|
1, 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
const fragmentShader = shaderer('FRAGMENT_SHADER', `#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
in vec4 v_color;
|
||||||
|
out vec4 myOutputColor;
|
||||||
|
void main() {
|
||||||
|
myOutputColor = v_color;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
const initProgram = gl => {
|
||||||
|
const program = gl.createProgram();
|
||||||
|
gl.attachShader(program, vertexShaderScalar(gl));
|
||||||
|
gl.attachShader(program, fragmentShader(gl));
|
||||||
|
gl.linkProgram(program);
|
||||||
|
gl.useProgram(program);
|
||||||
|
|
||||||
|
return 'colors tilts scale offset tilt'
|
||||||
|
.split(/\s+/)
|
||||||
|
.reduce((res, name) => Object.assign(res, {
|
||||||
|
[name]: gl.getUniformLocation(program, name)
|
||||||
|
}), {
|
||||||
|
pos: gl.getAttribLocation(program, 'pos'),
|
||||||
|
gl
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const bar = [
|
||||||
|
(f, t, a, b, c0, c1) => [].concat( // 0
|
||||||
|
(f === 1) ? [a, 2, c1] : [],
|
||||||
|
[a, 5, c0],
|
||||||
|
[b, 5, c0],
|
||||||
|
(t > 1) ? [b, 0, c0] : []
|
||||||
|
),
|
||||||
|
(f, t, a, b, c0, c1) => [].concat( // 1
|
||||||
|
(f === 0) ? [a, 5, c0] :
|
||||||
|
(f > 1) ? [a, 0, c0] : [],
|
||||||
|
[a, 2, c1],
|
||||||
|
[b, 2, c1],
|
||||||
|
(t > 1) ? [b, 0, c0] : []
|
||||||
|
),
|
||||||
|
(f, t, a, b, c0, c1) => [a, 0, c0, b, 0, c1] // 2 = Z
|
||||||
|
];
|
||||||
|
|
||||||
|
const brick = [
|
||||||
|
(f, t, a, b, c0, c1) => [].concat( // 0
|
||||||
|
(f === 0) ? [a, 5, c0] :
|
||||||
|
(f === 1) ? [a, 1, c1] : [],
|
||||||
|
[a, 6, c0],
|
||||||
|
(t === 0) ? [b, 5, c0] :
|
||||||
|
[b, 4, c0],
|
||||||
|
(t === 3) ? [b, 0, c0] : []
|
||||||
|
),
|
||||||
|
(f, t, a, b, c0, c1) => [].concat( // 1
|
||||||
|
(f === 0) ? [a, 4, c0, a, 3, c1] :
|
||||||
|
(f === 1) ? [a, 2, c1] :
|
||||||
|
(f === 2) ? [a, 3, c1] :
|
||||||
|
[a, 0, c0, a, 3, c1],
|
||||||
|
(t === 1) ? [b, 3, c1] :
|
||||||
|
[b, 1, c1],
|
||||||
|
(t === 3) ? [b, 0, c0] : []
|
||||||
|
),
|
||||||
|
(f, t, a, b, c0, c1) => [].concat( // 2
|
||||||
|
(f === 0) ? [a, 4, 0] :
|
||||||
|
(f === 1) ? [a, 1, 0] :
|
||||||
|
[a, 0, 0],
|
||||||
|
(t === 0) ? [b, 6, 0, b, 6, c0] :
|
||||||
|
(t === 1) ? [b, 3, 0, b, 3, c1, b, 4, c0] :
|
||||||
|
[b, 0, 0, b, 0, c0, b, 4, c0],
|
||||||
|
(f === 0) ? [a, 4, c0, a, 3, c1] :
|
||||||
|
(f === 1) ? [a, 6, c0, a, 1, c1] :
|
||||||
|
[a, 6, c0, a, 0, c0, a, 3, c1],
|
||||||
|
(t === 0) ? [b, 1, c1, b, 6, c0] :
|
||||||
|
(t === 1) ? [b, 3, c1] :
|
||||||
|
[b, 1, c1, b, 0, c0]
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
const wave2vertex = desc => {
|
||||||
|
Object.keys(desc.chango).map(ref => {
|
||||||
|
|
||||||
|
const chang = desc.chango[ref];
|
||||||
|
const { kind, wave } = chang;
|
||||||
|
|
||||||
|
// desc.view.map(lane => {
|
||||||
|
// if (!lane || lane.ref === undefined) { return; }
|
||||||
|
// const chang = desc.chango[lane.ref];
|
||||||
|
// if (chang === undefined) { return; }
|
||||||
|
// const {kind, wave} = chang;
|
||||||
|
// lane.kind = kind;
|
||||||
|
// lane.wave = wave;
|
||||||
|
|
||||||
|
if (kind === 'bit') {
|
||||||
|
const vertices = [];
|
||||||
|
const ilen = wave.length;
|
||||||
|
for (let i = 0; i < ilen; i++) {
|
||||||
|
const f = wave[(i === 0) ? 0 : (i - 1)];
|
||||||
|
const [tim, val] = wave[i];
|
||||||
|
const t = wave[(i === (ilen - 1)) ? i : (i + 1)];
|
||||||
|
const tt = (i === (ilen - 1)) ? desc.time : wave[i + 1][0];
|
||||||
|
|
||||||
|
switch (val) {
|
||||||
|
case 0: case 1: // 0 1
|
||||||
|
vertices.push(...bar[val](f[1], t[1], tim, tt, 2, 3));
|
||||||
|
break;
|
||||||
|
case 2: case 3: // x X
|
||||||
|
vertices.push(...bar[2](f[1], t[1], tim, tt, 4, 4));
|
||||||
|
break;
|
||||||
|
case 4: case 5: // z Z
|
||||||
|
vertices.push(...bar[2](f[1], t[1], tim, tt, 1, 1));
|
||||||
|
break;
|
||||||
|
case 6: case 7: // u U uninitialized
|
||||||
|
vertices.push(...bar[2](f[1], t[1], tim, tt, 6, 6));
|
||||||
|
break;
|
||||||
|
case 8: case 9: // w W weak unknown
|
||||||
|
vertices.push(...bar[2](f[1], t[1], tim, tt, 10, 10));
|
||||||
|
break;
|
||||||
|
case 10: case 11: // l L
|
||||||
|
vertices.push(...bar[0](f[1], t[1], tim, tt, 8, 9));
|
||||||
|
break;
|
||||||
|
case 12: case 13: // h H
|
||||||
|
vertices.push(...bar[1](f[1], t[1], tim, tt, 8, 9));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vertices.push(...bar[2](f[1], t[1], tim, tt, 7, 7));
|
||||||
|
// throw new Error('val is: ' + val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chang.vertices = new Uint32Array(vertices); // Uint16Array // 16bit
|
||||||
|
|
||||||
|
// lane.vertices = new Uint16Array(vertices);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (kind === 'vec') {
|
||||||
|
const vertices = [];
|
||||||
|
const ilen = wave.length;
|
||||||
|
for (let i = 0; i < ilen; i++) {
|
||||||
|
// const f = wave[(i === 0) ? 0 : (i - 1)];
|
||||||
|
const [tim, val, msk] = wave[i];
|
||||||
|
// const t = wave[(i === (ilen - 1)) ? i : (i + 1)];
|
||||||
|
const tt = (i === (ilen - 1)) ? desc.time : wave[i + 1][0];
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
if (msk) {
|
||||||
|
vertices.push(...brick[2](2, 2, tim, tt, 4, 4)); // x,z?
|
||||||
|
} else {
|
||||||
|
// vertices.push(...brick[2](2, 2, tim, tt, 5, 5)); // 2
|
||||||
|
vertices.push(
|
||||||
|
tim, 0, 0,
|
||||||
|
tt, 0, 0, tt, 0, 5, tt, 4, 5,
|
||||||
|
tim, 6, 5, tim, 0, 5, tim, 3, 5,
|
||||||
|
tt, 1, 5, tt, 0, 5
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (msk) {
|
||||||
|
vertices.push(...brick[2](2, 2, tim, tt, 4, 4)); // x
|
||||||
|
} else {
|
||||||
|
// vertices.push(...brick[0](2, 2, tim, tt, 2, 3)); // 0
|
||||||
|
vertices.push(tim, 6, 2, tt, 4, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chang.vertices = new Uint32Array(vertices); // Uint16Array // 16bit
|
||||||
|
|
||||||
|
// lane.vertices = new Uint16Array(vertices);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const initData = (loco, desc) => {
|
||||||
|
|
||||||
|
Object.keys(desc.chango).map(ref => {
|
||||||
|
|
||||||
|
const chang = desc.chango[ref];
|
||||||
|
const { vertices } = chang;
|
||||||
|
|
||||||
|
// desc.view.map(lane => {
|
||||||
|
// if (!lane) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// const vertices = desc.chango[lane.ref].vertices;
|
||||||
|
//
|
||||||
|
// if (!vertices) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!lane || lane.vertices === undefined) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// const vertices = lane.vertices;
|
||||||
|
|
||||||
|
const gl = loco.gl;
|
||||||
|
const vertexBuffer = gl.createBuffer();
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
||||||
|
|
||||||
|
// 将初始化的顶点数据复制到 buffer 区域
|
||||||
|
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
||||||
|
|
||||||
|
chang.vao = gl.createVertexArray();
|
||||||
|
gl.bindVertexArray(chang.vao);
|
||||||
|
gl.vertexAttribIPointer(
|
||||||
|
loco.pos,
|
||||||
|
3, // number of conponents (x, y, z)
|
||||||
|
gl.UNSIGNED_INT, // UNSIGNED_SHORT, // 16bit
|
||||||
|
0 /* stride */, 0 /* offset */
|
||||||
|
);
|
||||||
|
gl.enableVertexAttribArray(loco.pos);
|
||||||
|
|
||||||
|
gl.uniform4fv(loco.colors, cColors);
|
||||||
|
gl.uniform2fv(loco.tilts, cTilts);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const genRenderWavesGL = (els) => {
|
||||||
|
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
els.view0.replaceChildren(canvas);
|
||||||
|
// canvas.width = 1024;
|
||||||
|
// canvas.height = 1024;
|
||||||
|
// canvas.style = 'background-color: #111;';
|
||||||
|
const glProps = {
|
||||||
|
premultipliedAlpha: false,
|
||||||
|
alpha: true,
|
||||||
|
antialias: false,
|
||||||
|
depth: false
|
||||||
|
};
|
||||||
|
const gl = canvas.getContext('webgl2', glProps);
|
||||||
|
const loco = initProgram(gl);
|
||||||
|
|
||||||
|
return desc => {
|
||||||
|
wave2vertex(desc);
|
||||||
|
initData(loco, desc);
|
||||||
|
|
||||||
|
return (pstate, plugins) => {
|
||||||
|
let aReq;
|
||||||
|
return () => {
|
||||||
|
console.log('[wave render] render');
|
||||||
|
if (aReq !== undefined) {
|
||||||
|
cancelAnimationFrame(aReq);
|
||||||
|
}
|
||||||
|
aReq = window.requestAnimationFrame(() => {
|
||||||
|
const { width, height, xScale, xOffset, yOffset, yStep, yDuty } = pstate;
|
||||||
|
const cHeight = height - 40; // FIXME 40
|
||||||
|
// console.log(pstate);
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = cHeight;
|
||||||
|
// const xs = pstate.scale;
|
||||||
|
// const xo = -1;
|
||||||
|
gl.uniform1f(loco.tilt, 3 / width);
|
||||||
|
gl.uniform2f(loco.scale, 2 * xScale / width, yStep * yDuty / cHeight); // FIXME 40
|
||||||
|
gl.viewport(0, 0, width, cHeight);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
desc.view.map((lane, idx) => {
|
||||||
|
// console.log(lane, idx);
|
||||||
|
if (!lane) { // || lane.vertices === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ref = lane.ref;
|
||||||
|
if (ref === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const chang = desc.chango[ref];
|
||||||
|
if (chang === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// console.log(chang);
|
||||||
|
gl.bindVertexArray(chang.vao);
|
||||||
|
gl.uniform2f(loco.offset,
|
||||||
|
(2 * xOffset / width) - 1,
|
||||||
|
(2 * yOffset - 2 * yStep * (idx + .7)) / cHeight + 1
|
||||||
|
);
|
||||||
|
gl.drawArrays(
|
||||||
|
gl.LINE_STRIP, // mode
|
||||||
|
0, // first
|
||||||
|
chang.vertices.length / 3 // count
|
||||||
|
);
|
||||||
|
});
|
||||||
|
plugins.map(fn => fn(desc, pstate, els));
|
||||||
|
aReq = undefined;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = genRenderWavesGL;
|
||||||
|
|
||||||
|
/* eslint-env browser */
|
||||||
|
/* eslint complexity: [1, 30] */
|
27
src/hook/wave-view/gen-resize-handler.js
Normal file
27
src/hook/wave-view/gen-resize-handler.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const xOffsetUpdate = require('./x-offset-update.js');
|
||||||
|
|
||||||
|
const genResizeHandler = pstate =>
|
||||||
|
(width, height) => {
|
||||||
|
let { xOffset, yOffset, xScale, yStep, time, sidebarWidth, numLanes } = pstate;
|
||||||
|
pstate.width = width;
|
||||||
|
pstate.height = height;
|
||||||
|
|
||||||
|
// Y
|
||||||
|
const yOffsetMax = (numLanes + 2) * 2 * yStep;
|
||||||
|
if (yOffsetMax < 0) {
|
||||||
|
yOffset = 0;
|
||||||
|
} else if (yOffset > yOffsetMax) {
|
||||||
|
yOffset = yOffsetMax;
|
||||||
|
}
|
||||||
|
pstate.yOffset = yOffset;
|
||||||
|
console.log('resize handler', pstate);
|
||||||
|
// X
|
||||||
|
const xScaleMin = pstate.xScaleMin = (width - sidebarWidth) / time;
|
||||||
|
pstate.xScale = (xScale < xScaleMin) ? xScaleMin : xScale;
|
||||||
|
pstate.xScaleMin = 0.001;
|
||||||
|
xOffsetUpdate(pstate, xOffset);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = genResizeHandler;
|
16
src/hook/wave-view/get-element.js
Normal file
16
src/hook/wave-view/get-element.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const getElement = divName => {
|
||||||
|
if (typeof divName === 'string') {
|
||||||
|
const c = document.getElementById(divName);
|
||||||
|
if (c === null) {
|
||||||
|
throw new Error('<div> element width Id: "' + divName + '" not found');
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return divName;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = getElement;
|
||||||
|
|
||||||
|
/* eslint-env browser */
|
33
src/hook/wave-view/get-label.js
Normal file
33
src/hook/wave-view/get-label.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const format = require('./format.js');
|
||||||
|
|
||||||
|
const getLabel = (lane) => {
|
||||||
|
if (typeof lane !== 'object') {
|
||||||
|
lane = {};
|
||||||
|
}
|
||||||
|
const fmt = lane.format || '%h';
|
||||||
|
const width = Number(lane.width || 1);
|
||||||
|
const formatter = format(fmt, width);
|
||||||
|
|
||||||
|
return (vPre, mPre, x, w) => {
|
||||||
|
|
||||||
|
if (mPre) {
|
||||||
|
if (vPre) {
|
||||||
|
return ['text', {x, class: 'zxviolet'}, '?'];
|
||||||
|
} else {
|
||||||
|
return ['text', {x, class: 'xred'}, 'x'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pos = (w / 8) |0;
|
||||||
|
|
||||||
|
vPre = BigInt(vPre);
|
||||||
|
|
||||||
|
const txtShort = formatter(vPre, pos, width);
|
||||||
|
|
||||||
|
return ['text', {x}, txtShort];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = getLabel;
|
26
src/hook/wave-view/get-listing.js
Normal file
26
src/hook/wave-view/get-listing.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const lister = require('./lister.js');
|
||||||
|
|
||||||
|
const getListing = async (readers) => {
|
||||||
|
let listing = [];
|
||||||
|
const r = readers.find(reader => reader.ext === 'lst');
|
||||||
|
if (r) {
|
||||||
|
const utf8Decoder = new TextDecoder('utf-8');
|
||||||
|
const list = lister();
|
||||||
|
for (let i = 0; i < 10000; i++) {
|
||||||
|
let { done, value } = await r.reader.read();
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
value = utf8Decoder.decode(value, {stream: true});
|
||||||
|
}
|
||||||
|
list.onChunk(value);
|
||||||
|
if (done) {
|
||||||
|
listing = list.getTrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listing;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = getListing;
|
13
src/hook/wave-view/get-t.js
Normal file
13
src/hook/wave-view/get-t.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const getT = (x, pstate) => {
|
||||||
|
const {xOffset, xScale, tgcd } = pstate;
|
||||||
|
return Math.round((x / xScale) - (xOffset / xScale)) * tgcd;
|
||||||
|
// t = ((x / xScale * 2) - (xOffset * width / xScale)) * tgcd;
|
||||||
|
// t = (x / xScale * 2) * tgcd - (xOffset * width / xScale) * tgcd;
|
||||||
|
// t + (xOffset * width / xScale) * tgcd = (x / xScale * 2) * tgcd;
|
||||||
|
// (t / tgcd) + (xOffset * width / xScale) = (x / xScale * 2);
|
||||||
|
// (t / tgcd) * xScale / 2 + (xOffset * width / 2) = x;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = getT;
|
6
src/hook/wave-view/get-x.js
Normal file
6
src/hook/wave-view/get-x.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const getX = (pstate, time) =>
|
||||||
|
time * pstate.xScale + pstate.xOffset;
|
||||||
|
|
||||||
|
module.exports = getX;
|
15
src/hook/wave-view/hash.js
Normal file
15
src/hook/wave-view/hash.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Fletcher Style checksum
|
||||||
|
|
||||||
|
const hash = str => {
|
||||||
|
let sum1 = 599;
|
||||||
|
let sum2 = 173;
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
sum1 = (sum1 + str.charCodeAt(i)) & 255;
|
||||||
|
sum2 = (sum2 + sum1) & 255;
|
||||||
|
}
|
||||||
|
return (sum2 ^ sum1 ^ (sum2 >> 5) ^ (sum1 >> 5)) % 36;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = hash;
|
27
src/hook/wave-view/index.js
Normal file
27
src/hook/wave-view/index.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const getElement = require('./get-element.js');
|
||||||
|
const getListing = require('./get-listing.js');
|
||||||
|
const domContainer = require('./dom-container.js');
|
||||||
|
const pluginRenderValues = require('./plugin-render-values.js');
|
||||||
|
const pluginRenderTimeGrid = require('./plugin-render-time-grid.js');
|
||||||
|
const keyBindo = require('./key-bindo.js');
|
||||||
|
const mountTree = require('./mount-tree.js');
|
||||||
|
const genKeyHandler = require('./gen-key-handler.js');
|
||||||
|
const genOnWheel = require('./gen-on-wheel.js');
|
||||||
|
const xOffsetUpdate = require('./x-offset-update.js');
|
||||||
|
const getX = require('./get-x.js');
|
||||||
|
const getT = require('./get-t.js');
|
||||||
|
|
||||||
|
exports.getListing = getListing;
|
||||||
|
exports.getElement = getElement;
|
||||||
|
exports.domContainer = domContainer;
|
||||||
|
exports.pluginRenderValues = pluginRenderValues;
|
||||||
|
exports.pluginRenderTimeGrid = pluginRenderTimeGrid;
|
||||||
|
exports.keyBindo = keyBindo;
|
||||||
|
exports.mountTree = mountTree;
|
||||||
|
exports.genKeyHandler = genKeyHandler;
|
||||||
|
exports.genOnWheel = genOnWheel;
|
||||||
|
exports.xOffsetUpdate = xOffsetUpdate;
|
||||||
|
exports.getX = getX;
|
||||||
|
exports.getT = getT;
|
84
src/hook/wave-view/key-bindo.js
Normal file
84
src/hook/wave-view/key-bindo.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const xOffsetUpdate = require('./x-offset-update.js');
|
||||||
|
const xScaleUpdate = require('./x-scale-update.js');
|
||||||
|
|
||||||
|
const yScroll = delta => (pstate, cm) => {
|
||||||
|
const info = cm.getScrollInfo();
|
||||||
|
cm.scrollTo(null, info.top + info.clientHeight * delta);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const pluso = {
|
||||||
|
desc: 'Zoom in time',
|
||||||
|
fn: pstate => xScaleUpdate(pstate, 3 / 2 * pstate.xScale)
|
||||||
|
};
|
||||||
|
|
||||||
|
const minuso = {
|
||||||
|
desc: 'Zoom out time',
|
||||||
|
fn: pstate => xScaleUpdate(pstate, 2 / 3 * pstate.xScale)
|
||||||
|
};
|
||||||
|
|
||||||
|
const fullo = {
|
||||||
|
desc: 'All of time',
|
||||||
|
fn: pstate => xScaleUpdate(pstate, pstate.xScaleMin)
|
||||||
|
};
|
||||||
|
|
||||||
|
const scroll = {
|
||||||
|
left: {
|
||||||
|
desc: 'Scroll into the past',
|
||||||
|
fn: pstate => xOffsetUpdate(pstate, pstate.xOffset + .2 * pstate.width)
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
desc: 'Scroll into the future',
|
||||||
|
fn: pstate => xOffsetUpdate(pstate, pstate.xOffset - .2 * pstate.width)
|
||||||
|
},
|
||||||
|
up: {
|
||||||
|
desc: 'scroll up',
|
||||||
|
fn: yScroll(-.1)
|
||||||
|
},
|
||||||
|
down: {
|
||||||
|
desc: 'scroll down',
|
||||||
|
fn: yScroll(.1)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const editable = {
|
||||||
|
desc: 'Toggle edit mode',
|
||||||
|
fn: (pstate, cm) => {
|
||||||
|
console.log('editable', pstate, cm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// Alt + <, >. left / right
|
||||||
|
'Alt+,': scroll.left, 'Shift+icon:scrollUp': scroll.left,
|
||||||
|
|
||||||
|
'Alt+.': scroll.right, 'Shift+icon:scrollDown': scroll.right,
|
||||||
|
|
||||||
|
// Alt + [ ] home / end
|
||||||
|
'Alt+[': { desc: 'Jump to beginning of time', fn: pstate => xOffsetUpdate(pstate, pstate.sidebarWidth) }, // Home
|
||||||
|
|
||||||
|
'Alt+]': { desc: 'Jump to end time', fn: pstate => xOffsetUpdate(pstate, pstate.width - pstate.xScale * pstate.time) }, // End
|
||||||
|
|
||||||
|
// ALT + - +
|
||||||
|
'Alt+=': pluso, // '+': pluso, '=': pluso,
|
||||||
|
'Ctrl+icon:scrollUp': pluso,
|
||||||
|
|
||||||
|
'Alt+-': minuso, // '-': minuso, '_': minuso,
|
||||||
|
'Ctrl+icon:scrollDown': minuso,
|
||||||
|
|
||||||
|
'Alt+0': fullo, // 'Shift+f': fullo, F: fullo, 'Shift+F': fullo,
|
||||||
|
|
||||||
|
'Alt+/': editable,
|
||||||
|
|
||||||
|
// CAN'T DO: Alt + e, d, f, l
|
||||||
|
|
||||||
|
// ArrowUp: scroll.up, 'Shift+ArrowUp': scroll.up,
|
||||||
|
// ArrowDown: scroll.down, 'Shift+ArrowDown': scroll.down,
|
||||||
|
|
||||||
|
// PageUp: {desc: 'scroll page up', fn: yScroll(-1)},
|
||||||
|
// PageDown: {desc: 'scroll page down', fn: yScroll(1)},
|
||||||
|
|
||||||
|
nop: { fn: () => false }
|
||||||
|
};
|
23
src/hook/wave-view/lister.js
Normal file
23
src/hook/wave-view/lister.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
const trace = {};
|
||||||
|
let tail = '';
|
||||||
|
return {
|
||||||
|
onChunk: (chunk) => {
|
||||||
|
const rows = (tail + chunk).split('\n');
|
||||||
|
// console.log('chunk:', chunk.length, 'tail:', tail.length, 'rows:', rows.length);
|
||||||
|
tail = rows.pop();
|
||||||
|
rows.map(row => {
|
||||||
|
const m = row.match(/\s*([0-9a-f]+):\s*([0-9a-f]+)\s+(.+)/);
|
||||||
|
if (m) {
|
||||||
|
const pc = parseInt(m[1], 16);
|
||||||
|
const op = m[2];
|
||||||
|
const asm = m[3].replace(/\t/, ' ');
|
||||||
|
trace[pc] = {op, asm};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getTrace: () => trace
|
||||||
|
};
|
||||||
|
};
|
46
src/hook/wave-view/mount-tree.js
Normal file
46
src/hook/wave-view/mount-tree.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const defaultElemento = {
|
||||||
|
container: ['div', { class: 'wd-container', id: 'wd-container' }],
|
||||||
|
grid: ['div', { class: 'wd-grid', id: 'wd-grid' }],
|
||||||
|
view0: ['div', { class: 'wd-view', id: 'wd-view' }],
|
||||||
|
values: ['div', { class: 'wd-values', id: 'wd-values' }],
|
||||||
|
cursor: ['div', { class: 'wd-cursor', id: 'wd-cursor' }],
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultLayers = [
|
||||||
|
'grid',
|
||||||
|
'view0',
|
||||||
|
'values',
|
||||||
|
'cursor'
|
||||||
|
];
|
||||||
|
|
||||||
|
const createElemento = elemento => {
|
||||||
|
const names = Object.keys(elemento);
|
||||||
|
return names.reduce((res, name) => {
|
||||||
|
const ml = elemento[name];
|
||||||
|
const el = document.createElement(ml[0]);
|
||||||
|
const attr = (typeof ml[1] === 'object') ? ml[1] : {};
|
||||||
|
Object.keys(attr).map(key => {
|
||||||
|
if (key === 'class') {
|
||||||
|
el.classList.add(attr.class);
|
||||||
|
} else {
|
||||||
|
el.setAttribute(key, attr[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
res[name] = el;
|
||||||
|
return res;
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const createContainer = (els, layers) => {
|
||||||
|
layers.map(layer => els.container.appendChild(els[layer]));
|
||||||
|
return els.container;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.defaultElemento = defaultElemento;
|
||||||
|
exports.defaultLayers = defaultLayers;
|
||||||
|
exports.createElemento = createElemento;
|
||||||
|
exports.createContainer = createContainer;
|
||||||
|
|
||||||
|
/* eslint-env browser */
|
121
src/hook/wave-view/page-format.js
Normal file
121
src/hook/wave-view/page-format.js
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const onml = require('onml');
|
||||||
|
const format = require('./format');
|
||||||
|
|
||||||
|
const getElement = divName => {
|
||||||
|
if (typeof divName === 'string') {
|
||||||
|
const c = document.getElementById(divName);
|
||||||
|
if (c === null) {
|
||||||
|
throw new Error('<div> element width Id: "' + divName + '" not found');
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return divName;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fp64_2bigint = (val) => {
|
||||||
|
const buf = new ArrayBuffer(8);
|
||||||
|
const bufFloat = new Float64Array(buf);
|
||||||
|
const bufBInt = new BigInt64Array(buf);
|
||||||
|
bufFloat[0] = val;
|
||||||
|
return bufBInt[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
const fp32_2bigint = (val) => {
|
||||||
|
const buf = new ArrayBuffer(8);
|
||||||
|
const bufFloat = new Float32Array(buf);
|
||||||
|
const bufUInt = new BigInt64Array(buf);
|
||||||
|
bufFloat[0] = val;
|
||||||
|
return bufUInt[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
const rnda = 40 * (Math.random() - 0.5);
|
||||||
|
|
||||||
|
const specs = [
|
||||||
|
{fmt: '%b', val: 255n, len: 24},
|
||||||
|
{fmt: '%o', val: 255n, len: 24},
|
||||||
|
{fmt: '%d', val: 255n, len: 24},
|
||||||
|
{fmt: '%h', val: 255n, len: 24},
|
||||||
|
{fmt: '%b', val: 12345678n, len: 16},
|
||||||
|
{fmt: '%o', val: 12345678n, len: 16},
|
||||||
|
{fmt: '%d', val: 12345678n, len: 16},
|
||||||
|
{fmt: '%h', val: 12345678n, len: 16},
|
||||||
|
{fmt: '%b', val: fp32_2bigint(rnda), len: 32},
|
||||||
|
{fmt: '%o', val: fp32_2bigint(rnda), len: 32},
|
||||||
|
{fmt: '%d', val: fp32_2bigint(rnda), len: 32},
|
||||||
|
{fmt: '%h', val: fp32_2bigint(rnda), len: 32},
|
||||||
|
{fmt: '%sb', val: 12345678n, len: 24},
|
||||||
|
{fmt: '%so', val: 12345678n, len: 24},
|
||||||
|
{fmt: '%sd', val: 12345678n, len: 24},
|
||||||
|
{fmt: '%sh', val: 12345678n, len: 24},
|
||||||
|
{fmt: '%sb', val: 255n, len: 16},
|
||||||
|
{fmt: '%so', val: 255n, len: 16},
|
||||||
|
{fmt: '%sd', val: 255n, len: 16},
|
||||||
|
{fmt: '%sh', val: 255n, len: 16},
|
||||||
|
{fmt: '%sb', val: 12345678n, len: 25},
|
||||||
|
{fmt: '%so', val: 12345678n, len: 25},
|
||||||
|
{fmt: '%sd', val: 12345678n, len: 25},
|
||||||
|
{fmt: '%sh', val: 12345678n, len: 25},
|
||||||
|
|
||||||
|
{fmt: '%b8', val: 12345678n, len: 24},
|
||||||
|
{fmt: '%o8', val: 12345678n, len: 24},
|
||||||
|
{fmt: '%d8', val: 12345678n, len: 24},
|
||||||
|
{fmt: '%h8', val: 12345678n, len: 24},
|
||||||
|
{fmt: '%h8', val: 0x4142434445n, len: 40},
|
||||||
|
|
||||||
|
{fmt: '%a', val: 0x4142434445n, len: 40},
|
||||||
|
|
||||||
|
{fmt: '%f64', val: -0x27c0aad9be68b8fbn, len: 64},
|
||||||
|
{fmt: '%e64', val: -0x27c0aad9be68b8fbn, len: 64},
|
||||||
|
{fmt: '%f64', val: -0x3d23edde7c882195n, len: 64},
|
||||||
|
{fmt: '%e64', val: -0x3d23edde7c882195n, len: 64},
|
||||||
|
{fmt: '%f64', val: 0x3ee9e0fcaf9380fcn, len: 64},
|
||||||
|
{fmt: '%e64', val: 0x3ee9e0fcaf9380fcn, len: 64},
|
||||||
|
{fmt: '%f64', val: 0x405edd2f1a9fbe77n, len: 64},
|
||||||
|
{fmt: '%e64', val: 0x405edd2f1a9fbe77n, len: 64},
|
||||||
|
{fmt: '%f64', val: fp64_2bigint(rnda), len: 64},
|
||||||
|
{fmt: '%e64', val: fp64_2bigint(rnda), len: 64},
|
||||||
|
|
||||||
|
{fmt: '%f32', val: 0x42f6e979n, len: 32},
|
||||||
|
{fmt: '%e32', val: 0x42f6e979n, len: 32},
|
||||||
|
{fmt: '%f32', val: 0x374f07e5n, len: 32},
|
||||||
|
{fmt: '%e32', val: 0x374f07e5n, len: 32},
|
||||||
|
{fmt: '%f32', val: fp32_2bigint(rnda), len: 32},
|
||||||
|
{fmt: '%e32', val: fp32_2bigint(rnda), len: 32},
|
||||||
|
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
const getFmtTable = () => {
|
||||||
|
const poss = [1, 2, 3, 4, 5, 6, 7, 8, 16, 48];
|
||||||
|
const header = [
|
||||||
|
'', 'pos\u2192', ...poss,
|
||||||
|
'\u2B10fmt', '\u2B10len', ...poss.map(e => '*'.repeat(e))
|
||||||
|
].map(e => ['div', {class: 'tab-header'}, e]);
|
||||||
|
const rows = specs.flatMap(spec => [
|
||||||
|
spec.fmt, spec.len,
|
||||||
|
...poss.map(pos => format(spec.fmt, spec.len)(spec.val, pos))
|
||||||
|
].map(e => ['div', {class: 'tab-cell'}, e]));
|
||||||
|
|
||||||
|
const res = ['div', {class: 'tab-container'}, ...header, ...rows];
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBody = () =>
|
||||||
|
['div',
|
||||||
|
['h1', 'WaveQL'],
|
||||||
|
['span', 'WaveQL = Wave Query Language'],
|
||||||
|
['h2', 'Data label formats'],
|
||||||
|
`Text label of multibit values can be formated using one of standard formats.
|
||||||
|
The label may be shortened to fit the space available in waveform.
|
||||||
|
Some examples of labels shown in the table below.`,
|
||||||
|
getFmtTable()
|
||||||
|
];
|
||||||
|
|
||||||
|
global.pageFormat = async (div) => {
|
||||||
|
const root = getElement(div);
|
||||||
|
onml.renderer(root)(getBody());
|
||||||
|
};
|
||||||
|
|
||||||
|
/* eslint-env browser */
|
69
src/hook/wave-view/plugin-render-time-grid.js
Normal file
69
src/hook/wave-view/plugin-render-time-grid.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const genSVG = require('onml/gen-svg.js');
|
||||||
|
const stringify = require('onml/stringify.js');
|
||||||
|
|
||||||
|
const formatTime = require('./format-time.js');
|
||||||
|
const getT = require('./get-t.js');
|
||||||
|
|
||||||
|
const round10 = n =>
|
||||||
|
([
|
||||||
|
/*0 1 2 3 4 5 6 7 8 9 */
|
||||||
|
0, 1, 2, 4, 4, 5, 5, 5, 10, 10,
|
||||||
|
/*10 11 12 13 14 15 16 17 18 19 */
|
||||||
|
10, 10, 10, 15, 15, 15, 15, 20, 20, 20
|
||||||
|
])[Math.round(n)]
|
||||||
|
|| Math.round(n);
|
||||||
|
|
||||||
|
const getTimeGrid = pstate => {
|
||||||
|
const { sidebarWidth, width, height, timescale, xScale, tgcd, xOffset, topBarHeight, botBarHeight } = pstate;
|
||||||
|
const fontHeight = 16;
|
||||||
|
// const timeLineStart = (xOffset * width / 2) |0;
|
||||||
|
|
||||||
|
const timeGrid = ['g', {}];
|
||||||
|
|
||||||
|
const xStartExact = getT(sidebarWidth, pstate);
|
||||||
|
const xFinishExact = getT(width, pstate);
|
||||||
|
const density = 1;
|
||||||
|
const xLines = Math.round(density * width / sidebarWidth);
|
||||||
|
|
||||||
|
const xStep = ((xFinishExact - xStartExact) / xLines);
|
||||||
|
const xExp = Math.pow(10, Math.log10(xStep) |0);
|
||||||
|
const xDelta = round10(xStep / xExp) * xExp;
|
||||||
|
|
||||||
|
const xStart = Math.ceil(xStartExact / xDelta) * xDelta;
|
||||||
|
const xFinish = Math.floor(xFinishExact / xDelta) * xDelta;
|
||||||
|
|
||||||
|
for (let t = xStart; t <= xFinish; t += xDelta) {
|
||||||
|
const x = Math.round(t / tgcd * xScale + xOffset);
|
||||||
|
timeGrid.push(['g', {},
|
||||||
|
['line', {
|
||||||
|
class: 'wd-grid-time',
|
||||||
|
x1: x,
|
||||||
|
x2: x,
|
||||||
|
y2: height
|
||||||
|
}],
|
||||||
|
['text', {
|
||||||
|
class: 'wd-grid-time',
|
||||||
|
x: x,
|
||||||
|
y: (topBarHeight + fontHeight) / 2
|
||||||
|
}, formatTime(t, timescale)],
|
||||||
|
['text', {
|
||||||
|
class: 'wd-grid-time',
|
||||||
|
x: x,
|
||||||
|
y: height - (botBarHeight - fontHeight) / 2
|
||||||
|
}, formatTime(t, timescale)]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeGrid;
|
||||||
|
};
|
||||||
|
|
||||||
|
const pluginRenderTimeGrid = (desc, pstate, els) => {
|
||||||
|
const {width, height} = pstate;
|
||||||
|
const ml = genSVG(width, height);
|
||||||
|
ml.push(getTimeGrid(pstate));
|
||||||
|
els.grid.innerHTML = stringify(ml);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = pluginRenderTimeGrid;
|
16
src/hook/wave-view/plugin-render-values.js
Normal file
16
src/hook/wave-view/plugin-render-values.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const renderValues = require('./render-values.js');
|
||||||
|
|
||||||
|
const pluginRenderValues = (desc, pstate, els) => {
|
||||||
|
const gen = renderValues(desc, pstate);
|
||||||
|
for (let i = 0; i < 1e6; i++) {
|
||||||
|
const iter = gen.next();
|
||||||
|
if (iter.done) {
|
||||||
|
els.values.innerHTML = iter.value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = pluginRenderValues;
|
56
src/hook/wave-view/render-cursor.js
Normal file
56
src/hook/wave-view/render-cursor.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const genSVG = require('onml/gen-svg.js');
|
||||||
|
const stringify = require('onml/stringify.js');
|
||||||
|
const formatTime = require('./format-time.js');
|
||||||
|
|
||||||
|
const renderCursor = (cfg, pstate) => {
|
||||||
|
const { xmargin, fontWidth, fontHeight } = cfg;
|
||||||
|
const { height, xScale, xOffset, tgcd, timescale, xCursor } = pstate;
|
||||||
|
|
||||||
|
const xx = Math.round((xCursor - xOffset) / xScale) * tgcd;
|
||||||
|
const label = formatTime(xx, timescale);
|
||||||
|
const lWidth = (label.length + 1) * fontWidth;
|
||||||
|
|
||||||
|
const body = [
|
||||||
|
// vertical line
|
||||||
|
['line', {
|
||||||
|
class: 'wd-cursor-line',
|
||||||
|
x1: xmargin + 0.5,
|
||||||
|
x2: xmargin + 0.5,
|
||||||
|
y1: 0,
|
||||||
|
y2: height
|
||||||
|
}],
|
||||||
|
// top time label
|
||||||
|
['rect', {
|
||||||
|
class: 'wd-cursor-time',
|
||||||
|
x: xmargin - lWidth / 2,
|
||||||
|
y: 0,
|
||||||
|
rx: 9,
|
||||||
|
ry: 9,
|
||||||
|
width: lWidth,
|
||||||
|
height: fontHeight * 1.25
|
||||||
|
}],
|
||||||
|
['text', {
|
||||||
|
class: 'wd-cursor-time',
|
||||||
|
x: xmargin,
|
||||||
|
y: fontHeight
|
||||||
|
}, label],
|
||||||
|
// bottom time label
|
||||||
|
['rect', {
|
||||||
|
class: 'wd-cursor-time',
|
||||||
|
x: xmargin - lWidth / 2,
|
||||||
|
y: height - fontHeight * 1.25,
|
||||||
|
width: lWidth,
|
||||||
|
height: fontHeight * 1.25
|
||||||
|
}],
|
||||||
|
['text', {
|
||||||
|
class: 'wd-cursor-time',
|
||||||
|
x: xmargin,
|
||||||
|
y: height - fontHeight * .25
|
||||||
|
}, label]
|
||||||
|
];
|
||||||
|
return stringify(genSVG(2 * xmargin, height).concat(body));
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = renderCursor;
|
127
src/hook/wave-view/render-values.js
Normal file
127
src/hook/wave-view/render-values.js
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const tt = require('onml/tt.js');
|
||||||
|
const genSVG = require('onml/gen-svg.js');
|
||||||
|
const stringify = require('onml/stringify.js');
|
||||||
|
// const getPco = require('./get-pco.js');
|
||||||
|
const water = require('./water.js');
|
||||||
|
const bracer = require('./bracer.js');
|
||||||
|
const vline = require('./vline.js');
|
||||||
|
const getX = require('./get-x.js');
|
||||||
|
const vlineStylo = require('./vline-stylo.js');
|
||||||
|
const getLabel = require('./get-label.js');
|
||||||
|
|
||||||
|
const defs = ['defs',
|
||||||
|
['linearGradient', {id: 'valid'},
|
||||||
|
['stop', {offset: '30%', 'stop-color': 'hsla(100, 100%, 100%, 0)'}],
|
||||||
|
['stop', {offset: '90%', 'stop-color': 'hsla(100, 100%, 100%, .3)'}]
|
||||||
|
],
|
||||||
|
['linearGradient', {id: 'valid&ready'},
|
||||||
|
['stop', {offset: '30%', 'stop-color': 'hsla(100, 100%, 50%, 0)'}],
|
||||||
|
['stop', {offset: '90%', 'stop-color': 'hsla(100, 100%, 50%, .5)'}]
|
||||||
|
],
|
||||||
|
['linearGradient', {id: 'valid&~ready'},
|
||||||
|
['stop', {offset: '30%', 'stop-color': 'hsla(50, 100%, 50%, 0)'}],
|
||||||
|
['stop', {offset: '90%', 'stop-color': 'hsla(50, 100%, 50%, .5)'}]
|
||||||
|
],
|
||||||
|
...Object.keys(vlineStylo).map(key => {
|
||||||
|
const e = vlineStylo[key];
|
||||||
|
return ['filter', {id: 'neonGlow-' + key, width: 7, x: -3},
|
||||||
|
['feGaussianBlur', {stdDeviation: 3, in: 'SourceAlpha', result: 'ablur'}],
|
||||||
|
['feFlood', {'flood-color': `hsl(${e.h},100%,${e.l}%)`, result: 'xf'}],
|
||||||
|
['feComposite', {in: 'xf', in2: 'ablur', operator: 'in'}]
|
||||||
|
];
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
const renderValues = function* (desc, pstate) {
|
||||||
|
const { width, height, sidebarWidth, yOffset, yStep, topBarHeight, botBarHeight } = pstate;
|
||||||
|
const { view } = desc;
|
||||||
|
|
||||||
|
const ilen = height / yStep;
|
||||||
|
const iskip = yOffset / yStep;
|
||||||
|
|
||||||
|
// console.log(iskip, ilen, view.length);
|
||||||
|
|
||||||
|
const ml = genSVG(width, height - topBarHeight - botBarHeight);
|
||||||
|
|
||||||
|
let ifirst = 0;
|
||||||
|
for (let i = 0; i < ilen; i += 1) {
|
||||||
|
const lane = view[i];
|
||||||
|
if (lane && (lane.name || lane.kind)) {
|
||||||
|
if (i > iskip) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ifirst = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ml.push(defs);
|
||||||
|
yield;
|
||||||
|
|
||||||
|
const markers = ['g'];
|
||||||
|
ml.push(markers);
|
||||||
|
|
||||||
|
for (let i = 0; i < (iskip + ilen); i++) {
|
||||||
|
const lane = view[i + (ifirst |0)];
|
||||||
|
|
||||||
|
if (lane && lane.kind === 'DIZ') {
|
||||||
|
markers.push(['g', tt(0, Math.round((i - (iskip - ifirst) + 1.18) * yStep))].concat(water(lane, desc, pstate)));
|
||||||
|
} else
|
||||||
|
|
||||||
|
if (lane && lane.kind === 'brace') {
|
||||||
|
markers.push(['g', tt(0, Math.round((i - (iskip - ifirst) + 1.18) * yStep))].concat(bracer(lane, desc, pstate)));
|
||||||
|
} else
|
||||||
|
|
||||||
|
if (lane && lane.ref) {
|
||||||
|
const chango = desc.chango[lane.ref];
|
||||||
|
if (chango && chango.kind === 'vec') {
|
||||||
|
const mLane = ['g', tt(0, Math.round((i - (iskip - ifirst) + .9) * yStep))];
|
||||||
|
const { wave } = chango;
|
||||||
|
const jlen = wave.length;
|
||||||
|
|
||||||
|
perLane: {
|
||||||
|
let [tPre, vPre, mPre] = wave[0];
|
||||||
|
let xPre = getX(pstate, tPre);
|
||||||
|
const labeler = getLabel(lane);
|
||||||
|
for (let j = 1; j <= jlen; j++) {
|
||||||
|
const mark = wave[j];
|
||||||
|
const [tCur, vCur, mCur] = (mark || [desc.time, 0, 0]);
|
||||||
|
const xCur = getX(pstate, tCur);
|
||||||
|
if (vPre || mPre) {
|
||||||
|
if (xPre > width && xCur > width) { // both time stamps to the right
|
||||||
|
break perLane;
|
||||||
|
}
|
||||||
|
if (!((xPre < sidebarWidth) && (xCur < sidebarWidth))) { // both time stamps to the left
|
||||||
|
const xPreNorm = ((xPre > sidebarWidth) ? xPre : sidebarWidth) |0;
|
||||||
|
const xCurNorm = ((xCur < width) ? xCur : width) |0;
|
||||||
|
const w = xCurNorm - xPreNorm;
|
||||||
|
if (w > 8) {
|
||||||
|
const x = Math.round((xPreNorm + xCurNorm) / 2);
|
||||||
|
mLane.push(labeler(vPre, mPre, x, w));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xPre = xCur;
|
||||||
|
vPre = vCur;
|
||||||
|
mPre = mCur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ml.push(mLane);
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(view);
|
||||||
|
for (let i = 0; i < view.length; i++) {
|
||||||
|
const lane = view[i];
|
||||||
|
if (lane && lane.vlines) {
|
||||||
|
markers.push(...vline(lane, pstate, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield;
|
||||||
|
return stringify(ml);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = renderValues;
|
||||||
|
/* eslint complexity: [1, 55] */
|
22
src/hook/wave-view/sampler.js
Normal file
22
src/hook/wave-view/sampler.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
function* sampler (wave) {
|
||||||
|
let t1, v0, v1;
|
||||||
|
[t1, v1] = wave[0]; // initial state
|
||||||
|
let t = 0;
|
||||||
|
for (let i = 1; i < wave.length; i++) {
|
||||||
|
v0 = v1;
|
||||||
|
[t1, v1] = wave[i]; // next change
|
||||||
|
while (true) {
|
||||||
|
if (t >= t1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t = yield v0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(true) { // to the end of time
|
||||||
|
yield v1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = sampler;
|
24
src/hook/wave-view/surferer.js
Normal file
24
src/hook/wave-view/surferer.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const getT = require('./get-t.js');
|
||||||
|
|
||||||
|
function* surferer (wave, pstate) {
|
||||||
|
const { sidebarWidth, width } = pstate;
|
||||||
|
const xStartExact = getT(sidebarWidth, pstate);
|
||||||
|
const xFinishExact = getT(width, pstate);
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
for (i = 0; i < wave.length; i++) { // seek to the start of viewport
|
||||||
|
if ((wave[i] === undefined) || (wave[i][0] >= xStartExact)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i < wave.length; i++) { // render viewport
|
||||||
|
if ((wave[i] === undefined) || (wave[i][0] > xFinishExact)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
yield i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = surferer;
|
14
src/hook/wave-view/vline-stylo.js
Normal file
14
src/hook/wave-view/vline-stylo.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const vlineStylo = {
|
||||||
|
w: {h:0, l:100}, // w
|
||||||
|
r: {h:10, l:45}, // r
|
||||||
|
o: {h:33, l:65}, // o
|
||||||
|
y: {h:55, l:50}, // y
|
||||||
|
g: {h:120, l:75}, // g
|
||||||
|
c: {h:190, l:50}, // c
|
||||||
|
b: {h:215, l:70}, // b
|
||||||
|
v: {h:280, l:55} // v
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = vlineStylo;
|
57
src/hook/wave-view/vline.js
Normal file
57
src/hook/wave-view/vline.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const getX = require('./get-x.js');
|
||||||
|
const onml = require('onml');
|
||||||
|
const vlineStylo = require('./vline-stylo.js');
|
||||||
|
|
||||||
|
/* Zones
|
||||||
|
1 2 3
|
||||||
|
4 5 6
|
||||||
|
7 8 9
|
||||||
|
*/
|
||||||
|
|
||||||
|
const vline = (lane, pstate, i) => {
|
||||||
|
const {width, height, timescale, yStep, yOffset, topBarHeight, botBarHeight} = pstate;
|
||||||
|
const y = (i + .7) * yStep - yOffset;
|
||||||
|
const yMax = height - topBarHeight - botBarHeight;
|
||||||
|
|
||||||
|
return lane.vlines.map(vline => {
|
||||||
|
const t = vline.value * Math.pow(10, vline.mult - timescale);
|
||||||
|
const x = Math.round(getX(pstate, t));
|
||||||
|
const style = (vlineStylo[vline.style] || vlineStylo.w);
|
||||||
|
const color = `hsl(${style.h},100%,${style.l}%)`;
|
||||||
|
const symbol = ['path', {style: 'stroke-width: 1px; stroke: ' + color}];
|
||||||
|
|
||||||
|
if ((x < 0) || (x > width)) {
|
||||||
|
if ((y < 0) || (y > yMax)) { // Zones: 1, 7, 3, 9
|
||||||
|
return ['g'];
|
||||||
|
}
|
||||||
|
if (x < 0) { // Zone: 4
|
||||||
|
symbol[1].d = `M ${0} ${y} l 8 -4 v 8 z`;
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
// Zone: 6
|
||||||
|
symbol[1].d = `M ${width - 16} ${y} l -8 -4 v 8 z`;
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
const line = ['g', onml.tt(x, 0),
|
||||||
|
['rect', {x: -1, width: 3, height, fill: '#fff', filter: 'url(#neonGlow-' + vline.style + ')'}],
|
||||||
|
['rect', {width: 1, height, fill: color}]
|
||||||
|
];
|
||||||
|
|
||||||
|
if (y < 0) { // Zone: 2
|
||||||
|
symbol[1].d = `M ${x} ${topBarHeight} l 4 8 h -8 z`;
|
||||||
|
return ['g', line, symbol];
|
||||||
|
}
|
||||||
|
if (y > yMax) { // Zone: 8
|
||||||
|
symbol[1].d = `M ${x} ${yMax} l -4 -8 h 8 z`;
|
||||||
|
return ['g', line, symbol];
|
||||||
|
}
|
||||||
|
// Zone: 5
|
||||||
|
symbol[1].d = `M ${x} ${y} m-4 0 l 4 -4 l 4 4 l -4 4 z`;
|
||||||
|
return ['g', line, symbol];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = vline;
|
140
src/hook/wave-view/water.js
Normal file
140
src/hook/wave-view/water.js
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// PC based pipeline view
|
||||||
|
|
||||||
|
const tt = require('onml/tt.js');
|
||||||
|
const getX = require('./get-x.js');
|
||||||
|
const surferer = require('./surferer.js');
|
||||||
|
const sampler = require('./sampler.js');
|
||||||
|
const hash = require('./hash.js');
|
||||||
|
|
||||||
|
const pushBrick = (listing, pco, v, name, label, t) => {
|
||||||
|
let pc = v;
|
||||||
|
let tail = false;
|
||||||
|
let le = listing[pc];
|
||||||
|
if (le === undefined) {
|
||||||
|
pc = v - 2;
|
||||||
|
le = listing[pc];
|
||||||
|
tail = true;
|
||||||
|
}
|
||||||
|
if (le) {
|
||||||
|
if (pco[pc] === undefined) {
|
||||||
|
pco[pc] = {op: le.op, asm: le.asm, bricks: []};
|
||||||
|
}
|
||||||
|
pco[pc].bricks.push({name, label, t, tail});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const progress = (lane, desc, pstate) => {
|
||||||
|
const pco = {};
|
||||||
|
|
||||||
|
const { listing } = desc;
|
||||||
|
const { clock, othero } = lane;
|
||||||
|
|
||||||
|
|
||||||
|
if (desc.chango[clock.ref] === undefined) {
|
||||||
|
console.log(desc.chango, clock, clock.ref);
|
||||||
|
return pco;
|
||||||
|
}
|
||||||
|
const clockWave = desc.chango[clock.ref].wave;
|
||||||
|
const clockEr = surferer(clockWave, pstate);
|
||||||
|
|
||||||
|
// create samplers
|
||||||
|
for (const id of Object.keys(othero)) {
|
||||||
|
['pc', 'go'].map(role => {
|
||||||
|
const obj = othero[id][role];
|
||||||
|
obj.sampler = sampler(desc.chango[obj.ref].wave);
|
||||||
|
obj.sampler.next(0); // dry run
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let count = 8000; // max number of pipeline bricks
|
||||||
|
|
||||||
|
outerLoop: for (const iClock of clockEr) {
|
||||||
|
const [tClock, vClock] = clockWave[iClock];
|
||||||
|
if (vClock) {
|
||||||
|
for (const key of Object.keys(othero)) {
|
||||||
|
const id = othero[key];
|
||||||
|
const go = id.go.sampler.next(tClock).value;
|
||||||
|
const pc = id.pc.sampler.next(tClock).value;
|
||||||
|
const KEY = key.toUpperCase();
|
||||||
|
if (go) {
|
||||||
|
pushBrick(listing, pco, pc, KEY, KEY, tClock);
|
||||||
|
if (count-- === 0) {
|
||||||
|
break outerLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [idx, key] of Object.keys(pco).entries()) {
|
||||||
|
if (pco[key] !== undefined) {
|
||||||
|
pco[key].idx = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pco;
|
||||||
|
};
|
||||||
|
|
||||||
|
const water = (lane, desc, pstate) => {
|
||||||
|
const { width, yStep } = pstate;
|
||||||
|
const brickWidth = getX(pstate, 2) - getX(pstate, 0);
|
||||||
|
|
||||||
|
const pco = progress(lane, desc, pstate);
|
||||||
|
|
||||||
|
const pcs = Object.keys(pco).map(e => Number(e)).sort();
|
||||||
|
|
||||||
|
const mLanes = [];
|
||||||
|
|
||||||
|
// const pco = getPco(desc, pstate, lane); // signals, dats, cycles, listing, state.cursor);
|
||||||
|
for (let j = 0; j < lane.len - 2; j++) {
|
||||||
|
const pc = pcs[j];
|
||||||
|
const pcd = pco[pc];
|
||||||
|
if (pc === undefined || pcd === undefined) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const asm = pcd.asm.replace(/<.+>/, '\u25C6');
|
||||||
|
const mLane = ['g', tt(0, Math.round(j * yStep))];
|
||||||
|
|
||||||
|
// striped background
|
||||||
|
if (j & 1) {
|
||||||
|
mLane.push(['rect', {width: width, height: yStep - 1, class: 'pc-odd'}]);
|
||||||
|
// ['rect', {width: width, height: yStep - 2, class: (j & 1) ? 'pc-odd' : 'pc-even'}],
|
||||||
|
}
|
||||||
|
|
||||||
|
// dotted separator
|
||||||
|
if ((j > 0) && (pc - pcs[j - 1] > 4)) {
|
||||||
|
mLane.push(['line', {class: 'gap', x1: 0, y1: 0, x2: width, y2: 0}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// row header
|
||||||
|
mLane.push(['text', {class: 'pc', 'xml:space': 'preserve', y: Math.round(yStep * .7)},
|
||||||
|
['tspan', {class: 'pc-addr'}, parseInt(pc, 10).toString(16).padStart(12, ' ')],
|
||||||
|
['tspan', {class: 'pc-opcode'}, pcd.op.padStart(9, ' ')],
|
||||||
|
' ',
|
||||||
|
['tspan', {class: 'pc-asm'}, asm]
|
||||||
|
]);
|
||||||
|
|
||||||
|
// bricks in row
|
||||||
|
pcd.bricks.map(e => {
|
||||||
|
mLane.push(['g', tt(Math.round(getX(pstate, e.t))),
|
||||||
|
['rect', {
|
||||||
|
class: (e.label === '') ? e.name : 'ct' + hash(e.name).toString(36),
|
||||||
|
width: brickWidth,
|
||||||
|
height: (e.tail ? (yStep >> 1) : yStep) - 3,
|
||||||
|
y: e.tail ? ((yStep >> 1) + 1) : 1,
|
||||||
|
'data-stage': e.label
|
||||||
|
}],
|
||||||
|
...((brickWidth > 20) ? [['text', {class: e.name, width: brickWidth, x: brickWidth / 2, y: 16}, e.label]] : [])
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
mLanes.push(mLane);
|
||||||
|
}
|
||||||
|
return mLanes;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = water;
|
202
src/hook/wave-view/waveql.js
Normal file
202
src/hook/wave-view/waveql.js
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const get = require('lodash.get');
|
||||||
|
|
||||||
|
const diz = (cols, wires, path, rowIdx) => {
|
||||||
|
if (cols[0] !== 'DIZ') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const levelo = get(wires, path, false);
|
||||||
|
const arg1 = cols[1]; // pipeline stages
|
||||||
|
|
||||||
|
// find all potential candidates
|
||||||
|
const othero0 = Object.keys(levelo).reduce((res, name) => {
|
||||||
|
const m = name.match(arg1);
|
||||||
|
if (m) {
|
||||||
|
const {id, pc, go} = m.groups;
|
||||||
|
const stage = res[id] = (res[id] || {});
|
||||||
|
const desc = {name, ref: levelo[name]};
|
||||||
|
if (pc) {
|
||||||
|
stage[pc] = desc;
|
||||||
|
} else
|
||||||
|
if (go) {
|
||||||
|
stage[go] = desc;
|
||||||
|
} else {
|
||||||
|
console.log(desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
// filter out singles
|
||||||
|
const othero = Object.keys(othero0).reduce((res, name) => {
|
||||||
|
const val = othero0[name];
|
||||||
|
if (val.pc && val.go) {
|
||||||
|
res[name] = val;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return {kind: 'DIZ', idx: rowIdx, othero, clock: {name: 'clock', ref: levelo.clock}};
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.parser = wires => str => {
|
||||||
|
const arr = str.split('\n');
|
||||||
|
const path = [];
|
||||||
|
const labelo = {};
|
||||||
|
let nRow;
|
||||||
|
let mat;
|
||||||
|
|
||||||
|
const res = arr.map((row, rowIdx) => {
|
||||||
|
row = row.trim();
|
||||||
|
|
||||||
|
// Section with Parentheses
|
||||||
|
|
||||||
|
if (row[0] === '(') {
|
||||||
|
const cols = row.slice(1).split(/\s+/);
|
||||||
|
const res = diz(cols, wires, path, rowIdx); // || other commands
|
||||||
|
if (res) {
|
||||||
|
nRow = res;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row[0] === ')') {
|
||||||
|
if (nRow !== undefined) {
|
||||||
|
nRow.len = rowIdx - nRow.idx + 1;
|
||||||
|
nRow = undefined;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowo = {};
|
||||||
|
const cols = row.split(/\s+/);
|
||||||
|
cols.map(col => {
|
||||||
|
if (col === '...') { path.pop(); path.pop(); return; }
|
||||||
|
if (col === '..') { path.pop(); return; }
|
||||||
|
if (col === '.') { return; }
|
||||||
|
if (col === '/') { path.length = 0; return; }
|
||||||
|
|
||||||
|
mat = col.match(/^:(\S+)$/); if (mat) {
|
||||||
|
labelo[mat[1]] = rowo;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat = col.match(/^(\{)([^}]+)(\})$/); if (mat) {
|
||||||
|
const a = mat[2];
|
||||||
|
const b = a.split(',');
|
||||||
|
rowo.kind = 'brace';
|
||||||
|
rowo.body = b.reduce((res, e) => {
|
||||||
|
const ee = e.split(':');
|
||||||
|
if (ee.length === 2) {
|
||||||
|
const key = ee[0];
|
||||||
|
const val = labelo[ee[1]] || Number(ee[1]);
|
||||||
|
res[key] = val;
|
||||||
|
} else
|
||||||
|
if (ee.length === 1) {
|
||||||
|
res[ee[0]] = labelo[ee[0]] || {};
|
||||||
|
} else {
|
||||||
|
console.error(ee);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}, {});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat = col.match(/^%([<>^])?([+-])?([su])?([bodhHac])$/); if (mat) {
|
||||||
|
rowo.format = {
|
||||||
|
align: mat[1],
|
||||||
|
plus: mat[2],
|
||||||
|
sign: mat[3],
|
||||||
|
radix: mat[4]
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newPath = path.concat(col);
|
||||||
|
const ref = get(wires, newPath, false);
|
||||||
|
|
||||||
|
if (typeof ref === 'string') {
|
||||||
|
rowo.name = col;
|
||||||
|
rowo.ref = ref;
|
||||||
|
} else
|
||||||
|
if (typeof ref === 'object') {
|
||||||
|
path.push(col);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return rowo;
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.cmMode = function(CodeMirror, desc) {
|
||||||
|
const { wires } = desc;
|
||||||
|
CodeMirror.defineMode('waveql', function() {
|
||||||
|
return {
|
||||||
|
startState: function() {
|
||||||
|
return {path: []};
|
||||||
|
},
|
||||||
|
token: function (stream, stt) {
|
||||||
|
// const line = stream.lineOracle.line;
|
||||||
|
let mat;
|
||||||
|
|
||||||
|
if (stream.eatSpace()) { return null; }
|
||||||
|
|
||||||
|
mat = stream.match(/^\.\.\.(\s+|$)/); if (mat) { stt.path.pop(); stt.path.pop(); return 'punct'; }
|
||||||
|
mat = stream.match(/^\.\.(\s+|$)/); if (mat) { stt.path.pop(); return 'punct'; }
|
||||||
|
mat = stream.match(/^\.(\s+|$)/); if (mat) { return 'punct'; }
|
||||||
|
mat = stream.match(/^\/(\s+|$)/); if (mat) { stt.path.length = 0; return 'punct'; }
|
||||||
|
|
||||||
|
mat = stream.match(/^:(\S+)(\s+|$)/); if (mat) {
|
||||||
|
return 'label';
|
||||||
|
}
|
||||||
|
|
||||||
|
mat = stream.match(/^\{[^}]+\}(\s+|$)/); if (mat) {
|
||||||
|
return 'mark';
|
||||||
|
}
|
||||||
|
|
||||||
|
mat = stream.match(/^%([<>^])?([+-])?([su])?([bodhHac])(\s+|$)/); if (mat) {
|
||||||
|
return 'format';
|
||||||
|
}
|
||||||
|
|
||||||
|
mat = stream.match(/^(\S+)(\s+|$)/); if (mat) {
|
||||||
|
const sigName = mat[1];
|
||||||
|
const newPath = stt.path.concat(sigName);
|
||||||
|
const ref = get(wires, newPath, false);
|
||||||
|
if (typeof ref === 'string') {
|
||||||
|
return 'signal';
|
||||||
|
}
|
||||||
|
if (typeof ref === 'object') {
|
||||||
|
stt.path = newPath;
|
||||||
|
return 'path';
|
||||||
|
}
|
||||||
|
return 'comment';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
CodeMirror.defineMIME('text/x-waveql', 'waveql');
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.cmHint = (CodeMirror, desc) => {
|
||||||
|
const { wires } = desc;
|
||||||
|
return async (cm /*, options */) => {
|
||||||
|
const cursor = cm.getCursor();
|
||||||
|
const token = cm.getTokenAt(cursor);
|
||||||
|
const line = cm.getLine(cursor.line);
|
||||||
|
let start = cursor.ch;
|
||||||
|
let end = cursor.ch;
|
||||||
|
while (start && /\w/.test(line.charAt(start - 1))) --start;
|
||||||
|
while (end < line.length && /\w/.test(line.charAt(end))) ++end;
|
||||||
|
const cur = token.string.trim();
|
||||||
|
const list = get(wires, token.state.path, {});
|
||||||
|
const alls = ['/', '..'].concat(Object.keys(list));
|
||||||
|
const hints = alls.filter(e => e.match(cur));
|
||||||
|
return {
|
||||||
|
list: hints,
|
||||||
|
from: CodeMirror.Pos(cursor.line, start),
|
||||||
|
to: CodeMirror.Pos(cursor.line, end)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
20
src/hook/wave-view/x-offset-update.js
Normal file
20
src/hook/wave-view/x-offset-update.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const xOffsetUpdate = (pstate, xOffsetNext) => {
|
||||||
|
let {width, xOffset, xScale, time, sidebarWidth} = pstate;
|
||||||
|
|
||||||
|
const xOffsetMax = sidebarWidth; // maximum offset
|
||||||
|
xOffsetNext = (xOffsetNext > xOffsetMax) ? xOffsetMax : xOffsetNext;
|
||||||
|
|
||||||
|
const xOffsetMin = width - xScale * time; // minimum offset
|
||||||
|
xOffsetNext = (xOffsetNext < xOffsetMin) ? xOffsetMin : xOffsetNext;
|
||||||
|
|
||||||
|
if (xOffsetNext === xOffset) {
|
||||||
|
return false; // exit without scroll
|
||||||
|
}
|
||||||
|
|
||||||
|
pstate.xOffset = xOffsetNext;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = xOffsetUpdate;
|
24
src/hook/wave-view/x-scale-update.js
Normal file
24
src/hook/wave-view/x-scale-update.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const xOffsetUpdate = require('./x-offset-update.js');
|
||||||
|
|
||||||
|
const xScaleUpdate = (pstate, xScaleNext) => {
|
||||||
|
const { xOffset, xCursor, xScale, xScaleMin, xScaleMax } = pstate;
|
||||||
|
|
||||||
|
xScaleNext = (xScaleNext > xScaleMax) ? xScaleMax : xScaleNext;
|
||||||
|
|
||||||
|
xScaleNext = (xScaleNext < xScaleMin) ? xScaleMin : xScaleNext;
|
||||||
|
|
||||||
|
console.log('pstate', pstate);
|
||||||
|
console.log('scale next', xScaleNext);
|
||||||
|
|
||||||
|
if (xScaleNext === xScale) {
|
||||||
|
return false; // exit without scale change
|
||||||
|
}
|
||||||
|
pstate.xScale = xScaleNext;
|
||||||
|
|
||||||
|
xOffsetUpdate(pstate, xCursor - (xCursor - xOffset) * xScaleNext / xScale);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = xScaleUpdate;
|
43
src/hook/wheel.js
Normal file
43
src/hook/wheel.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { globalLookup } from './global';
|
||||||
|
|
||||||
|
let changeView = globalLookup.view;
|
||||||
|
const config = {
|
||||||
|
maxScale: 1000,
|
||||||
|
minScale: 0.01,
|
||||||
|
scaleInterval: 0.1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {WheelEvent} event
|
||||||
|
*/
|
||||||
|
function wheelScale(event) {
|
||||||
|
// 鼠标滚轮往下是收缩, 往上是变大
|
||||||
|
if (event.deltaY > 0) {
|
||||||
|
const laterScale = changeView.currentScaleX + config.scaleInterval;
|
||||||
|
if (laterScale <= config.maxScale) {
|
||||||
|
changeView.currentScaleX = laterScale;
|
||||||
|
document.body.style.setProperty('--render-scale-x', laterScale);
|
||||||
|
}
|
||||||
|
} else if (event.deltaY < 0) {
|
||||||
|
const laterScale = changeView.currentScaleX - config.scaleInterval;
|
||||||
|
if (laterScale >= config.minScale) {
|
||||||
|
changeView.currentScaleX = laterScale;
|
||||||
|
document.body.style.setProperty('--render-scale-x', laterScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {WheelEvent} event
|
||||||
|
*/
|
||||||
|
function wheelTranslate(event) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
wheelScale,
|
||||||
|
wheelTranslate
|
||||||
|
};
|
17
test/vertex.glsl
Normal file
17
test/vertex.glsl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#version 300 es
|
||||||
|
in uvec3 pos;
|
||||||
|
out vec4 v_color;
|
||||||
|
uniform vec2 scale;
|
||||||
|
uniform vec2 offset;
|
||||||
|
uniform vec4 colors[16];
|
||||||
|
uniform vec2 tilts[7];
|
||||||
|
uniform float tilt;
|
||||||
|
void main() {
|
||||||
|
v_color = colors[pos.z];
|
||||||
|
vec2 node = tilts[pos.y];
|
||||||
|
gl_Position = vec4(
|
||||||
|
float(pos.x) * scale.x + offset.x + node[1] * tilt,
|
||||||
|
float(node[0]) * scale.y + offset.y,
|
||||||
|
1, 1
|
||||||
|
);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user