初始代码
|
@ -0,0 +1,26 @@
|
|||
# yanduscreen
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Run your tests
|
||||
```
|
||||
npm run test
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
npm run lint
|
||||
```
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
presets: [
|
||||
'@vue/app'
|
||||
]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"name": "yanduscreen",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
||||
"axios": "^1.1.3",
|
||||
"core-js": "^2.6.5",
|
||||
"docx-preview": "^0.1.15",
|
||||
"echarts": "^5.4.0",
|
||||
"element-ui": "^2.15.10",
|
||||
"express": "^4.18.2",
|
||||
"express-ws": "^5.0.2",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"jsmpeg": "^1.0.0",
|
||||
"jszip": "^3.10.1",
|
||||
"less": "^4.1.3",
|
||||
"less-loader": "^5.0.0",
|
||||
"moment": "^2.29.4",
|
||||
"mxdraw": "^0.1.138",
|
||||
"node-cmd": "^5.0.0",
|
||||
"pdfjs-dist": "^2.0.943",
|
||||
"rtsp2web": "^2.2.0",
|
||||
"v-fit-columns": "^0.2.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-jsmpeg-player": "^1.1.0-beta",
|
||||
"vue-pdf": "^4.3.0",
|
||||
"vue-router": "^3.0.3",
|
||||
"vue-video-player": "^5.0.2",
|
||||
"vuex": "^3.0.1",
|
||||
"websocket-stream": "^5.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^3.0.4",
|
||||
"@vue/cli-service": "^3.0.4",
|
||||
"express": "^4.18.2",
|
||||
"express-ws": "^5.0.2",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"websocket-stream": "^5.5.2"
|
||||
},
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
"autoprefixer": {}
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions"
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<!-- <script type="text/javascript" src="../stactic/webrtcstreamer.js"></script>
|
||||
<script type="text/javascript" src="../stactic/adapter.min.js"></script> -->
|
||||
<script src="https://jsmpeg.com/jsmpeg.min.js" charset="utf-8"></script>
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title>yanduscreen</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but yanduscreen doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,305 @@
|
|||
var WebRtcStreamer = (function() {
|
||||
|
||||
/**
|
||||
* Interface with WebRTC-streamer API
|
||||
* @constructor
|
||||
* @param {string} videoElement - id of the video element tag
|
||||
* @param {string} srvurl - url of webrtc-streamer (default is current location)
|
||||
*/
|
||||
var WebRtcStreamer = function WebRtcStreamer (videoElement, srvurl) {
|
||||
if (typeof videoElement === "string") {
|
||||
this.videoElement = document.getElementById(videoElement);
|
||||
} else {
|
||||
this.videoElement = videoElement;
|
||||
}
|
||||
this.srvurl = srvurl || location.protocol+"//"+window.location.hostname+":"+window.location.port;
|
||||
this.pc = null;
|
||||
|
||||
this.mediaConstraints = { offerToReceiveAudio: true, offerToReceiveVideo: true };
|
||||
|
||||
this.iceServers = null;
|
||||
this.earlyCandidates = [];
|
||||
}
|
||||
|
||||
WebRtcStreamer.prototype._handleHttpErrors = function (response) {
|
||||
if (!response.ok) {
|
||||
throw Error(response.statusText);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect a WebRTC Stream to videoElement
|
||||
* @param {string} videourl - id of WebRTC video stream
|
||||
* @param {string} audiourl - id of WebRTC audio stream
|
||||
* @param {string} options - options of WebRTC call
|
||||
* @param {string} stream - local stream to send
|
||||
*/
|
||||
WebRtcStreamer.prototype.connect = function(videourl, audiourl, options, localstream) {
|
||||
this.disconnect();
|
||||
|
||||
// getIceServers is not already received
|
||||
if (!this.iceServers) {
|
||||
console.log("Get IceServers");
|
||||
|
||||
fetch(this.srvurl + "/api/getIceServers")
|
||||
.then(this._handleHttpErrors)
|
||||
.then( (response) => (response.json()) )
|
||||
.then( (response) => this.onReceiveGetIceServers(response, videourl, audiourl, options, localstream))
|
||||
.catch( (error) => this.onError("getIceServers " + error ))
|
||||
|
||||
} else {
|
||||
this.onReceiveGetIceServers(this.iceServers, videourl, audiourl, options, localstream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect a WebRTC Stream and clear videoElement source
|
||||
*/
|
||||
WebRtcStreamer.prototype.disconnect = function() {
|
||||
if (this.videoElement?.srcObject) {
|
||||
this.videoElement.srcObject.getTracks().forEach(track => {
|
||||
track.stop()
|
||||
this.videoElement.srcObject.removeTrack(track);
|
||||
});
|
||||
}
|
||||
if (this.pc) {
|
||||
fetch(this.srvurl + "/api/hangup?peerid=" + this.pc.peerid)
|
||||
.then(this._handleHttpErrors)
|
||||
.catch( (error) => this.onError("hangup " + error ))
|
||||
|
||||
|
||||
try {
|
||||
this.pc.close();
|
||||
}
|
||||
catch (e) {
|
||||
console.log ("Failure close peer connection:" + e);
|
||||
}
|
||||
this.pc = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GetIceServers callback
|
||||
*/
|
||||
WebRtcStreamer.prototype.onReceiveGetIceServers = function(iceServers, videourl, audiourl, options, stream) {
|
||||
this.iceServers = iceServers;
|
||||
this.pcConfig = iceServers || {"iceServers": [] };
|
||||
try {
|
||||
this.createPeerConnection();
|
||||
|
||||
var callurl = this.srvurl + "/api/call?peerid=" + this.pc.peerid + "&url=" + encodeURIComponent(videourl);
|
||||
if (audiourl) {
|
||||
callurl += "&audiourl="+encodeURIComponent(audiourl);
|
||||
}
|
||||
if (options) {
|
||||
callurl += "&options="+encodeURIComponent(options);
|
||||
}
|
||||
|
||||
if (stream) {
|
||||
this.pc.addStream(stream);
|
||||
}
|
||||
|
||||
// clear early candidates
|
||||
this.earlyCandidates.length = 0;
|
||||
|
||||
// create Offer
|
||||
this.pc.createOffer(this.mediaConstraints).then((sessionDescription) => {
|
||||
console.log("Create offer:" + JSON.stringify(sessionDescription));
|
||||
|
||||
this.pc.setLocalDescription(sessionDescription)
|
||||
.then(() => {
|
||||
fetch(callurl, { method: "POST", body: JSON.stringify(sessionDescription) })
|
||||
.then(this._handleHttpErrors)
|
||||
.then( (response) => (response.json()) )
|
||||
.catch( (error) => this.onError("call " + error ))
|
||||
.then( (response) => this.onReceiveCall(response) )
|
||||
.catch( (error) => this.onError("call " + error ))
|
||||
|
||||
}, (error) => {
|
||||
console.log ("setLocalDescription error:" + JSON.stringify(error));
|
||||
});
|
||||
|
||||
}, (error) => {
|
||||
alert("Create offer error:" + JSON.stringify(error));
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
this.disconnect();
|
||||
alert("connect error: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WebRtcStreamer.prototype.getIceCandidate = function() {
|
||||
fetch(this.srvurl + "/api/getIceCandidate?peerid=" + this.pc.peerid)
|
||||
.then(this._handleHttpErrors)
|
||||
.then( (response) => (response.json()) )
|
||||
.then( (response) => this.onReceiveCandidate(response))
|
||||
.catch( (error) => this.onError("getIceCandidate " + error ))
|
||||
}
|
||||
|
||||
/*
|
||||
* create RTCPeerConnection
|
||||
*/
|
||||
WebRtcStreamer.prototype.createPeerConnection = function() {
|
||||
console.log("createPeerConnection config: " + JSON.stringify(this.pcConfig));
|
||||
this.pc = new RTCPeerConnection(this.pcConfig);
|
||||
var pc = this.pc;
|
||||
pc.peerid = Math.random();
|
||||
|
||||
pc.onicecandidate = (evt) => this.onIceCandidate(evt);
|
||||
pc.onaddstream = (evt) => this.onAddStream(evt);
|
||||
pc.oniceconnectionstatechange = (evt) => {
|
||||
console.log("oniceconnectionstatechange state: " + pc.iceConnectionState);
|
||||
if (this.videoElement) {
|
||||
if (pc.iceConnectionState === "connected") {
|
||||
this.videoElement.style.opacity = "1.0";
|
||||
}
|
||||
else if (pc.iceConnectionState === "disconnected") {
|
||||
this.videoElement.style.opacity = "0.25";
|
||||
}
|
||||
else if ( (pc.iceConnectionState === "failed") || (pc.iceConnectionState === "closed") ) {
|
||||
this.videoElement.style.opacity = "0.5";
|
||||
} else if (pc.iceConnectionState === "new") {
|
||||
this.getIceCandidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
pc.ondatachannel = function(evt) {
|
||||
console.log("remote datachannel created:"+JSON.stringify(evt));
|
||||
|
||||
evt.channel.onopen = function () {
|
||||
console.log("remote datachannel open");
|
||||
this.send("remote channel openned");
|
||||
}
|
||||
evt.channel.onmessage = function (event) {
|
||||
console.log("remote datachannel recv:"+JSON.stringify(event.data));
|
||||
}
|
||||
}
|
||||
pc.onicegatheringstatechange = function() {
|
||||
if (pc.iceGatheringState === "complete") {
|
||||
const recvs = pc.getReceivers();
|
||||
|
||||
recvs.forEach((recv) => {
|
||||
if (recv.track && recv.track.kind === "video") {
|
||||
console.log("codecs:" + JSON.stringify(recv.getParameters().codecs))
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
var dataChannel = pc.createDataChannel("ClientDataChannel");
|
||||
dataChannel.onopen = function() {
|
||||
console.log("local datachannel open");
|
||||
this.send("local channel openned");
|
||||
}
|
||||
dataChannel.onmessage = function(evt) {
|
||||
console.log("local datachannel recv:"+JSON.stringify(evt.data));
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Cannor create datachannel error: " + e);
|
||||
}
|
||||
|
||||
console.log("Created RTCPeerConnnection with config: " + JSON.stringify(this.pcConfig) );
|
||||
return pc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RTCPeerConnection IceCandidate callback
|
||||
*/
|
||||
WebRtcStreamer.prototype.onIceCandidate = function (event) {
|
||||
if (event.candidate) {
|
||||
if (this.pc.currentRemoteDescription) {
|
||||
this.addIceCandidate(this.pc.peerid, event.candidate);
|
||||
} else {
|
||||
this.earlyCandidates.push(event.candidate);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log("End of candidates.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WebRtcStreamer.prototype.addIceCandidate = function(peerid, candidate) {
|
||||
fetch(this.srvurl + "/api/addIceCandidate?peerid="+peerid, { method: "POST", body: JSON.stringify(candidate) })
|
||||
.then(this._handleHttpErrors)
|
||||
.then( (response) => (response.json()) )
|
||||
.then( (response) => {console.log("addIceCandidate ok:" + response)})
|
||||
.catch( (error) => this.onError("addIceCandidate " + error ))
|
||||
}
|
||||
|
||||
/*
|
||||
* RTCPeerConnection AddTrack callback
|
||||
*/
|
||||
WebRtcStreamer.prototype.onAddStream = function(event) {
|
||||
console.log("Remote track added:" + JSON.stringify(event));
|
||||
|
||||
this.videoElement.srcObject = event.stream;
|
||||
var promise = this.videoElement.play();
|
||||
if (promise !== undefined) {
|
||||
promise.catch((error) => {
|
||||
console.warn("error:"+error);
|
||||
this.videoElement.setAttribute("controls", true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* AJAX /call callback
|
||||
*/
|
||||
WebRtcStreamer.prototype.onReceiveCall = function(dataJson) {
|
||||
|
||||
console.log("offer: " + JSON.stringify(dataJson));
|
||||
var descr = new RTCSessionDescription(dataJson);
|
||||
this.pc.setRemoteDescription(descr).then(() => {
|
||||
console.log ("setRemoteDescription ok");
|
||||
while (this.earlyCandidates.length) {
|
||||
var candidate = this.earlyCandidates.shift();
|
||||
this.addIceCandidate(this.pc.peerid, candidate);
|
||||
}
|
||||
|
||||
this.getIceCandidate()
|
||||
}
|
||||
, (error) => {
|
||||
console.log ("setRemoteDescription error:" + JSON.stringify(error));
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* AJAX /getIceCandidate callback
|
||||
*/
|
||||
WebRtcStreamer.prototype.onReceiveCandidate = function(dataJson) {
|
||||
console.log("candidate: " + JSON.stringify(dataJson));
|
||||
if (dataJson) {
|
||||
for (var i=0; i<dataJson.length; i++) {
|
||||
var candidate = new RTCIceCandidate(dataJson[i]);
|
||||
|
||||
console.log("Adding ICE candidate :" + JSON.stringify(candidate) );
|
||||
this.pc.addIceCandidate(candidate).then( () => { console.log ("addIceCandidate OK"); }
|
||||
, (error) => { console.log ("addIceCandidate error:" + JSON.stringify(error)); } );
|
||||
}
|
||||
this.pc.addIceCandidate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AJAX callback for Error
|
||||
*/
|
||||
WebRtcStreamer.prototype.onError = function(status) {
|
||||
console.log("onError:" + status);
|
||||
}
|
||||
|
||||
return WebRtcStreamer;
|
||||
})();
|
||||
|
||||
if (typeof window !== 'undefined' && typeof window.document !== 'undefined') {
|
||||
window.WebRtcStreamer = WebRtcStreamer;
|
||||
}
|
||||
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
||||
module.exports = WebRtcStreamer;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{"Keys":["com.unity.services.core.version"],"Values":[{"m_Value":"1.3.1","m_IsReadOnly":true}]}
|
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 175 B |
After Width: | Height: | Size: 96 B |
After Width: | Height: | Size: 109 B |
After Width: | Height: | Size: 74 B |
After Width: | Height: | Size: 84 B |
|
@ -0,0 +1,16 @@
|
|||
body { padding: 0; margin: 0 }
|
||||
#unity-container { position: absolute }
|
||||
#unity-container.unity-desktop { left: 50%; top: 50%; transform: translate(-50%, -50%);height: 100%; width: 100%; overflow: hidden;}
|
||||
#unity-container.unity-mobile { width: 100%; height: 100% }
|
||||
#unity-canvas { background: #231F20;width: 100% !important; height: 100% !important;cursor: default; }
|
||||
.unity-mobile #unity-canvas { width: 100%; height: 100% }
|
||||
#unity-loading-bar { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: none }
|
||||
#unity-logo { width: 154px; height: 130px; background: url('unity-logo-dark.png') no-repeat center }
|
||||
#unity-progress-bar-empty { width: 141px; height: 18px; margin-top: 10px; margin-left: 6.5px; background: url('progress-bar-empty-dark.png') no-repeat center }
|
||||
#unity-progress-bar-full { width: 0%; height: 18px; margin-top: 10px; background: url('progress-bar-full-dark.png') no-repeat center }
|
||||
#unity-footer { position: relative }
|
||||
.unity-mobile #unity-footer { display: none }
|
||||
#unity-webgl-logo { float:left; width: 204px; height: 38px; background: url('webgl-logo.png') no-repeat center }
|
||||
#unity-build-title { float: right; margin-right: 10px; line-height: 38px; font-family: arial; font-size: 18px }
|
||||
#unity-fullscreen-button { float: right; width: 38px; height: 38px; background: url('fullscreen-button.png') no-repeat center }
|
||||
#unity-warning { position: absolute; left: 50%; top: 5%; transform: translate(-50%); background: white; padding: 10px; display: none }
|
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 2.9 KiB |
|
@ -0,0 +1,133 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Unity WebGL Player | Yd_ElectricPowerVisualization</title>
|
||||
<link rel="shortcut icon" href="TemplateData/favicon.ico">
|
||||
<link rel="stylesheet" href="TemplateData/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="unity-container" class="unity-desktop">
|
||||
<canvas id="unity-canvas" width=960 height=600></canvas>
|
||||
<div id="unity-loading-bar">
|
||||
<div id="unity-logo"></div>
|
||||
<div id="unity-progress-bar-empty">
|
||||
<div id="unity-progress-bar-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="unity-warning"> </div>
|
||||
<div id="unity-footer">
|
||||
<div id="unity-webgl-logo"></div>
|
||||
<div id="unity-fullscreen-button"></div>
|
||||
<div id="unity-build-title">Yd_ElectricPowerVisualization</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var container = document.querySelector("#unity-container");
|
||||
var canvas = document.querySelector("#unity-canvas");
|
||||
var loadingBar = document.querySelector("#unity-loading-bar");
|
||||
var progressBarFull = document.querySelector("#unity-progress-bar-full");
|
||||
var fullscreenButton = document.querySelector("#unity-fullscreen-button");
|
||||
var warningBanner = document.querySelector("#unity-warning");
|
||||
|
||||
// Shows a temporary message banner/ribbon for a few seconds, or
|
||||
// a permanent error message on top of the canvas if type=='error'.
|
||||
// If type=='warning', a yellow highlight color is used.
|
||||
// Modify or remove this function to customize the visually presented
|
||||
// way that non-critical warnings and error messages are presented to the
|
||||
// user.
|
||||
function unityShowBanner(msg, type) {
|
||||
function updateBannerVisibility() {
|
||||
warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
|
||||
}
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = msg;
|
||||
warningBanner.appendChild(div);
|
||||
if (type == 'error') div.style = 'background: red; padding: 10px;';
|
||||
else {
|
||||
if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
|
||||
setTimeout(function() {
|
||||
warningBanner.removeChild(div);
|
||||
updateBannerVisibility();
|
||||
}, 5000);
|
||||
}
|
||||
updateBannerVisibility();
|
||||
}
|
||||
|
||||
var buildUrl = "Build";
|
||||
var loaderUrl = buildUrl + "/YD_UnityWeb.loader.js";
|
||||
var config = {
|
||||
dataUrl: buildUrl + "/YD_UnityWeb.data.unityweb",
|
||||
frameworkUrl: buildUrl + "/YD_UnityWeb.framework.js.unityweb",
|
||||
codeUrl: buildUrl + "/YD_UnityWeb.wasm.unityweb",
|
||||
streamingAssetsUrl: "StreamingAssets",
|
||||
companyName: "DefaultCompany",
|
||||
productName: "Yd_ElectricPowerVisualization",
|
||||
productVersion: "0.1",
|
||||
showBanner: unityShowBanner,
|
||||
};
|
||||
|
||||
// By default Unity keeps WebGL canvas render target size matched with
|
||||
// the DOM size of the canvas element (scaled by window.devicePixelRatio)
|
||||
// Set this to false if you want to decouple this synchronization from
|
||||
// happening inside the engine, and you would instead like to size up
|
||||
// the canvas DOM size and WebGL render target sizes yourself.
|
||||
// config.matchWebGLToCanvasSize = false;
|
||||
if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
|
||||
// Mobile device style: fill the whole browser client area with the game canvas:
|
||||
var meta = document.createElement('meta');
|
||||
meta.name = 'viewport';
|
||||
meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';
|
||||
document.getElementsByTagName('head')[0].appendChild(meta);
|
||||
container.className = "unity-mobile";
|
||||
|
||||
// To lower canvas resolution on mobile devices to gain some
|
||||
// performance, uncomment the following line:
|
||||
// config.devicePixelRatio = 1;
|
||||
canvas.style.width = window.innerWidth + 'px';
|
||||
canvas.style.height = window.innerHeight + 'px';
|
||||
|
||||
unityShowBanner('WebGL builds are not supported on mobile devices.');
|
||||
} else {
|
||||
// Desktop style: Render the game canvas in a window that can be maximized to fullscreen:
|
||||
canvas.style.width = "960px";
|
||||
canvas.style.height = "600px";
|
||||
}
|
||||
|
||||
loadingBar.style.display = "block";
|
||||
|
||||
var script = document.createElement("script");
|
||||
var unityInstanceA
|
||||
script.src = loaderUrl;
|
||||
script.onload = () => {
|
||||
createUnityInstance(canvas, config, (progress) => {
|
||||
progressBarFull.style.width = 100 * progress + "%";
|
||||
}).then((unityInstance) => {
|
||||
unityInstanceA = unityInstance
|
||||
loadingBar.style.display = "none";
|
||||
fullscreenButton.onclick = () => {
|
||||
unityInstance.SetFullscreen(1);
|
||||
};
|
||||
}).catch((message) => {
|
||||
alert(message);
|
||||
});
|
||||
};
|
||||
function handleChange(val){
|
||||
unityInstanceA.SendMessage('GameManager','UnityMethod_SelectType',val)
|
||||
};
|
||||
function handleChangeLine(val){
|
||||
unityInstanceA.SendMessage('GameManager','UnityMethod_SelectLine',val)
|
||||
};
|
||||
function WebMethod_SelectDevice(val){
|
||||
window.parent.postMessage({
|
||||
val
|
||||
}, '*'); // * 通配符 匹配所有地址; content 表示传递过去嵌套iframe页面的数据
|
||||
};
|
||||
function fullscreen(val){
|
||||
unityInstanceA.SetFullscreen(val)
|
||||
}
|
||||
document.body.appendChild(script);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,6 @@
|
|||
const RTSP2web = require('rtsp2web')
|
||||
//服务端的端口号,端口号可以自定义
|
||||
const port = 9999
|
||||
new RTSP2web({
|
||||
port
|
||||
})
|
|
@ -0,0 +1 @@
|
|||
node index.js
|
|
@ -0,0 +1,454 @@
|
|||
<template>
|
||||
<div id="app">
|
||||
<div class="top">
|
||||
<div class="left">
|
||||
<div class="time">
|
||||
<span>{{ this.$moment().format("YYYY-MM-DD") }} {{ week }}</span>
|
||||
<span style="font-size: 24px; margin-top: 3px">{{
|
||||
nowDate
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="middle">
|
||||
<div class="box">
|
||||
|
||||
</div>
|
||||
<!-- <div
|
||||
class="router"
|
||||
:class="{ active: routerActive == index }"
|
||||
v-for="(item, index) in routerTitle"
|
||||
@click="handleChange(index)"
|
||||
:key="index"
|
||||
:text="item"
|
||||
>
|
||||
{{ item }}
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="time">
|
||||
<span>{{ this.$moment().format("YYYY-MM-DD") }} {{ week }}</span>
|
||||
<span style="font-size: 24px; margin-top: 3px">{{
|
||||
nowDate
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="weather" v-for="(item, index) in weatherArr" :key="index">
|
||||
<div class="pic">
|
||||
<img :src="item.pic" alt="" style="height: 100%; width: 100%" />
|
||||
</div>
|
||||
<div class="date">
|
||||
<span>{{ item.date }}</span>
|
||||
<span style="font-size: 24px; margin-top: 3px">{{
|
||||
item.wendu
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import MinxinItem from "./mixins";
|
||||
import axios from "axios";
|
||||
import { getWather, Weather, getToken } from "./api/index.js";
|
||||
export default {
|
||||
name: "home",
|
||||
mixins: [MinxinItem],
|
||||
data() {
|
||||
return {
|
||||
addDay: "",
|
||||
subDay: "",
|
||||
routerTitle: ["实时监测", "安全管控", "站房智辅"],
|
||||
routerActive: 0,
|
||||
weatherArr: [
|
||||
{
|
||||
day: "今天",
|
||||
temperature: "",
|
||||
pic: require("./assets/images/sun.png"),
|
||||
},
|
||||
{
|
||||
day: "昨天",
|
||||
temperature: "",
|
||||
pic: require("./assets/images/union.png"),
|
||||
},
|
||||
{
|
||||
day: "明天",
|
||||
temperature: "",
|
||||
pic: require("./assets/images/windy.png"),
|
||||
},
|
||||
],
|
||||
weekList: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
|
||||
week: "",
|
||||
nowDate:'',
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.handleWather();
|
||||
let week = new Date(this.$moment().format("YYYY-MM-DD")).getDay();
|
||||
this.week = this.weekList[week];
|
||||
// let params = new URLSearchParams()
|
||||
let params = {
|
||||
appKey: "symnzwxdfu1ul8raqrykgbld7zonktga",
|
||||
appSecret: "a3tdb6nxfciekxcgcl94ljvtmw2lsafx",
|
||||
};
|
||||
// params.append('appKey','symnzwxdfu1ul8raqrykgbld7zonktga')
|
||||
// params.append('appSecret','a3tdb6nxfciekxcgcl94ljvtmw2lsafx')
|
||||
getToken(params).then((res) => {
|
||||
localStorage.setItem("token", res.data.data.token);
|
||||
// console.log(localStorage.getItem('token'),'token');
|
||||
});
|
||||
setInterval(()=>{
|
||||
this. handleWather()
|
||||
},480000)
|
||||
setInterval(()=>{
|
||||
this.nowDate = this.$moment().format("HH:mm:ss")
|
||||
},100)
|
||||
},
|
||||
|
||||
methods: {
|
||||
getDateSub(n) {
|
||||
let day = this.$moment(new Date())
|
||||
.subtract(n, "days")
|
||||
.format("YYYY-MM-DD");
|
||||
this.subDay = day;
|
||||
return day;
|
||||
},
|
||||
getDateAdd(n) {
|
||||
var dd = new Date();
|
||||
dd.setDate(dd.getDate() + n); //获取n天后的日期
|
||||
// var y = dd.getFullYear();
|
||||
var m = dd.getMonth() + 1; //获取当前月份的日期
|
||||
if (m < 10) {
|
||||
m = "0" + m;
|
||||
}
|
||||
var d = dd.getDate();
|
||||
if (d < 10) {
|
||||
d = "0" + d;
|
||||
}
|
||||
let day = m + "-" + d;
|
||||
// this.addDay = day;
|
||||
return day;
|
||||
},
|
||||
getNewDate() {
|
||||
var date = new Date();
|
||||
var month = date.getMonth() + 1; //获取当前月份的日期
|
||||
if (month < 10) {
|
||||
month = "0" + month;
|
||||
}
|
||||
var a = date.getDate();
|
||||
if (a < 10) {
|
||||
a = "0" + a;
|
||||
}
|
||||
let day = month + "-" + a;
|
||||
return day;
|
||||
},
|
||||
//天气
|
||||
handleWather() {
|
||||
// axios({url:"http://www.jcznedu.com:5000/weather/prediction/?city=盐都&&limit=3",methods:'GET'}).then(res=>{
|
||||
// })
|
||||
|
||||
getWather().then((res) => {
|
||||
// console.log(res, "天气情况");
|
||||
for (let i = 0; i < res.data.data.length; i++) {
|
||||
let item = res.data.data[i];
|
||||
// console.log(item.date);
|
||||
if (item.date == this.getNewDate()) {
|
||||
item.date = "今天";
|
||||
item.wendu = item.low + "℃~" + item.high + "℃";
|
||||
item.pic = this.Onweather(item.weather, i);
|
||||
} else if (item.date == this.getDateAdd(1)) {
|
||||
item.date = "明天";
|
||||
item.wendu = item.low + "℃~" + item.high + "℃";
|
||||
item.pic = this.Onweather(item.weather, i);
|
||||
} else if (item.date == this.getDateAdd(2)) {
|
||||
item.date = "后天";
|
||||
item.wendu = item.low + "℃~" + item.high + "℃";
|
||||
item.pic = this.Onweather(item.weather, i);
|
||||
}
|
||||
}
|
||||
// console.log(res.data.data);
|
||||
// 天气
|
||||
this.weatherArr = res.data.data;
|
||||
// console.log(this.weatherArr);
|
||||
// console.log(this.getNewDate(),'获取');
|
||||
});
|
||||
// Weather({
|
||||
// action: "one",
|
||||
// key: "天气情况",
|
||||
// }).then((res) => {
|
||||
// // console.log(res, "天气情况");
|
||||
// let toDay = this.$moment().format("D");
|
||||
// this.getDateSub(1);
|
||||
// this.getDateAdd(1),
|
||||
// res.data.data.forEach((item, index) => {
|
||||
// if (item.第N天 == this.$moment(this.subDay).format("D")) {
|
||||
// this.weatherArr[1].date = "昨天";
|
||||
// this.weatherArr[1].temperature =
|
||||
// item.最低温度 + "℃" + "~" + item.最高温度 + "℃";
|
||||
// this.Onweather(item.天气, 1);
|
||||
// } else if (item.第N天 == this.$moment(this.addDay).format("D")) {
|
||||
// this.weatherArr[2].date = "明天";
|
||||
// this.weatherArr[2].temperature =
|
||||
// item.最低温度 + "℃" + "~" + item.最高温度 + "℃";
|
||||
// this.Onweather(item.天气, 2);
|
||||
// } else if (item.第N天 == toDay) {
|
||||
// this.weatherArr[0].date = "今天";
|
||||
// this.weatherArr[0].temperature =
|
||||
// item.最低温度 + "℃" + "~" + item.最高温度 + "℃";
|
||||
// this.Onweather(item.天气, 0);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
},
|
||||
//天气
|
||||
Onweather(name, index) {
|
||||
// console.log(name, "名字");
|
||||
if(name.includes('阴')||name.includes('多云')){
|
||||
if(name.includes('雨')){
|
||||
return require("./assets/weather/rain.png");
|
||||
}else{
|
||||
return require("./assets/weather/Cloudy .png");
|
||||
}
|
||||
}
|
||||
if(name.includes('小雨')){
|
||||
|
||||
return require("./assets/weather/rain.png");
|
||||
|
||||
}
|
||||
// console.log(index);
|
||||
switch (name) {
|
||||
|
||||
case '风转阴':
|
||||
return require("./assets/weather/Cloudy .png");
|
||||
case "多云":
|
||||
return require("./assets/weather/Cloudy .png");
|
||||
case "阴":
|
||||
return require("./assets/weather/Cloudy .png");
|
||||
case "阴转多云":
|
||||
return require("./assets/weather/Cloudy .png");
|
||||
case "暴雨":
|
||||
return require("./assets/weather/rainstorm.png");
|
||||
case "冰雹":
|
||||
return require("./assets/weather/hail.png");
|
||||
case "大风":
|
||||
return require("./assets/weather/gale.png");
|
||||
case "大雪":
|
||||
return require("./assets/weather/bigsnow.png");
|
||||
case "大雨":
|
||||
return require("./assets/weather/bigrain.png");
|
||||
case "雷电":
|
||||
return require("./assets/weather/thunder.png");
|
||||
case "雷阵雨":
|
||||
return require("./assets/weather/shower.png");
|
||||
case "沙尘暴":
|
||||
return require("./assets/weather/sand.png");
|
||||
case "晴":
|
||||
return require("./assets/weather/sun.png");
|
||||
case "雾霾":
|
||||
return require("./assets/weather/smog.png");
|
||||
case "小雪":
|
||||
return require("./assets/weather/snow.png");
|
||||
case "小雨":
|
||||
return require("./assets/weather/rain.png");
|
||||
case "雪":
|
||||
return require("./assets/weather/rainlitter.png");
|
||||
case "多云":
|
||||
return require("./assets/weather/night.png");
|
||||
case "雨夹雪":
|
||||
return require("./assets/weather/rainsnow.png");
|
||||
case "月亮":
|
||||
return require("./assets/weather/moon.png");
|
||||
case "中雪":
|
||||
return require("./assets/weather/mieddlesnow.png");
|
||||
case "中雨":
|
||||
return require("./assets/weather/middlerain.png");
|
||||
case "阴转雨":
|
||||
return require("./assets/weather/rain.png");
|
||||
case "阴转晴":
|
||||
return require("./assets/weather/Cloudy .png");
|
||||
}
|
||||
},
|
||||
handleChange(index) {
|
||||
let that = this;
|
||||
this.routerActive = index;
|
||||
if (this.routerActive == 0) {
|
||||
if (this.$route.name != "index") {
|
||||
that.$router.push({ name: "index" });
|
||||
}
|
||||
} else if (this.routerActive == 2) {
|
||||
that.$router.push({ name: "stationBuilding" });
|
||||
}
|
||||
// else if (this.routerActive == 1) {
|
||||
// that.$router.push({ name: "twentyKV" });
|
||||
// }
|
||||
else if (this.routerActive == 1) {
|
||||
that.$router.push({ name: "thirtyFiveKV" });
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style >
|
||||
@import "./assets/index.css";
|
||||
|
||||
#app {
|
||||
font-family: "Avenir", Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
background: url("./assets/index/bg.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.top {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
/* background: rgba(147, 230, 244,0.6); */
|
||||
/* background-image: linear-gradient(90deg, rgba(147, 230, 244,0.6),rgba(147, 230, 244,0), rgba(147, 230, 244,0.6)); */
|
||||
// background: url("./assets/images/topBg.png") no-repeat;
|
||||
background: url("./assets/indexN/title.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-between;
|
||||
.left {
|
||||
width: 815px;
|
||||
height: 97px;
|
||||
// background: url("./assets/index/title.png") no-repeat;
|
||||
// background-size: 100% 100%;
|
||||
font-size: 44px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 22px;
|
||||
color: #ffffff;
|
||||
// line-height: 97px;
|
||||
padding-left: 86px;
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
.time {
|
||||
height: 100%;
|
||||
color: #ffffff;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
text-align: left;
|
||||
}
|
||||
.weather {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
margin-left: 36px;
|
||||
.pic {
|
||||
width: 61px;
|
||||
height: 61px;
|
||||
}
|
||||
.date {
|
||||
height: 100%;
|
||||
color: #ffffff;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
margin-left: 19px;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.left:before {
|
||||
content: attr(text);
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
color: rgb(86, 254, 246);
|
||||
-webkit-mask: linear-gradient(to top, rgb(86, 244, 254), transparent);
|
||||
}
|
||||
.middle {
|
||||
width: 27%;
|
||||
height: 80px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
/* display: flex; */
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
position: absolute;
|
||||
left: 38%;
|
||||
top: 3%;
|
||||
.box{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url("./assets/indexN/titleText.png") no-repeat;
|
||||
}
|
||||
.router {
|
||||
width: 244px;
|
||||
height: 100%;
|
||||
line-height: 78px;
|
||||
color: rgb(41, 114, 124);
|
||||
font-size: 22px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.active {
|
||||
color: #ffffff;
|
||||
background: url("./assets/images/routerActive.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.active:before {
|
||||
content: attr(text);
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
color: rgb(86, 254, 246);
|
||||
-webkit-mask: linear-gradient(to top, rgb(86, 244, 254), transparent);
|
||||
}
|
||||
}
|
||||
.right {
|
||||
// width: 740px;
|
||||
height: 78px;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-between;
|
||||
padding-right: 15px;
|
||||
.time {
|
||||
height: 100%;
|
||||
color: #ffffff;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
text-align: left;
|
||||
}
|
||||
.weather {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
margin-left: 36px;
|
||||
.pic {
|
||||
width: 61px;
|
||||
height: 61px;
|
||||
}
|
||||
.date {
|
||||
height: 100%;
|
||||
color: #ffffff;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
margin-left: 19px;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
width: 100%;
|
||||
height: calc(100% - 100px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,128 @@
|
|||
import axios from 'axios'
|
||||
// if (process.env.NODE_ENV === 'development') {
|
||||
// axios.defaults.baseURL = '/app'
|
||||
// } else if (process.env.NODE_ENV === 'production') {
|
||||
// axios.defaults.baseURL = '/app'
|
||||
// }
|
||||
//设置请求头参数 common 为设置所有的接口 post为设置post请求的接口
|
||||
// axios.defaults.headers.common['Authorization'] = `Bearer ${localStorage.getItem('access_token')}`;
|
||||
export const getWord = (url) =>{
|
||||
return axios.get('app'+url,{
|
||||
responseType:'blob',
|
||||
})
|
||||
}
|
||||
// 电力概况
|
||||
export const getCompanyInfo = (params) => {
|
||||
return axios.get('app/Handler/Company.ashx', {
|
||||
params
|
||||
})
|
||||
};
|
||||
// 路线查询 下拉
|
||||
export const getLine = (params) => {
|
||||
return axios.get('app/Handler/Line.ashx', {
|
||||
params
|
||||
})
|
||||
};
|
||||
// 查询设备素材
|
||||
export const getDevice = (params) => {
|
||||
return axios.get('app/Handler/Device.ashx', {
|
||||
params
|
||||
})
|
||||
};
|
||||
//班组故障查询
|
||||
export const getBanzugz = (params) => {
|
||||
return axios.get('app/Handler/Banzugz.ashx', {
|
||||
params
|
||||
})
|
||||
};
|
||||
//查询工单统计
|
||||
export const getGdtj = (params) => {
|
||||
return axios.get('app/Handler/gdtj.ashx', {
|
||||
params
|
||||
})
|
||||
};
|
||||
|
||||
//查询单位本周故障
|
||||
export const getDwbzgz = (params) => {
|
||||
return axios.get('app/Handler/Dwbzgz.ashx', {
|
||||
params
|
||||
})
|
||||
};
|
||||
//查询供电所供电质量情况
|
||||
export const getGdsgdzl = (params) => {
|
||||
return axios.get('app/Handler/Gdsgdzl.ashx', {
|
||||
params
|
||||
})
|
||||
};
|
||||
//查询配变停运情况
|
||||
export const getPbtyqk = (params) => {
|
||||
return axios.get('app/Handler/Pbtyqk.ashx', {
|
||||
params
|
||||
})
|
||||
};
|
||||
|
||||
//查询天气
|
||||
export const getWather = (params) => {
|
||||
return axios.get('app/Handler/Weather.ashx', {
|
||||
params
|
||||
})
|
||||
};
|
||||
// // 获取区属
|
||||
// export const getDistrict=(params)=>{
|
||||
// return axios.get('/app/')
|
||||
// }
|
||||
//查询天气
|
||||
// export const Weather = (params) => {
|
||||
// return axios.get('app/Handler/Weather.ashx', {
|
||||
// params
|
||||
// })
|
||||
// };
|
||||
//查询天气1
|
||||
export const Weather = (params) => {
|
||||
return axios.get('app/Handler/Data.ashx', {
|
||||
params
|
||||
})
|
||||
};
|
||||
//获取token
|
||||
export const getToken = (data) => {
|
||||
return axios.post('aps/api/v1/token'+'?appKey='+data.appKey+'&appSecret='+data.appSecret,data
|
||||
,{headers: { 'Content-Type': 'application/x-www-form-urlencoded' }})
|
||||
};
|
||||
//获取单个网柜信息
|
||||
export const getCabinetInfo = (data) => {
|
||||
return axios.post('aps/api/v1/cabinetInfo'+'?sn='+data.sn+'&token='+data.token,data
|
||||
,{headers: { 'Content-Type': 'application/x-www-form-urlencoded' }})
|
||||
};
|
||||
//获取网柜列表
|
||||
export const getCabinetList = (data) => {
|
||||
return axios.post('aps/api/v1/cabinetList'+'?sn='+data.pageSize+'&token='+data.token,data
|
||||
,{headers: { 'Content-Type': 'application/x-www-form-urlencoded' }})
|
||||
};
|
||||
//获取单个网柜数据
|
||||
export const getCabinetData = (data) => {
|
||||
return axios.post('aps/api/v1/cabinetData'+'?sn='+data.sn+'&token='+data.token,data
|
||||
,{headers: { 'Content-Type': 'application/x-www-form-urlencoded' }})
|
||||
};
|
||||
//获取单个网柜视频列表
|
||||
export const getCabinetCameraList = (data) => {
|
||||
return axios.post('aps/api/v1/cabinetCameraList'+'?sn='+data.sn+'&token='+data.token,data
|
||||
,{headers: { 'Content-Type': 'application/x-www-form-urlencoded' }})
|
||||
};
|
||||
//获取历史故障
|
||||
export const getfaultReportList = (data) => {
|
||||
return axios.post('aps/api/v1/faultReportList'+'?sn='+data.sn+'&token='+data.token,data
|
||||
,{headers: { 'Content-Type': 'application/x-www-form-urlencoded' }})
|
||||
};
|
||||
//获取告警数据
|
||||
export const getCabinetAlarmList = (data) => {
|
||||
return axios.post('aps/api/v1/cabinetAlarmList'+'?sn='+data.sn+'&token='+data.token+'&startDate='+data.startDate+'&endDate='+data.endDate+'&page='+data.page+'&pageSize='+data.pageSize,
|
||||
data
|
||||
,{headers: { 'Content-Type': 'application/x-www-form-urlencoded' }})
|
||||
};
|
||||
//获取网柜测点历史数据
|
||||
export const getCabinetPointHistory = (data) => {
|
||||
return axios.post('aps/api/v1/cabinetPointHistory'+'?sn='+data.sn+'&token='+data.token+'&point='+data.point+'&date='+data.date,
|
||||
data
|
||||
,{headers: { 'Content-Type': 'application/x-www-form-urlencoded' }})
|
||||
};
|
||||
|
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 498 B |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 352 B |
After Width: | Height: | Size: 354 B |
After Width: | Height: | Size: 338 B |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 9.7 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 934 B |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 845 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 327 B |
After Width: | Height: | Size: 472 B |
After Width: | Height: | Size: 633 B |
After Width: | Height: | Size: 483 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 870 B |
After Width: | Height: | Size: 289 B |
After Width: | Height: | Size: 448 B |
After Width: | Height: | Size: 462 B |
After Width: | Height: | Size: 1021 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 183 KiB |
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 158 KiB |
After Width: | Height: | Size: 2.5 MiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.4 KiB |