├── .env
├── .github
└── workflows
│ └── docker-image.yml
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── babel.config.js
├── jsconfig.json
├── package.json
├── public
├── css
│ └── main.css
├── download.html
├── favicon.ico
├── favicon.png
├── index.html
├── js
│ ├── 3d-lines-animation.js
│ ├── canvas-renderer.js
│ ├── color.js
│ ├── djtx.min.js
│ ├── jquery.min.js
│ ├── projector.js
│ └── three.min.js
└── web
│ ├── netflix.svg
│ └── nf.ico
├── src
├── App.vue
├── assets
│ └── css
│ │ ├── dark.min.css
│ │ ├── element-ui.scss
│ │ ├── element-variables.scss
│ │ └── light.min.css
├── components
│ └── SvgIcon
│ │ └── index.vue
├── icons
│ ├── index.js
│ └── svg
│ │ ├── bilibili.svg
│ │ ├── github.svg
│ │ ├── telegram.svg
│ │ └── youtube.svg
├── main.js
├── plugins
│ ├── axios.js
│ ├── base64.js
│ ├── clipboard.js
│ ├── device.js
│ ├── element-ui.js
│ └── particles.js
├── router
│ └── index.js
└── views
│ └── Subconverter.vue
├── vue.config.js
└── yarn.lock
/.env:
--------------------------------------------------------------------------------
1 | VUE_APP_PROJECT = "https://github.com/youshandefeiyang/sub-web-modify"
2 |
3 | VUE_APP_BOT_LINK = "https://t.me/feiyangdigital"
4 |
5 | VUE_APP_BILIBILI_LINK = "https://space.bilibili.com/138129883"
6 |
7 | VUE_APP_YOUTUBE_LINK = "https://youtube.com/channel/UCKHJ2UPlkNsDRj1cVXi0UsA"
8 |
9 | VUE_APP_BASIC_VIDEO = "https://www.youtube.com/watch?v=C4WV4223uYw"
10 |
11 | VUE_APP_ADVANCED_VIDEO = "https://www.youtube.com/watch?v=cHs-J2P5CT0"
12 |
13 | VUE_APP_SCRIPT_CONFIG = "https://github.com/tindy2013/subconverter/blob/a24cb7c00a7e5a71ef2e6c0d64d84d91bc7a21d6/README-cn.md?plain=1#L703-L719"
14 |
15 | VUE_APP_FILTER_CONFIG = "https://github.com/tindy2013/subconverter/blob/a24cb7c00a7e5a71ef2e6c0d64d84d91bc7a21d6/README-cn.md?plain=1#L514-L531"
16 |
17 | VUE_APP_SUBCONVERTER_REMOTE_CONFIG = "https://subconverter.oss-ap-southeast-1.aliyuncs.com/Rules/RemoteConfig/universal/urltest.ini"
18 |
19 | # API 后端
20 | VUE_APP_SUBCONVERTER_DEFAULT_BACKEND = "https://url.v1.mk"
21 |
22 | # 短链接后端
23 | VUE_APP_MYURLS_DEFAULT_BACKEND = "https://v1.mk"
24 |
25 | # 文本托管后端
26 | VUE_APP_CONFIG_UPLOAD_BACKEND = "https://subapi.v1.mk"
27 |
--------------------------------------------------------------------------------
/.github/workflows/docker-image.yml:
--------------------------------------------------------------------------------
1 | name: Docker Image CI
2 | on:
3 | push:
4 | branches:
5 | - master
6 |
7 | jobs:
8 | build-and-push:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - name: Check out repository
13 | uses: actions/checkout@master
14 |
15 | - name: Set up Docker Buildx
16 | uses: docker/setup-buildx-action@v2
17 |
18 | - name: Log in to Docker Hub
19 | uses: docker/login-action@v2
20 | with:
21 | username: ${{ secrets.DOCKERHUB_USERNAME }}
22 | password: ${{ secrets.DOCKERHUB_TOKEN }}
23 |
24 | - name: Build and push Docker image
25 | uses: docker/build-push-action@v4
26 | with:
27 | context: .
28 | platforms: linux/amd64,linux/arm,linux/arm64
29 | push: true
30 | tags: youshandefeiyang/sub-web-modify:latest
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:18-alpine AS build
2 | WORKDIR /app
3 | COPY . .
4 | RUN yarn install
5 | RUN yarn build
6 |
7 | FROM nginx:1.24-alpine
8 | COPY --from=build /app/dist /usr/share/nginx/html
9 | EXPOSE 80
10 | CMD [ "nginx", "-g", "daemon off;" ]
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 youshandefeiyang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # sub-web-modify
2 | [本项目](https://suburl.v1.mk)重制[原项目](https://github.com/CareyWang/sub-web)CSS样式,兼容nodejs最新版本(可直接一键部署至Vercel),解决大部分布局细节问题,增加“暗黑模式”,默认自动切换亮/暗模式(点击“太阳/月亮”图标可手动切换),增加“高级功能”点击显示/隐藏,添加短链接选择/自定义功能,增加近百条远程配置,新增[sub-web聚合API](https://github.com/youshandefeiyang/sub-web-api),增加从短链接中获取订阅信息并返回至前端界面,增加上传自定义远程配置/JS进阶排序节点/JS进阶筛选节点等功能,感兴趣的朋友可以自建API服务,增加URL传参设置自定义后端
3 | ## 效果预览:
4 | 
5 | ### 使用方法:
6 | 建议使用Docker一键部署:
7 | ```
8 | docker run -d --restart unless-stopped --privileged=true -p 8090:80 --name sub-web-modify youshandefeiyang/sub-web-modify
9 | ```
10 | 访问地址举例:
11 | ```
12 | http://192.168.10.1:8090/?backend=https://url.v1.mk
13 | ```
14 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "esnext",
5 | "baseUrl": "./",
6 | "moduleResolution": "node",
7 | "paths": {
8 | "@/*": [
9 | "src/*"
10 | ]
11 | },
12 | "lib": [
13 | "esnext",
14 | "dom",
15 | "dom.iterable",
16 | "scripthost"
17 | ]
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sub-web-modify",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build"
8 | },
9 | "dependencies": {
10 | "atob": "^2.1.2",
11 | "axios": "^1.7.2",
12 | "btoa": "^1.2.1",
13 | "core-js": "^3.37.1",
14 | "element-ui": "^2.15.14",
15 | "vue": "^2.7.16",
16 | "vue-clipboard2": "^0.3.3",
17 | "vue-router": "^3.6.5"
18 | },
19 | "devDependencies": {
20 | "@vue/cli-plugin-babel": "~5.0.0",
21 | "@vue/cli-plugin-router": "~5.0.0",
22 | "@vue/cli-service": "~5.0.0",
23 | "babel-plugin-component": "^1.1.1",
24 | "babel-plugin-import": "^1.13.8",
25 | "sass": "^1.66.1",
26 | "sass-loader": "^13.3.2",
27 | "svg-sprite-loader": "^6.0.11",
28 | "vue-particles": "^1.0.9",
29 | "vue-template-compiler": "^2.6.14"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/public/download.html:
--------------------------------------------------------------------------------
1 |
2 | 各平台代理工具集合
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
19 |
24 |
25 |
26 |
27 |
Clash全平台客户端备份
28 |
点击查看
29 |
代理客户端
30 |
Android TV(包括国行索尼电视、FireTv系列)
31 |
37 |
iOS 客户端 (全区可下载,包括中区)
38 |
41 |
iOS 客户端 (中区无法下载,其他区可下载)
42 |
43 | - Surge iOS 5 更新订阅制,首年:49.99,次年开始:14.99/年 (支持Snell/SS/VMess/VMessAEAD/Trojan/SSH/WireGuard/Hysteria2) 推荐官网购买
44 | - Quantumult X $7.99 (支持SS/SSR/VMess/VMessAEAD/Trojan)
45 | - Shadowrocket $2.99 (也叫:小火箭, 支持SS/SSR/Snell/VMess/VMessAEAD/Trojan/VLESS/Relay/Hysteria/Hysteria2/TUIC/WireGuard/Brook/Lua/Juicity)
46 | - Loon $5.99 (支持SS/SSR/VMess/VMessAEAD/Trojan/VLESS/WireGuard/Hysteria2)
47 | - Loon Lite $0.99
48 | - Stash $3.99 (iOS 上的 Clash 客户端, 支持SS/SSR/Snell/VMess/VMessAEAD/Trojan/VLESS/XTLS/Hysteria/Hysteria2)
49 | - Choc $2.99 (iOS 上的 Clash 客户端, 支持SS/SSR/Snell/VMess/VMessAEAD/Trojan)
50 | - Maomi TestFlight (iOS 上的 Clash 客户端, 支持 Clash Premium 内核)
51 | - sing-box Free (支持SOCKS/HTTP/SS/SSR/VMess/Trojan/WireGuard/Hysteria/Hysteria2/ShadowTLS/VLESS/TUIC/Tor/SSH)
52 | - Egern $2.99 (支持SS/Trojan)
53 | - Blatu $1.99 (Shadowrocket作者开发的, 支持shadowvpn,DSVPN,WireGuard)
54 | - Pharos Pro $1.99
55 | - Kitsunebi $4.99
56 | - Potatso 2 $2.99
57 | - Potatso Lite Free
58 | - LanceX $2.99
59 | - TrojanX $1.99
60 | - OneClick Free
61 | - Spectre VPN Free
62 | - 代购/人民币购买地址
63 |
64 |
tvOS 客户端
65 |
66 | - Surge
67 | - sing-box
68 | - Quantumult X
69 | - Shadowrocket
70 | - Loon
71 | - Loon Lite
72 | - Stash
73 | - Potatso
74 |
75 |
Android/安卓 客户端
76 |
100 |
Windows 客户端
101 |
117 |
macOS 客户端
118 |
130 |
路由器
131 |
138 |
Telegram 客户端 Proxy 代理设置
139 |
点击查看
140 |
耗电/流量
141 |
为什么使用了代理应用后在电量统计中显示耗电很多?
142 | 这是移动操作系统的一个特殊机制,Surge iOS、Quantumult X、Shadowrocket、Choc 等等所有的 SS/SSR/V2Ray/Trojan 客户端开启后会接管全局的(几乎)所有通信,所以所有的网络方面电量消耗都会被算在代理应用头上,实际使用中不会感到代理应用对电量有明显影响,「设置-电池」中看到它的电池用量,绝大部分都是网络所消耗的电量,并不是代理应用消耗的电量,代理应用就是背锅侠。
143 | 还有,夜间或锁屏后系统也会请求网络,比如后台刷新、系统服务等等,只要有请求网络就会经过代理应用,所以在「设置-电池」处看到代理应用在后台也会运行。
144 | 网络流量也是如此的。
145 |
146 |
147 |
148 |
149 | ⚠️本站部分资源引用自TG-@congcongx_bot
150 |
151 |
152 |
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youshandefeiyang/sub-web-modify/68422ba384475acb791fd65eb30ada7f38634a6b/public/favicon.ico
--------------------------------------------------------------------------------
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youshandefeiyang/sub-web-modify/68422ba384475acb791fd65eb30ada7f38634a6b/public/favicon.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 在线订阅转换工具
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/public/js/3d-lines-animation.js:
--------------------------------------------------------------------------------
1 | var mouseX = 0, mouseY = 0,
2 |
3 | windowHalfX = window.innerWidth / 2,
4 | windowHalfY = window.innerHeight / 2,
5 |
6 | SEPARATION = 200,
7 | AMOUNTX = 1,
8 | AMOUNTY = 1,
9 |
10 | camera, scene, renderer;
11 |
12 | init();
13 | animate();
14 |
15 |
16 |
17 | function init() {
18 |
19 |
20 | /*
21 | * Define variables
22 | */
23 | var container, separation = 1000, amountX = 50, amountY = 50, color = 0xffffff,
24 | particles, particle;
25 |
26 | container = document.getElementById("canvas");
27 |
28 |
29 | camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
30 | camera.position.z = 100;
31 |
32 | scene = new THREE.Scene();
33 |
34 | renderer = new THREE.CanvasRenderer({ alpha: true });
35 | renderer.setPixelRatio( window.devicePixelRatio );
36 | renderer.setClearColor( 0x000000, 0 ); // canvas background color
37 | renderer.setSize( window.innerWidth, window.innerHeight );
38 | container.appendChild( renderer.domElement );
39 |
40 |
41 |
42 | var PI2 = Math.PI * 2;
43 | var material = new THREE.SpriteCanvasMaterial( {
44 |
45 | color: color,
46 | opacity: 0.5,
47 | program: function ( context ) {
48 |
49 | context.beginPath();
50 | context.arc( 0, 0, 0.5, 0, PI2, true );
51 | context.fill();
52 |
53 | }
54 |
55 | } );
56 |
57 | var geometry = new THREE.Geometry();
58 |
59 | /*
60 | * Number of particles
61 | */
62 | for ( var i = 0; i < 150; i ++ ) {
63 |
64 | particle = new THREE.Sprite( material );
65 | particle.position.x = Math.random() * 2 - 1;
66 | particle.position.y = Math.random() * 2 - 1;
67 | particle.position.z = Math.random() * 2 - 1;
68 | particle.position.normalize();
69 | particle.position.multiplyScalar( Math.random() * 10 + 600 );
70 | particle.scale.x = particle.scale.y = 5;
71 |
72 | scene.add( particle );
73 |
74 | geometry.vertices.push( particle.position );
75 |
76 | }
77 |
78 | /*
79 | * Lines
80 | */
81 |
82 | var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: color, opacity: 0.2 } ) );
83 | scene.add( line );
84 |
85 | document.addEventListener( 'mousemove', onDocumentMouseMove, false );
86 | document.addEventListener( 'touchstart', onDocumentTouchStart, false );
87 | document.addEventListener( 'touchmove', onDocumentTouchMove, false );
88 |
89 | //
90 |
91 | window.addEventListener( 'resize', onWindowResize, false );
92 |
93 | }
94 |
95 | function onWindowResize() {
96 |
97 | windowHalfX = window.innerWidth / 2;
98 | windowHalfY = window.innerHeight / 2;
99 |
100 | camera.aspect = window.innerWidth / window.innerHeight;
101 | camera.updateProjectionMatrix();
102 |
103 | renderer.setSize( window.innerWidth, window.innerHeight );
104 |
105 | }
106 |
107 | //
108 |
109 | function onDocumentMouseMove(event) {
110 |
111 | mouseX = (event.clientX - windowHalfX) * 0.05;
112 | mouseY = (event.clientY - windowHalfY) * 0.2;
113 |
114 | }
115 |
116 | function onDocumentTouchStart( event ) {
117 |
118 | if ( event.touches.length > 1 ) {
119 |
120 | event.preventDefault();
121 |
122 | mouseX = (event.touches[ 0 ].pageX - windowHalfX) * 0.7;
123 | mouseY = (event.touches[ 0 ].pageY - windowHalfY) * 0.7;
124 |
125 | }
126 |
127 | }
128 |
129 | function onDocumentTouchMove( event ) {
130 |
131 | if ( event.touches.length == 1 ) {
132 |
133 | event.preventDefault();
134 |
135 | mouseX = event.touches[ 0 ].pageX - windowHalfX;
136 | mouseY = event.touches[ 0 ].pageY - windowHalfY;
137 |
138 | }
139 |
140 | }
141 |
142 | //
143 |
144 | function animate() {
145 |
146 | requestAnimationFrame( animate );
147 |
148 | render();
149 |
150 | }
151 |
152 | function render() {
153 |
154 | camera.position.x += ( mouseX - camera.position.x ) * 0.1;
155 | camera.position.y += ( - mouseY + 200 - camera.position.y ) * 0.05;
156 | camera.lookAt( scene.position );
157 |
158 | renderer.render( scene, camera );
159 |
160 | }
--------------------------------------------------------------------------------
/public/js/canvas-renderer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | */
4 |
5 | THREE.SpriteCanvasMaterial = function ( parameters ) {
6 |
7 | THREE.Material.call( this );
8 |
9 | this.type = 'SpriteCanvasMaterial';
10 |
11 | this.color = new THREE.Color( 0xffffff );
12 | this.program = function ( context, color ) {};
13 |
14 | this.setValues( parameters );
15 |
16 | };
17 |
18 | THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype );
19 | THREE.SpriteCanvasMaterial.prototype.constructor = THREE.SpriteCanvasMaterial;
20 |
21 | THREE.SpriteCanvasMaterial.prototype.clone = function () {
22 |
23 | var material = new THREE.SpriteCanvasMaterial();
24 |
25 | THREE.Material.prototype.clone.call( this, material );
26 |
27 | material.color.copy( this.color );
28 | material.program = this.program;
29 |
30 | return material;
31 |
32 | };
33 |
34 | //
35 |
36 | THREE.CanvasRenderer = function ( parameters ) {
37 |
38 | console.log( 'THREE.CanvasRenderer', THREE.REVISION );
39 |
40 | var smoothstep = THREE.Math.smoothstep;
41 |
42 | parameters = parameters || {};
43 |
44 | var _this = this,
45 | _renderData, _elements, _lights,
46 | _projector = new THREE.Projector(),
47 |
48 | _canvas = parameters.canvas !== undefined
49 | ? parameters.canvas
50 | : document.createElement( 'canvas' ),
51 |
52 | _canvasWidth = _canvas.width,
53 | _canvasHeight = _canvas.height,
54 | _canvasWidthHalf = Math.floor( _canvasWidth / 2 ),
55 | _canvasHeightHalf = Math.floor( _canvasHeight / 2 ),
56 |
57 | _viewportX = 0,
58 | _viewportY = 0,
59 | _viewportWidth = _canvasWidth,
60 | _viewportHeight = _canvasHeight,
61 |
62 | pixelRatio = 1,
63 |
64 | _context = _canvas.getContext( '2d', {
65 | alpha: parameters.alpha === true
66 | } ),
67 |
68 | _clearColor = new THREE.Color( 0x000000 ),
69 | _clearAlpha = parameters.alpha === true ? 0 : 1,
70 |
71 | _contextGlobalAlpha = 1,
72 | _contextGlobalCompositeOperation = 0,
73 | _contextStrokeStyle = null,
74 | _contextFillStyle = null,
75 | _contextLineWidth = null,
76 | _contextLineCap = null,
77 | _contextLineJoin = null,
78 | _contextLineDash = [],
79 |
80 | _camera,
81 |
82 | _v1, _v2, _v3, _v4,
83 | _v5 = new THREE.RenderableVertex(),
84 | _v6 = new THREE.RenderableVertex(),
85 |
86 | _v1x, _v1y, _v2x, _v2y, _v3x, _v3y,
87 | _v4x, _v4y, _v5x, _v5y, _v6x, _v6y,
88 |
89 | _color = new THREE.Color(),
90 | _color1 = new THREE.Color(),
91 | _color2 = new THREE.Color(),
92 | _color3 = new THREE.Color(),
93 | _color4 = new THREE.Color(),
94 |
95 | _diffuseColor = new THREE.Color(),
96 | _emissiveColor = new THREE.Color(),
97 |
98 | _lightColor = new THREE.Color(),
99 |
100 | _patterns = {},
101 |
102 | _image, _uvs,
103 | _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y,
104 |
105 | _clipBox = new THREE.Box2(),
106 | _clearBox = new THREE.Box2(),
107 | _elemBox = new THREE.Box2(),
108 |
109 | _ambientLight = new THREE.Color(),
110 | _directionalLights = new THREE.Color(),
111 | _pointLights = new THREE.Color(),
112 |
113 | _vector3 = new THREE.Vector3(), // Needed for PointLight
114 | _centroid = new THREE.Vector3(),
115 | _normal = new THREE.Vector3(),
116 | _normalViewMatrix = new THREE.Matrix3();
117 |
118 | // dash+gap fallbacks for Firefox and everything else
119 |
120 | if ( _context.setLineDash === undefined ) {
121 |
122 | _context.setLineDash = function () {}
123 |
124 | }
125 |
126 | this.domElement = _canvas;
127 |
128 | this.autoClear = true;
129 | this.sortObjects = true;
130 | this.sortElements = true;
131 |
132 | this.info = {
133 |
134 | render: {
135 |
136 | vertices: 0,
137 | faces: 0
138 |
139 | }
140 |
141 | }
142 |
143 | // WebGLRenderer compatibility
144 |
145 | this.supportsVertexTextures = function () {};
146 | this.setFaceCulling = function () {};
147 |
148 | //
149 |
150 | this.getPixelRatio = function () {
151 |
152 | return pixelRatio;
153 |
154 | };
155 |
156 | this.setPixelRatio = function ( value ) {
157 |
158 | pixelRatio = value;
159 |
160 | };
161 |
162 | this.setSize = function ( width, height, updateStyle ) {
163 |
164 | _canvasWidth = width * pixelRatio;
165 | _canvasHeight = height * pixelRatio;
166 |
167 | _canvas.width = _canvasWidth;
168 | _canvas.height = _canvasHeight;
169 |
170 | _canvasWidthHalf = Math.floor( _canvasWidth / 2 );
171 | _canvasHeightHalf = Math.floor( _canvasHeight / 2 );
172 |
173 | if ( updateStyle !== false ) {
174 |
175 | _canvas.style.width = width + 'px';
176 | _canvas.style.height = height + 'px';
177 |
178 | }
179 |
180 | _clipBox.min.set( -_canvasWidthHalf, -_canvasHeightHalf ),
181 | _clipBox.max.set( _canvasWidthHalf, _canvasHeightHalf );
182 |
183 | _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf );
184 | _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf );
185 |
186 | _contextGlobalAlpha = 1;
187 | _contextGlobalCompositeOperation = 0;
188 | _contextStrokeStyle = null;
189 | _contextFillStyle = null;
190 | _contextLineWidth = null;
191 | _contextLineCap = null;
192 | _contextLineJoin = null;
193 |
194 | this.setViewport( 0, 0, width, height );
195 |
196 | };
197 |
198 | this.setViewport = function ( x, y, width, height ) {
199 |
200 | _viewportX = x * pixelRatio;
201 | _viewportY = y * pixelRatio;
202 |
203 | _viewportWidth = width * pixelRatio;
204 | _viewportHeight = height * pixelRatio;
205 |
206 | };
207 |
208 | this.setScissor = function () {};
209 | this.enableScissorTest = function () {};
210 |
211 | this.setClearColor = function ( color, alpha ) {
212 |
213 | _clearColor.set( color );
214 | _clearAlpha = alpha !== undefined ? alpha : 1;
215 |
216 | _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf );
217 | _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf );
218 |
219 | };
220 |
221 | this.setClearColorHex = function ( hex, alpha ) {
222 |
223 | console.warn( 'THREE.CanvasRenderer: .setClearColorHex() is being removed. Use .setClearColor() instead.' );
224 | this.setClearColor( hex, alpha );
225 |
226 | };
227 |
228 | this.getClearColor = function () {
229 |
230 | return _clearColor;
231 |
232 | };
233 |
234 | this.getClearAlpha = function () {
235 |
236 | return _clearAlpha;
237 |
238 | };
239 |
240 | this.getMaxAnisotropy = function () {
241 |
242 | return 0;
243 |
244 | };
245 |
246 | this.clear = function () {
247 |
248 | if ( _clearBox.empty() === false ) {
249 |
250 | _clearBox.intersect( _clipBox );
251 | _clearBox.expandByScalar( 2 );
252 |
253 | _clearBox.min.x = _clearBox.min.x + _canvasWidthHalf;
254 | _clearBox.min.y = - _clearBox.min.y + _canvasHeightHalf; // higher y value !
255 | _clearBox.max.x = _clearBox.max.x + _canvasWidthHalf;
256 | _clearBox.max.y = - _clearBox.max.y + _canvasHeightHalf; // lower y value !
257 |
258 | if ( _clearAlpha < 1 ) {
259 |
260 | _context.clearRect(
261 | _clearBox.min.x | 0,
262 | _clearBox.max.y | 0,
263 | ( _clearBox.max.x - _clearBox.min.x ) | 0,
264 | ( _clearBox.min.y - _clearBox.max.y ) | 0
265 | );
266 |
267 | }
268 |
269 | if ( _clearAlpha > 0 ) {
270 |
271 | setBlending( THREE.NormalBlending );
272 | setOpacity( 1 );
273 |
274 | setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' );
275 |
276 | _context.fillRect(
277 | _clearBox.min.x | 0,
278 | _clearBox.max.y | 0,
279 | ( _clearBox.max.x - _clearBox.min.x ) | 0,
280 | ( _clearBox.min.y - _clearBox.max.y ) | 0
281 | );
282 |
283 | }
284 |
285 | _clearBox.makeEmpty();
286 |
287 | }
288 |
289 | };
290 |
291 | // compatibility
292 |
293 | this.clearColor = function () {};
294 | this.clearDepth = function () {};
295 | this.clearStencil = function () {};
296 |
297 | this.render = function ( scene, camera ) {
298 |
299 | if ( camera instanceof THREE.Camera === false ) {
300 |
301 | console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' );
302 | return;
303 |
304 | }
305 |
306 | if ( this.autoClear === true ) this.clear();
307 |
308 | _this.info.render.vertices = 0;
309 | _this.info.render.faces = 0;
310 |
311 | _context.setTransform( _viewportWidth / _canvasWidth, 0, 0, - _viewportHeight / _canvasHeight, _viewportX, _canvasHeight - _viewportY );
312 | _context.translate( _canvasWidthHalf, _canvasHeightHalf );
313 |
314 | _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
315 | _elements = _renderData.elements;
316 | _lights = _renderData.lights;
317 | _camera = camera;
318 |
319 | _normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );
320 |
321 | /* DEBUG
322 | setFillStyle( 'rgba( 0, 255, 255, 0.5 )' );
323 | _context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y );
324 | */
325 |
326 | calculateLights();
327 |
328 | for ( var e = 0, el = _elements.length; e < el; e ++ ) {
329 |
330 | var element = _elements[ e ];
331 |
332 | var material = element.material;
333 |
334 | if ( material === undefined || material.opacity === 0 ) continue;
335 |
336 | _elemBox.makeEmpty();
337 |
338 | if ( element instanceof THREE.RenderableSprite ) {
339 |
340 | _v1 = element;
341 | _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf;
342 |
343 | renderSprite( _v1, element, material );
344 |
345 | } else if ( element instanceof THREE.RenderableLine ) {
346 |
347 | _v1 = element.v1; _v2 = element.v2;
348 |
349 | _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
350 | _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
351 |
352 | _elemBox.setFromPoints( [
353 | _v1.positionScreen,
354 | _v2.positionScreen
355 | ] );
356 |
357 | if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
358 |
359 | renderLine( _v1, _v2, element, material );
360 |
361 | }
362 |
363 | } else if ( element instanceof THREE.RenderableFace ) {
364 |
365 | _v1 = element.v1; _v2 = element.v2; _v3 = element.v3;
366 |
367 | if ( _v1.positionScreen.z < - 1 || _v1.positionScreen.z > 1 ) continue;
368 | if ( _v2.positionScreen.z < - 1 || _v2.positionScreen.z > 1 ) continue;
369 | if ( _v3.positionScreen.z < - 1 || _v3.positionScreen.z > 1 ) continue;
370 |
371 | _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
372 | _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
373 | _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf;
374 |
375 | if ( material.overdraw > 0 ) {
376 |
377 | expand( _v1.positionScreen, _v2.positionScreen, material.overdraw );
378 | expand( _v2.positionScreen, _v3.positionScreen, material.overdraw );
379 | expand( _v3.positionScreen, _v1.positionScreen, material.overdraw );
380 |
381 | }
382 |
383 | _elemBox.setFromPoints( [
384 | _v1.positionScreen,
385 | _v2.positionScreen,
386 | _v3.positionScreen
387 | ] );
388 |
389 | if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
390 |
391 | renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material );
392 |
393 | }
394 |
395 | }
396 |
397 | /* DEBUG
398 | setLineWidth( 1 );
399 | setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' );
400 | _context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y );
401 | */
402 |
403 | _clearBox.union( _elemBox );
404 |
405 | }
406 |
407 | /* DEBUG
408 | setLineWidth( 1 );
409 | setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' );
410 | _context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y );
411 | */
412 |
413 | _context.setTransform( 1, 0, 0, 1, 0, 0 );
414 |
415 | };
416 |
417 | //
418 |
419 | function calculateLights() {
420 |
421 | _ambientLight.setRGB( 0, 0, 0 );
422 | _directionalLights.setRGB( 0, 0, 0 );
423 | _pointLights.setRGB( 0, 0, 0 );
424 |
425 | for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {
426 |
427 | var light = _lights[ l ];
428 | var lightColor = light.color;
429 |
430 | if ( light instanceof THREE.AmbientLight ) {
431 |
432 | _ambientLight.add( lightColor );
433 |
434 | } else if ( light instanceof THREE.DirectionalLight ) {
435 |
436 | // for sprites
437 |
438 | _directionalLights.add( lightColor );
439 |
440 | } else if ( light instanceof THREE.PointLight ) {
441 |
442 | // for sprites
443 |
444 | _pointLights.add( lightColor );
445 |
446 | }
447 |
448 | }
449 |
450 | }
451 |
452 | function calculateLight( position, normal, color ) {
453 |
454 | for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {
455 |
456 | var light = _lights[ l ];
457 |
458 | _lightColor.copy( light.color );
459 |
460 | if ( light instanceof THREE.DirectionalLight ) {
461 |
462 | var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();
463 |
464 | var amount = normal.dot( lightPosition );
465 |
466 | if ( amount <= 0 ) continue;
467 |
468 | amount *= light.intensity;
469 |
470 | color.add( _lightColor.multiplyScalar( amount ) );
471 |
472 | } else if ( light instanceof THREE.PointLight ) {
473 |
474 | var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );
475 |
476 | var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() );
477 |
478 | if ( amount <= 0 ) continue;
479 |
480 | amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );
481 |
482 | if ( amount == 0 ) continue;
483 |
484 | amount *= light.intensity;
485 |
486 | color.add( _lightColor.multiplyScalar( amount ) );
487 |
488 | }
489 |
490 | }
491 |
492 | }
493 |
494 | function renderSprite( v1, element, material ) {
495 |
496 | setOpacity( material.opacity );
497 | setBlending( material.blending );
498 |
499 | var scaleX = element.scale.x * _canvasWidthHalf;
500 | var scaleY = element.scale.y * _canvasHeightHalf;
501 |
502 | var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite
503 | _elemBox.min.set( v1.x - dist, v1.y - dist );
504 | _elemBox.max.set( v1.x + dist, v1.y + dist );
505 |
506 | if ( material instanceof THREE.SpriteMaterial ) {
507 |
508 | var texture = material.map;
509 |
510 | if ( texture !== null && texture.image !== undefined ) {
511 |
512 | if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) {
513 |
514 | if ( texture.image.width > 0 ) {
515 |
516 | textureToPattern( texture );
517 |
518 | }
519 |
520 | texture.addEventListener( 'update', onTextureUpdate );
521 |
522 | }
523 |
524 | var pattern = _patterns[ texture.id ];
525 |
526 | if ( pattern !== undefined ) {
527 |
528 | setFillStyle( pattern );
529 |
530 | } else {
531 |
532 | setFillStyle( 'rgba( 0, 0, 0, 1 )' );
533 |
534 | }
535 |
536 | //
537 |
538 | var bitmap = texture.image;
539 |
540 | var ox = bitmap.width * texture.offset.x;
541 | var oy = bitmap.height * texture.offset.y;
542 |
543 | var sx = bitmap.width * texture.repeat.x;
544 | var sy = bitmap.height * texture.repeat.y;
545 |
546 | var cx = scaleX / sx;
547 | var cy = scaleY / sy;
548 |
549 | _context.save();
550 | _context.translate( v1.x, v1.y );
551 | if ( material.rotation !== 0 ) _context.rotate( material.rotation );
552 | _context.translate( - scaleX / 2, - scaleY / 2 );
553 | _context.scale( cx, cy );
554 | _context.translate( - ox, - oy );
555 | _context.fillRect( ox, oy, sx, sy );
556 | _context.restore();
557 |
558 | } else {
559 |
560 | // no texture
561 |
562 | setFillStyle( material.color.getStyle() );
563 |
564 | _context.save();
565 | _context.translate( v1.x, v1.y );
566 | if ( material.rotation !== 0 ) _context.rotate( material.rotation );
567 | _context.scale( scaleX, - scaleY );
568 | _context.fillRect( - 0.5, - 0.5, 1, 1 );
569 | _context.restore();
570 |
571 | }
572 |
573 | } else if ( material instanceof THREE.SpriteCanvasMaterial ) {
574 |
575 | setStrokeStyle( material.color.getStyle() );
576 | setFillStyle( material.color.getStyle() );
577 |
578 | _context.save();
579 | _context.translate( v1.x, v1.y );
580 | if ( material.rotation !== 0 ) _context.rotate( material.rotation );
581 | _context.scale( scaleX, scaleY );
582 |
583 | material.program( _context );
584 |
585 | _context.restore();
586 |
587 | }
588 |
589 | /* DEBUG
590 | setStrokeStyle( 'rgb(255,255,0)' );
591 | _context.beginPath();
592 | _context.moveTo( v1.x - 10, v1.y );
593 | _context.lineTo( v1.x + 10, v1.y );
594 | _context.moveTo( v1.x, v1.y - 10 );
595 | _context.lineTo( v1.x, v1.y + 10 );
596 | _context.stroke();
597 | */
598 |
599 | }
600 |
601 | function renderLine( v1, v2, element, material ) {
602 |
603 | setOpacity( material.opacity );
604 | setBlending( material.blending );
605 |
606 | _context.beginPath();
607 | _context.moveTo( v1.positionScreen.x, v1.positionScreen.y );
608 | _context.lineTo( v2.positionScreen.x, v2.positionScreen.y );
609 |
610 | if ( material instanceof THREE.LineBasicMaterial ) {
611 |
612 | setLineWidth( material.linewidth );
613 | setLineCap( material.linecap );
614 | setLineJoin( material.linejoin );
615 |
616 | if ( material.vertexColors !== THREE.VertexColors ) {
617 |
618 | setStrokeStyle( material.color.getStyle() );
619 |
620 | } else {
621 |
622 | var colorStyle1 = element.vertexColors[ 0 ].getStyle();
623 | var colorStyle2 = element.vertexColors[ 1 ].getStyle();
624 |
625 | if ( colorStyle1 === colorStyle2 ) {
626 |
627 | setStrokeStyle( colorStyle1 );
628 |
629 | } else {
630 |
631 | try {
632 |
633 | var grad = _context.createLinearGradient(
634 | v1.positionScreen.x,
635 | v1.positionScreen.y,
636 | v2.positionScreen.x,
637 | v2.positionScreen.y
638 | );
639 | grad.addColorStop( 0, colorStyle1 );
640 | grad.addColorStop( 1, colorStyle2 );
641 |
642 | } catch ( exception ) {
643 |
644 | grad = colorStyle1;
645 |
646 | }
647 |
648 | setStrokeStyle( grad );
649 |
650 | }
651 |
652 | }
653 |
654 | _context.stroke();
655 | _elemBox.expandByScalar( material.linewidth * 2 );
656 |
657 | } else if ( material instanceof THREE.LineDashedMaterial ) {
658 |
659 | setLineWidth( material.linewidth );
660 | setLineCap( material.linecap );
661 | setLineJoin( material.linejoin );
662 | setStrokeStyle( material.color.getStyle() );
663 | setLineDash( [ material.dashSize, material.gapSize ] );
664 |
665 | _context.stroke();
666 |
667 | _elemBox.expandByScalar( material.linewidth * 2 );
668 |
669 | setLineDash( [] );
670 |
671 | }
672 |
673 | }
674 |
675 | function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) {
676 |
677 | _this.info.render.vertices += 3;
678 | _this.info.render.faces ++;
679 |
680 | setOpacity( material.opacity );
681 | setBlending( material.blending );
682 |
683 | _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y;
684 | _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y;
685 | _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y;
686 |
687 | drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y );
688 |
689 | if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) {
690 |
691 | _diffuseColor.copy( material.color );
692 | _emissiveColor.copy( material.emissive );
693 |
694 | if ( material.vertexColors === THREE.FaceColors ) {
695 |
696 | _diffuseColor.multiply( element.color );
697 |
698 | }
699 |
700 | _color.copy( _ambientLight );
701 |
702 | _centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 );
703 |
704 | calculateLight( _centroid, element.normalModel, _color );
705 |
706 | _color.multiply( _diffuseColor ).add( _emissiveColor );
707 |
708 | material.wireframe === true
709 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
710 | : fillPath( _color );
711 |
712 | } else if ( material instanceof THREE.MeshBasicMaterial ||
713 | material instanceof THREE.MeshLambertMaterial ||
714 | material instanceof THREE.MeshPhongMaterial ) {
715 |
716 | if ( material.map !== null ) {
717 |
718 | var mapping = material.map.mapping;
719 |
720 | if ( mapping === THREE.UVMapping ) {
721 |
722 | _uvs = element.uvs;
723 | patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map );
724 |
725 | }
726 |
727 | } else if ( material.envMap !== null ) {
728 |
729 | if ( material.envMap.mapping === THREE.SphericalReflectionMapping ) {
730 |
731 | _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix );
732 | _uv1x = 0.5 * _normal.x + 0.5;
733 | _uv1y = 0.5 * _normal.y + 0.5;
734 |
735 | _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix );
736 | _uv2x = 0.5 * _normal.x + 0.5;
737 | _uv2y = 0.5 * _normal.y + 0.5;
738 |
739 | _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix );
740 | _uv3x = 0.5 * _normal.x + 0.5;
741 | _uv3y = 0.5 * _normal.y + 0.5;
742 |
743 | patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap );
744 |
745 | }
746 |
747 | } else {
748 |
749 | _color.copy( material.color );
750 |
751 | if ( material.vertexColors === THREE.FaceColors ) {
752 |
753 | _color.multiply( element.color );
754 |
755 | }
756 |
757 | material.wireframe === true
758 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
759 | : fillPath( _color );
760 |
761 | }
762 |
763 | } else if ( material instanceof THREE.MeshDepthMaterial ) {
764 |
765 | _color.r = _color.g = _color.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _camera.near, _camera.far );
766 |
767 | material.wireframe === true
768 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
769 | : fillPath( _color );
770 |
771 | } else if ( material instanceof THREE.MeshNormalMaterial ) {
772 |
773 | _normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );
774 |
775 | _color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
776 |
777 | material.wireframe === true
778 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
779 | : fillPath( _color );
780 |
781 | } else {
782 |
783 | _color.setRGB( 1, 1, 1 );
784 |
785 | material.wireframe === true
786 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
787 | : fillPath( _color );
788 |
789 | }
790 |
791 | }
792 |
793 | //
794 |
795 | function drawTriangle( x0, y0, x1, y1, x2, y2 ) {
796 |
797 | _context.beginPath();
798 | _context.moveTo( x0, y0 );
799 | _context.lineTo( x1, y1 );
800 | _context.lineTo( x2, y2 );
801 | _context.closePath();
802 |
803 | }
804 |
805 | function strokePath( color, linewidth, linecap, linejoin ) {
806 |
807 | setLineWidth( linewidth );
808 | setLineCap( linecap );
809 | setLineJoin( linejoin );
810 | setStrokeStyle( color.getStyle() );
811 |
812 | _context.stroke();
813 |
814 | _elemBox.expandByScalar( linewidth * 2 );
815 |
816 | }
817 |
818 | function fillPath( color ) {
819 |
820 | setFillStyle( color.getStyle() );
821 | _context.fill();
822 |
823 | }
824 |
825 | function onTextureUpdate ( event ) {
826 |
827 | textureToPattern( event.target );
828 |
829 | }
830 |
831 | function textureToPattern( texture ) {
832 |
833 | if ( texture instanceof THREE.CompressedTexture ) return;
834 |
835 | var repeatX = texture.wrapS === THREE.RepeatWrapping;
836 | var repeatY = texture.wrapT === THREE.RepeatWrapping;
837 |
838 | var image = texture.image;
839 |
840 | var canvas = document.createElement( 'canvas' );
841 | canvas.width = image.width;
842 | canvas.height = image.height;
843 |
844 | var context = canvas.getContext( '2d' );
845 | context.setTransform( 1, 0, 0, - 1, 0, image.height );
846 | context.drawImage( image, 0, 0 );
847 |
848 | _patterns[ texture.id ] = _context.createPattern(
849 | canvas, repeatX === true && repeatY === true
850 | ? 'repeat'
851 | : repeatX === true && repeatY === false
852 | ? 'repeat-x'
853 | : repeatX === false && repeatY === true
854 | ? 'repeat-y'
855 | : 'no-repeat'
856 | );
857 |
858 | }
859 |
860 | function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) {
861 |
862 | if ( texture instanceof THREE.DataTexture ) return;
863 |
864 | if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) {
865 |
866 | if ( texture.image !== undefined && texture.image.width > 0 ) {
867 |
868 | textureToPattern( texture );
869 |
870 | }
871 |
872 | texture.addEventListener( 'update', onTextureUpdate );
873 |
874 | }
875 |
876 | var pattern = _patterns[ texture.id ];
877 |
878 | if ( pattern !== undefined ) {
879 |
880 | setFillStyle( pattern );
881 |
882 | } else {
883 |
884 | setFillStyle( 'rgba(0,0,0,1)' );
885 | _context.fill();
886 |
887 | return;
888 |
889 | }
890 |
891 | // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
892 |
893 | var a, b, c, d, e, f, det, idet,
894 | offsetX = texture.offset.x / texture.repeat.x,
895 | offsetY = texture.offset.y / texture.repeat.y,
896 | width = texture.image.width * texture.repeat.x,
897 | height = texture.image.height * texture.repeat.y;
898 |
899 | u0 = ( u0 + offsetX ) * width;
900 | v0 = ( v0 + offsetY ) * height;
901 |
902 | u1 = ( u1 + offsetX ) * width;
903 | v1 = ( v1 + offsetY ) * height;
904 |
905 | u2 = ( u2 + offsetX ) * width;
906 | v2 = ( v2 + offsetY ) * height;
907 |
908 | x1 -= x0; y1 -= y0;
909 | x2 -= x0; y2 -= y0;
910 |
911 | u1 -= u0; v1 -= v0;
912 | u2 -= u0; v2 -= v0;
913 |
914 | det = u1 * v2 - u2 * v1;
915 |
916 | if ( det === 0 ) return;
917 |
918 | idet = 1 / det;
919 |
920 | a = ( v2 * x1 - v1 * x2 ) * idet;
921 | b = ( v2 * y1 - v1 * y2 ) * idet;
922 | c = ( u1 * x2 - u2 * x1 ) * idet;
923 | d = ( u1 * y2 - u2 * y1 ) * idet;
924 |
925 | e = x0 - a * u0 - c * v0;
926 | f = y0 - b * u0 - d * v0;
927 |
928 | _context.save();
929 | _context.transform( a, b, c, d, e, f );
930 | _context.fill();
931 | _context.restore();
932 |
933 | }
934 |
935 | function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) {
936 |
937 | // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
938 |
939 | var a, b, c, d, e, f, det, idet,
940 | width = image.width - 1,
941 | height = image.height - 1;
942 |
943 | u0 *= width; v0 *= height;
944 | u1 *= width; v1 *= height;
945 | u2 *= width; v2 *= height;
946 |
947 | x1 -= x0; y1 -= y0;
948 | x2 -= x0; y2 -= y0;
949 |
950 | u1 -= u0; v1 -= v0;
951 | u2 -= u0; v2 -= v0;
952 |
953 | det = u1 * v2 - u2 * v1;
954 |
955 | idet = 1 / det;
956 |
957 | a = ( v2 * x1 - v1 * x2 ) * idet;
958 | b = ( v2 * y1 - v1 * y2 ) * idet;
959 | c = ( u1 * x2 - u2 * x1 ) * idet;
960 | d = ( u1 * y2 - u2 * y1 ) * idet;
961 |
962 | e = x0 - a * u0 - c * v0;
963 | f = y0 - b * u0 - d * v0;
964 |
965 | _context.save();
966 | _context.transform( a, b, c, d, e, f );
967 | _context.clip();
968 | _context.drawImage( image, 0, 0 );
969 | _context.restore();
970 |
971 | }
972 |
973 | // Hide anti-alias gaps
974 |
975 | function expand( v1, v2, pixels ) {
976 |
977 | var x = v2.x - v1.x, y = v2.y - v1.y,
978 | det = x * x + y * y, idet;
979 |
980 | if ( det === 0 ) return;
981 |
982 | idet = pixels / Math.sqrt( det );
983 |
984 | x *= idet; y *= idet;
985 |
986 | v2.x += x; v2.y += y;
987 | v1.x -= x; v1.y -= y;
988 |
989 | }
990 |
991 | // Context cached methods.
992 |
993 | function setOpacity( value ) {
994 |
995 | if ( _contextGlobalAlpha !== value ) {
996 |
997 | _context.globalAlpha = value;
998 | _contextGlobalAlpha = value;
999 |
1000 | }
1001 |
1002 | }
1003 |
1004 | function setBlending( value ) {
1005 |
1006 | if ( _contextGlobalCompositeOperation !== value ) {
1007 |
1008 | if ( value === THREE.NormalBlending ) {
1009 |
1010 | _context.globalCompositeOperation = 'source-over';
1011 |
1012 | } else if ( value === THREE.AdditiveBlending ) {
1013 |
1014 | _context.globalCompositeOperation = 'lighter';
1015 |
1016 | } else if ( value === THREE.SubtractiveBlending ) {
1017 |
1018 | _context.globalCompositeOperation = 'darker';
1019 |
1020 | }
1021 |
1022 | _contextGlobalCompositeOperation = value;
1023 |
1024 | }
1025 |
1026 | }
1027 |
1028 | function setLineWidth( value ) {
1029 |
1030 | if ( _contextLineWidth !== value ) {
1031 |
1032 | _context.lineWidth = value;
1033 | _contextLineWidth = value;
1034 |
1035 | }
1036 |
1037 | }
1038 |
1039 | function setLineCap( value ) {
1040 |
1041 | // "butt", "round", "square"
1042 |
1043 | if ( _contextLineCap !== value ) {
1044 |
1045 | _context.lineCap = value;
1046 | _contextLineCap = value;
1047 |
1048 | }
1049 |
1050 | }
1051 |
1052 | function setLineJoin( value ) {
1053 |
1054 | // "round", "bevel", "miter"
1055 |
1056 | if ( _contextLineJoin !== value ) {
1057 |
1058 | _context.lineJoin = value;
1059 | _contextLineJoin = value;
1060 |
1061 | }
1062 |
1063 | }
1064 |
1065 | function setStrokeStyle( value ) {
1066 |
1067 | if ( _contextStrokeStyle !== value ) {
1068 |
1069 | _context.strokeStyle = value;
1070 | _contextStrokeStyle = value;
1071 |
1072 | }
1073 |
1074 | }
1075 |
1076 | function setFillStyle( value ) {
1077 |
1078 | if ( _contextFillStyle !== value ) {
1079 |
1080 | _context.fillStyle = value;
1081 | _contextFillStyle = value;
1082 |
1083 | }
1084 |
1085 | }
1086 |
1087 | function setLineDash( value ) {
1088 |
1089 | if ( _contextLineDash.length !== value.length ) {
1090 |
1091 | _context.setLineDash( value );
1092 | _contextLineDash = value;
1093 |
1094 | }
1095 |
1096 | }
1097 |
1098 | };
1099 |
--------------------------------------------------------------------------------
/public/js/color.js:
--------------------------------------------------------------------------------
1 |
2 | var colors = new Array(
3 | [62,35,255],
4 | [60,255,60],
5 | [255,35,98],
6 | [45,175,230],
7 | [255,0,255],
8 | [255,128,0]);
9 |
10 |
11 | //
12 |
13 | var step = 0;
14 | //color table indices for:
15 | // current color left
16 | // next color left
17 | // current color right
18 | // next color right
19 | var colorIndices = [0,1,2,3];
20 |
21 | //transition speed
22 | var gradientSpeed = 0.002;
23 |
24 | function updateGradient()
25 | {
26 |
27 | if ( $===undefined ) return;
28 |
29 | var c0_0 = colors[colorIndices[0]];
30 | var c0_1 = colors[colorIndices[1]];
31 | var c1_0 = colors[colorIndices[2]];
32 | var c1_1 = colors[colorIndices[3]];
33 |
34 | var istep = 1 - step;
35 | var r1 = Math.round(istep * c0_0[0] + step * c0_1[0]);
36 | var g1 = Math.round(istep * c0_0[1] + step * c0_1[1]);
37 | var b1 = Math.round(istep * c0_0[2] + step * c0_1[2]);
38 | var color1 = "rgb("+r1+","+g1+","+b1+")";
39 |
40 | var r2 = Math.round(istep * c1_0[0] + step * c1_1[0]);
41 | var g2 = Math.round(istep * c1_0[1] + step * c1_1[1]);
42 | var b2 = Math.round(istep * c1_0[2] + step * c1_1[2]);
43 | var color2 = "rgb("+r2+","+g2+","+b2+")";
44 |
45 | $('.gradient').css({
46 | background: "-webkit-gradient(linear, left top, right top, from("+color1+"), to("+color2+"))"}).css({
47 | background: "-moz-linear-gradient(left, "+color1+" 0%, "+color2+" 100%)"});
48 |
49 | step += gradientSpeed;
50 | if ( step >= 1 )
51 | {
52 | step %= 1;
53 | colorIndices[0] = colorIndices[1];
54 | colorIndices[2] = colorIndices[3];
55 |
56 | //pick two new target color indices
57 | //do not pick the same as the current one
58 | colorIndices[1] = ( colorIndices[1] + Math.floor( 1 + Math.random() * (colors.length - 1))) % colors.length;
59 | colorIndices[3] = ( colorIndices[3] + Math.floor( 1 + Math.random() * (colors.length - 1))) % colors.length;
60 |
61 | }
62 | }
63 |
64 | setInterval(updateGradient,10);
--------------------------------------------------------------------------------
/public/js/djtx.min.js:
--------------------------------------------------------------------------------
1 | function normalize(t,s,e){return(t-s)/(e-s)}function denormalize(t,s,e){return t*(e-s)+s}function getRandomFloat(t,s){return Math.random()*(s-t)+t}function getRandomInt(t,s){return Math.floor(Math.random()*(s-t+1)+t)}class CursorSparkler{static modes={follow:"follow",trail:"trail"};static TranslateZero="translate3d(0, 0, 0)";constructor(t){(t=t||{}).mode=t.mode||CursorSparkler.modes.trail,t.numSparkles=t.numSparkles||20,t.sparkleFactor=1,t.sparkleDurationRange=[50,500],t.sparkleDistanceRange=[40,100],t.sparkleSizeRange=[1,5],this.options=t,this.el=document.createElement("div"),this.el.style.position="absolute",this.el.style.top=-this.options.sparkleSizeRange[1]+"px",this.el.style.left=-this.options.sparkleSizeRange[1]+"px",this.el.style.zIndex="10000",this.el.style.pointerEvents="none",this.el.style.width="1px",this.el.style.height="1px",this.shouldAnimate=!0,this.sparkles=[],this.onMouseMove=this.onMouseMove.bind(this),this.onMouseDown=this.onMouseDown.bind(this),this.onMouseUp=this.onMouseUp.bind(this),this.onAnimationFrame=this.onAnimationFrame.bind(this)}listen(){window.addEventListener("mousemove",this.onMouseMove),window.addEventListener("mousedown",this.onMouseDown),window.addEventListener("mouseup",this.onMouseUp),document.body.appendChild(this.el),requestAnimationFrame(this.onAnimationFrame)}destroy(){this.el.parentElement.removeChild(this.el),window.removeEventListener("mousemove",this.onMouseMove),this.shouldAnimate=!1}render(t){if(this.options.disabled)"none"!==this.el.style.display&&(this.el.style.display="none");else{"block"!==this.el.style.display&&(this.el.style.display="block"),this.options.mode===CursorSparkler.modes.follow?this.el.style.transform="translate3d("+this.x+"px, "+this.y+"px, 0)":this.el.style.transform!==CursorSparkler.TranslateZero&&(this.el.style.transform=CursorSparkler.TranslateZero);var s=this.options.numSparkles;this.sparkles.length>s&&(this.sparkles.slice(s).forEach((function(t){t.destroy()})),this.sparkles.length=s);for(var e,i=0;i=e.options.startTime+e.options.duration&&(e.destroy(),this.sparkles[i]=this.sparkle(t+100),this.el.appendChild(this.sparkles[i].el))):(this.sparkles[i]=this.sparkle(t+getRandomInt(0,800/this.options.sparkleFactor)),this.el.appendChild(this.sparkles[i].el))}}sparkle(t){var s=this.options,e=s.sparkleFactor,i=s.sparkleDurationRange,o=s.sparkleDistanceRange,r=s.sparkleSizeRange,n=s.mode===CursorSparkler.modes.trail?this.x:0,a=s.mode===CursorSparkler.modes.trail?this.y:0;return n+=s.sparkleSizeRange[1],a+=s.sparkleSizeRange[1],new Sparkle({window:this.window,startTime:t,startX:n,startY:a,duration:getRandomInt(i[0],i[1]/e),distance:getRandomInt(o[0],o[1]*(1===e?1:e/4)),size:getRandomInt(r[0],r[1]*(1===e?1:e/3))})}onMouseMove(t){this.x=t.pageX,this.y=t.pageY}onMouseDown(t){this.originalSparkleFactor?this.options.sparkleFactor=this.originalSparkleFactor:this.originalSparkleFactor=this.options.sparkleFactor,this.options.sparkleFactor*=4}onMouseUp(t){this.options.sparkleFactor=this.originalSparkleFactor||1,delete this.originalSparkleFactor}onAnimationFrame(t){this.shouldAnimate&&(this.start||(this.start=t),this.render(t),requestAnimationFrame(this.onAnimationFrame))}}class Sparkle{static fantasticColors=["yellow","pink","red","orange","purple","cyan"];constructor(t){(t=t||{}).duration=t.duration||getRandomInt(50,500),t.direction=t.direction||getRandomFloat(0,2*Math.PI),t.distance=t.distance||getRandomInt(40,100),t.size=t.size||getRandomInt(1,5),t.color=t.color||Sparkle.getFantasticColor(),t.startTime=t.startTime||0,this.options=t,this.el=document.createElement("div"),this.el.style.position="absolute",this.el.style.background=this.options.color,this.el.style.width=this.options.size+"px",this.el.style.height=this.options.size+"px",this.el.style.borderRadius="50%",this.el.style.transform="translate3d(0,0,0)"}static getFantasticColor(){return Sparkle.fantasticColors[~~(Sparkle.fantasticColors.length*Math.random())]}destroy(){this.el.parentElement.removeChild(this.el)}render(t){var s=normalize(t,this.options.startTime,this.options.startTime+this.options.duration),e=this.options.startX+Math.sin(this.options.direction)*this.options.distance*s,i=this.options.startY+Math.cos(this.options.direction)*this.options.distance*s;this.el.style.opacity=(1-s).toString(),this.el.style.transform="translate3d("+e+"px, "+i+"px, 0)"}}var sparkler=new CursorSparkler({mode:"trail"});function bootstrap(){sparkler.listen()}bootstrap();
--------------------------------------------------------------------------------
/public/js/projector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | * @author supereggbert / http://www.paulbrunt.co.uk/
4 | * @author julianwa / https://github.com/julianwa
5 | */
6 |
7 | THREE.RenderableObject = function () {
8 |
9 | this.id = 0;
10 |
11 | this.object = null;
12 | this.z = 0;
13 |
14 | };
15 |
16 | //
17 |
18 | THREE.RenderableFace = function () {
19 |
20 | this.id = 0;
21 |
22 | this.v1 = new THREE.RenderableVertex();
23 | this.v2 = new THREE.RenderableVertex();
24 | this.v3 = new THREE.RenderableVertex();
25 |
26 | this.normalModel = new THREE.Vector3();
27 |
28 | this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
29 | this.vertexNormalsLength = 0;
30 |
31 | this.color = new THREE.Color();
32 | this.material = null;
33 | this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ];
34 |
35 | this.z = 0;
36 |
37 | };
38 |
39 | //
40 |
41 | THREE.RenderableVertex = function () {
42 |
43 | this.position = new THREE.Vector3();
44 | this.positionWorld = new THREE.Vector3();
45 | this.positionScreen = new THREE.Vector4();
46 |
47 | this.visible = true;
48 |
49 | };
50 |
51 | THREE.RenderableVertex.prototype.copy = function ( vertex ) {
52 |
53 | this.positionWorld.copy( vertex.positionWorld );
54 | this.positionScreen.copy( vertex.positionScreen );
55 |
56 | };
57 |
58 | //
59 |
60 | THREE.RenderableLine = function () {
61 |
62 | this.id = 0;
63 |
64 | this.v1 = new THREE.RenderableVertex();
65 | this.v2 = new THREE.RenderableVertex();
66 |
67 | this.vertexColors = [ new THREE.Color(), new THREE.Color() ];
68 | this.material = null;
69 |
70 | this.z = 0;
71 |
72 | };
73 |
74 | //
75 |
76 | THREE.RenderableSprite = function () {
77 |
78 | this.id = 0;
79 |
80 | this.object = null;
81 |
82 | this.x = 0;
83 | this.y = 0;
84 | this.z = 0;
85 |
86 | this.rotation = 0;
87 | this.scale = new THREE.Vector2();
88 |
89 | this.material = null;
90 |
91 | };
92 |
93 | //
94 |
95 | THREE.Projector = function () {
96 |
97 | var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
98 | _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
99 | _face, _faceCount, _facePool = [], _facePoolLength = 0,
100 | _line, _lineCount, _linePool = [], _linePoolLength = 0,
101 | _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0,
102 |
103 | _renderData = { objects: [], lights: [], elements: [] },
104 |
105 | _vector3 = new THREE.Vector3(),
106 | _vector4 = new THREE.Vector4(),
107 |
108 | _clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ),
109 | _boundingBox = new THREE.Box3(),
110 | _points3 = new Array( 3 ),
111 | _points4 = new Array( 4 ),
112 |
113 | _viewMatrix = new THREE.Matrix4(),
114 | _viewProjectionMatrix = new THREE.Matrix4(),
115 |
116 | _modelMatrix,
117 | _modelViewProjectionMatrix = new THREE.Matrix4(),
118 |
119 | _normalMatrix = new THREE.Matrix3(),
120 |
121 | _frustum = new THREE.Frustum(),
122 |
123 | _clippedVertex1PositionScreen = new THREE.Vector4(),
124 | _clippedVertex2PositionScreen = new THREE.Vector4();
125 |
126 | //
127 |
128 | this.projectVector = function ( vector, camera ) {
129 |
130 | console.warn( 'THREE.Projector: .projectVector() is now vector.project().' );
131 | vector.project( camera );
132 |
133 | };
134 |
135 | this.unprojectVector = function ( vector, camera ) {
136 |
137 | console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );
138 | vector.unproject( camera );
139 |
140 | };
141 |
142 | this.pickingRay = function ( vector, camera ) {
143 |
144 | console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );
145 |
146 | };
147 |
148 | //
149 |
150 | var RenderList = function () {
151 |
152 | var normals = [];
153 | var uvs = [];
154 |
155 | var object = null;
156 | var material = null;
157 |
158 | var normalMatrix = new THREE.Matrix3();
159 |
160 | var setObject = function ( value ) {
161 |
162 | object = value;
163 | material = object.material;
164 |
165 | normalMatrix.getNormalMatrix( object.matrixWorld );
166 |
167 | normals.length = 0;
168 | uvs.length = 0;
169 |
170 | };
171 |
172 | var projectVertex = function ( vertex ) {
173 |
174 | var position = vertex.position;
175 | var positionWorld = vertex.positionWorld;
176 | var positionScreen = vertex.positionScreen;
177 |
178 | positionWorld.copy( position ).applyMatrix4( _modelMatrix );
179 | positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix );
180 |
181 | var invW = 1 / positionScreen.w;
182 |
183 | positionScreen.x *= invW;
184 | positionScreen.y *= invW;
185 | positionScreen.z *= invW;
186 |
187 | vertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 &&
188 | positionScreen.y >= - 1 && positionScreen.y <= 1 &&
189 | positionScreen.z >= - 1 && positionScreen.z <= 1;
190 |
191 | };
192 |
193 | var pushVertex = function ( x, y, z ) {
194 |
195 | _vertex = getNextVertexInPool();
196 | _vertex.position.set( x, y, z );
197 |
198 | projectVertex( _vertex );
199 |
200 | };
201 |
202 | var pushNormal = function ( x, y, z ) {
203 |
204 | normals.push( x, y, z );
205 |
206 | };
207 |
208 | var pushUv = function ( x, y ) {
209 |
210 | uvs.push( x, y );
211 |
212 | };
213 |
214 | var checkTriangleVisibility = function ( v1, v2, v3 ) {
215 |
216 | if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true;
217 |
218 | _points3[ 0 ] = v1.positionScreen;
219 | _points3[ 1 ] = v2.positionScreen;
220 | _points3[ 2 ] = v3.positionScreen;
221 |
222 | return _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) );
223 |
224 | };
225 |
226 | var checkBackfaceCulling = function ( v1, v2, v3 ) {
227 |
228 | return ( ( v3.positionScreen.x - v1.positionScreen.x ) *
229 | ( v2.positionScreen.y - v1.positionScreen.y ) -
230 | ( v3.positionScreen.y - v1.positionScreen.y ) *
231 | ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;
232 |
233 | };
234 |
235 | var pushLine = function ( a, b ) {
236 |
237 | var v1 = _vertexPool[ a ];
238 | var v2 = _vertexPool[ b ];
239 |
240 | _line = getNextLineInPool();
241 |
242 | _line.id = object.id;
243 | _line.v1.copy( v1 );
244 | _line.v2.copy( v2 );
245 | _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2;
246 |
247 | _line.material = object.material;
248 |
249 | _renderData.elements.push( _line );
250 |
251 | };
252 |
253 | var pushTriangle = function ( a, b, c ) {
254 |
255 | var v1 = _vertexPool[ a ];
256 | var v2 = _vertexPool[ b ];
257 | var v3 = _vertexPool[ c ];
258 |
259 | if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return;
260 |
261 | if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) {
262 |
263 | _face = getNextFaceInPool();
264 |
265 | _face.id = object.id;
266 | _face.v1.copy( v1 );
267 | _face.v2.copy( v2 );
268 | _face.v3.copy( v3 );
269 | _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
270 |
271 | for ( var i = 0; i < 3; i ++ ) {
272 |
273 | var offset = arguments[ i ] * 3;
274 | var normal = _face.vertexNormalsModel[ i ];
275 |
276 | normal.set( normals[ offset ], normals[ offset + 1 ], normals[ offset + 2 ] );
277 | normal.applyMatrix3( normalMatrix ).normalize();
278 |
279 | var offset2 = arguments[ i ] * 2;
280 |
281 | var uv = _face.uvs[ i ];
282 | uv.set( uvs[ offset2 ], uvs[ offset2 + 1 ] );
283 |
284 | }
285 |
286 | _face.vertexNormalsLength = 3;
287 |
288 | _face.material = object.material;
289 |
290 | _renderData.elements.push( _face );
291 |
292 | }
293 |
294 | };
295 |
296 | return {
297 | setObject: setObject,
298 | projectVertex: projectVertex,
299 | checkTriangleVisibility: checkTriangleVisibility,
300 | checkBackfaceCulling: checkBackfaceCulling,
301 | pushVertex: pushVertex,
302 | pushNormal: pushNormal,
303 | pushUv: pushUv,
304 | pushLine: pushLine,
305 | pushTriangle: pushTriangle
306 | }
307 |
308 | };
309 |
310 | var renderList = new RenderList();
311 |
312 | this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
313 |
314 | _faceCount = 0;
315 | _lineCount = 0;
316 | _spriteCount = 0;
317 |
318 | _renderData.elements.length = 0;
319 |
320 | if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
321 | if ( camera.parent === undefined ) camera.updateMatrixWorld();
322 |
323 | _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) );
324 | _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
325 |
326 | _frustum.setFromMatrix( _viewProjectionMatrix );
327 |
328 | //
329 |
330 | _objectCount = 0;
331 |
332 | _renderData.objects.length = 0;
333 | _renderData.lights.length = 0;
334 |
335 | scene.traverseVisible( function ( object ) {
336 |
337 | if ( object instanceof THREE.Light ) {
338 |
339 | _renderData.lights.push( object );
340 |
341 | } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) {
342 |
343 | if ( object.material.visible === false ) return;
344 |
345 | if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {
346 |
347 | _object = getNextObjectInPool();
348 | _object.id = object.id;
349 | _object.object = object;
350 |
351 | _vector3.setFromMatrixPosition( object.matrixWorld );
352 | _vector3.applyProjection( _viewProjectionMatrix );
353 | _object.z = _vector3.z;
354 |
355 | _renderData.objects.push( _object );
356 |
357 | }
358 |
359 | }
360 |
361 | } );
362 |
363 | if ( sortObjects === true ) {
364 |
365 | _renderData.objects.sort( painterSort );
366 |
367 | }
368 |
369 | //
370 |
371 | for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) {
372 |
373 | var object = _renderData.objects[ o ].object;
374 | var geometry = object.geometry;
375 |
376 | renderList.setObject( object );
377 |
378 | _modelMatrix = object.matrixWorld;
379 |
380 | _vertexCount = 0;
381 |
382 | if ( object instanceof THREE.Mesh ) {
383 |
384 | if ( geometry instanceof THREE.BufferGeometry ) {
385 |
386 | var attributes = geometry.attributes;
387 | var offsets = geometry.offsets;
388 |
389 | if ( attributes.position === undefined ) continue;
390 |
391 | var positions = attributes.position.array;
392 |
393 | for ( var i = 0, l = positions.length; i < l; i += 3 ) {
394 |
395 | renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
396 |
397 | }
398 |
399 | if ( attributes.normal !== undefined ) {
400 |
401 | var normals = attributes.normal.array;
402 |
403 | for ( var i = 0, l = normals.length; i < l; i += 3 ) {
404 |
405 | renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] );
406 |
407 | }
408 |
409 | }
410 |
411 | if ( attributes.uv !== undefined ) {
412 |
413 | var uvs = attributes.uv.array;
414 |
415 | for ( var i = 0, l = uvs.length; i < l; i += 2 ) {
416 |
417 | renderList.pushUv( uvs[ i ], uvs[ i + 1 ] );
418 |
419 | }
420 |
421 | }
422 |
423 | if ( attributes.index !== undefined ) {
424 |
425 | var indices = attributes.index.array;
426 |
427 | if ( offsets.length > 0 ) {
428 |
429 | for ( var o = 0; o < offsets.length; o ++ ) {
430 |
431 | var offset = offsets[ o ];
432 | var index = offset.index;
433 |
434 | for ( var i = offset.start, l = offset.start + offset.count; i < l; i += 3 ) {
435 |
436 | renderList.pushTriangle( indices[ i ] + index, indices[ i + 1 ] + index, indices[ i + 2 ] + index );
437 |
438 | }
439 |
440 | }
441 |
442 | } else {
443 |
444 | for ( var i = 0, l = indices.length; i < l; i += 3 ) {
445 |
446 | renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
447 |
448 | }
449 |
450 | }
451 |
452 | } else {
453 |
454 | for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) {
455 |
456 | renderList.pushTriangle( i, i + 1, i + 2 );
457 |
458 | }
459 |
460 | }
461 |
462 | } else if ( geometry instanceof THREE.Geometry ) {
463 |
464 | var vertices = geometry.vertices;
465 | var faces = geometry.faces;
466 | var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
467 |
468 | _normalMatrix.getNormalMatrix( _modelMatrix );
469 |
470 | var material = object.material;
471 |
472 | var isFaceMaterial = material instanceof THREE.MeshFaceMaterial;
473 | var objectMaterials = isFaceMaterial === true ? object.material : null;
474 |
475 | for ( var v = 0, vl = vertices.length; v < vl; v ++ ) {
476 |
477 | var vertex = vertices[ v ];
478 |
479 | _vector3.copy( vertex );
480 |
481 | if ( material.morphTargets === true ) {
482 |
483 | var morphTargets = geometry.morphTargets;
484 | var morphInfluences = object.morphTargetInfluences;
485 |
486 | for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
487 |
488 | var influence = morphInfluences[ t ];
489 |
490 | if ( influence === 0 ) continue;
491 |
492 | var target = morphTargets[ t ];
493 | var targetVertex = target.vertices[ v ];
494 |
495 | _vector3.x += ( targetVertex.x - vertex.x ) * influence;
496 | _vector3.y += ( targetVertex.y - vertex.y ) * influence;
497 | _vector3.z += ( targetVertex.z - vertex.z ) * influence;
498 |
499 | }
500 |
501 | }
502 |
503 | renderList.pushVertex( _vector3.x, _vector3.y, _vector3.z );
504 |
505 | }
506 |
507 | for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
508 |
509 | var face = faces[ f ];
510 |
511 | var material = isFaceMaterial === true
512 | ? objectMaterials.materials[ face.materialIndex ]
513 | : object.material;
514 |
515 | if ( material === undefined ) continue;
516 |
517 | var side = material.side;
518 |
519 | var v1 = _vertexPool[ face.a ];
520 | var v2 = _vertexPool[ face.b ];
521 | var v3 = _vertexPool[ face.c ];
522 |
523 | if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue;
524 |
525 | var visible = renderList.checkBackfaceCulling( v1, v2, v3 );
526 |
527 | if ( side !== THREE.DoubleSide ) {
528 | if ( side === THREE.FrontSide && visible === false ) continue;
529 | if ( side === THREE.BackSide && visible === true ) continue;
530 | }
531 |
532 | _face = getNextFaceInPool();
533 |
534 | _face.id = object.id;
535 | _face.v1.copy( v1 );
536 | _face.v2.copy( v2 );
537 | _face.v3.copy( v3 );
538 |
539 | _face.normalModel.copy( face.normal );
540 |
541 | if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
542 |
543 | _face.normalModel.negate();
544 |
545 | }
546 |
547 | _face.normalModel.applyMatrix3( _normalMatrix ).normalize();
548 |
549 | var faceVertexNormals = face.vertexNormals;
550 |
551 | for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) {
552 |
553 | var normalModel = _face.vertexNormalsModel[ n ];
554 | normalModel.copy( faceVertexNormals[ n ] );
555 |
556 | if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
557 |
558 | normalModel.negate();
559 |
560 | }
561 |
562 | normalModel.applyMatrix3( _normalMatrix ).normalize();
563 |
564 | }
565 |
566 | _face.vertexNormalsLength = faceVertexNormals.length;
567 |
568 | var vertexUvs = faceVertexUvs[ f ];
569 |
570 | if ( vertexUvs !== undefined ) {
571 |
572 | for ( var u = 0; u < 3; u ++ ) {
573 |
574 | _face.uvs[ u ].copy( vertexUvs[ u ] );
575 |
576 | }
577 |
578 | }
579 |
580 | _face.color = face.color;
581 | _face.material = material;
582 |
583 | _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
584 |
585 | _renderData.elements.push( _face );
586 |
587 | }
588 |
589 | }
590 |
591 | } else if ( object instanceof THREE.Line ) {
592 |
593 | if ( geometry instanceof THREE.BufferGeometry ) {
594 |
595 | var attributes = geometry.attributes;
596 |
597 | if ( attributes.position !== undefined ) {
598 |
599 | var positions = attributes.position.array;
600 |
601 | for ( var i = 0, l = positions.length; i < l; i += 3 ) {
602 |
603 | renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
604 |
605 | }
606 |
607 | if ( attributes.index !== undefined ) {
608 |
609 | var indices = attributes.index.array;
610 |
611 | for ( var i = 0, l = indices.length; i < l; i += 2 ) {
612 |
613 | renderList.pushLine( indices[ i ], indices[ i + 1 ] );
614 |
615 | }
616 |
617 | } else {
618 |
619 | var step = object.mode === THREE.LinePieces ? 2 : 1;
620 |
621 | for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) {
622 |
623 | renderList.pushLine( i, i + 1 );
624 |
625 | }
626 |
627 | }
628 |
629 | }
630 |
631 | } else if ( geometry instanceof THREE.Geometry ) {
632 |
633 | _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
634 |
635 | var vertices = object.geometry.vertices;
636 |
637 | if ( vertices.length === 0 ) continue;
638 |
639 | v1 = getNextVertexInPool();
640 | v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix );
641 |
642 | // Handle LineStrip and LinePieces
643 | var step = object.mode === THREE.LinePieces ? 2 : 1;
644 |
645 | for ( var v = 1, vl = vertices.length; v < vl; v ++ ) {
646 |
647 | v1 = getNextVertexInPool();
648 | v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix );
649 |
650 | if ( ( v + 1 ) % step > 0 ) continue;
651 |
652 | v2 = _vertexPool[ _vertexCount - 2 ];
653 |
654 | _clippedVertex1PositionScreen.copy( v1.positionScreen );
655 | _clippedVertex2PositionScreen.copy( v2.positionScreen );
656 |
657 | if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) {
658 |
659 | // Perform the perspective divide
660 | _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );
661 | _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );
662 |
663 | _line = getNextLineInPool();
664 |
665 | _line.id = object.id;
666 | _line.v1.positionScreen.copy( _clippedVertex1PositionScreen );
667 | _line.v2.positionScreen.copy( _clippedVertex2PositionScreen );
668 |
669 | _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );
670 |
671 | _line.material = object.material;
672 |
673 | if ( object.material.vertexColors === THREE.VertexColors ) {
674 |
675 | _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] );
676 | _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] );
677 |
678 | }
679 |
680 | _renderData.elements.push( _line );
681 |
682 | }
683 |
684 | }
685 |
686 | }
687 |
688 | } else if ( object instanceof THREE.Sprite ) {
689 |
690 | _vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 );
691 | _vector4.applyMatrix4( _viewProjectionMatrix );
692 |
693 | var invW = 1 / _vector4.w;
694 |
695 | _vector4.z *= invW;
696 |
697 | if ( _vector4.z >= - 1 && _vector4.z <= 1 ) {
698 |
699 | _sprite = getNextSpriteInPool();
700 | _sprite.id = object.id;
701 | _sprite.x = _vector4.x * invW;
702 | _sprite.y = _vector4.y * invW;
703 | _sprite.z = _vector4.z;
704 | _sprite.object = object;
705 |
706 | _sprite.rotation = object.rotation;
707 |
708 | _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) );
709 | _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) );
710 |
711 | _sprite.material = object.material;
712 |
713 | _renderData.elements.push( _sprite );
714 |
715 | }
716 |
717 | }
718 |
719 | }
720 |
721 | if ( sortElements === true ) {
722 |
723 | _renderData.elements.sort( painterSort );
724 |
725 | }
726 |
727 | return _renderData;
728 |
729 | };
730 |
731 | // Pools
732 |
733 | function getNextObjectInPool() {
734 |
735 | if ( _objectCount === _objectPoolLength ) {
736 |
737 | var object = new THREE.RenderableObject();
738 | _objectPool.push( object );
739 | _objectPoolLength ++;
740 | _objectCount ++;
741 | return object;
742 |
743 | }
744 |
745 | return _objectPool[ _objectCount ++ ];
746 |
747 | }
748 |
749 | function getNextVertexInPool() {
750 |
751 | if ( _vertexCount === _vertexPoolLength ) {
752 |
753 | var vertex = new THREE.RenderableVertex();
754 | _vertexPool.push( vertex );
755 | _vertexPoolLength ++;
756 | _vertexCount ++;
757 | return vertex;
758 |
759 | }
760 |
761 | return _vertexPool[ _vertexCount ++ ];
762 |
763 | }
764 |
765 | function getNextFaceInPool() {
766 |
767 | if ( _faceCount === _facePoolLength ) {
768 |
769 | var face = new THREE.RenderableFace();
770 | _facePool.push( face );
771 | _facePoolLength ++;
772 | _faceCount ++;
773 | return face;
774 |
775 | }
776 |
777 | return _facePool[ _faceCount ++ ];
778 |
779 |
780 | }
781 |
782 | function getNextLineInPool() {
783 |
784 | if ( _lineCount === _linePoolLength ) {
785 |
786 | var line = new THREE.RenderableLine();
787 | _linePool.push( line );
788 | _linePoolLength ++;
789 | _lineCount ++
790 | return line;
791 |
792 | }
793 |
794 | return _linePool[ _lineCount ++ ];
795 |
796 | }
797 |
798 | function getNextSpriteInPool() {
799 |
800 | if ( _spriteCount === _spritePoolLength ) {
801 |
802 | var sprite = new THREE.RenderableSprite();
803 | _spritePool.push( sprite );
804 | _spritePoolLength ++;
805 | _spriteCount ++
806 | return sprite;
807 |
808 | }
809 |
810 | return _spritePool[ _spriteCount ++ ];
811 |
812 | }
813 |
814 | //
815 |
816 | function painterSort( a, b ) {
817 |
818 | if ( a.z !== b.z ) {
819 |
820 | return b.z - a.z;
821 |
822 | } else if ( a.id !== b.id ) {
823 |
824 | return a.id - b.id;
825 |
826 | } else {
827 |
828 | return 0;
829 |
830 | }
831 |
832 | }
833 |
834 | function clipLine( s1, s2 ) {
835 |
836 | var alpha1 = 0, alpha2 = 1,
837 |
838 | // Calculate the boundary coordinate of each vertex for the near and far clip planes,
839 | // Z = -1 and Z = +1, respectively.
840 | bc1near = s1.z + s1.w,
841 | bc2near = s2.z + s2.w,
842 | bc1far = - s1.z + s1.w,
843 | bc2far = - s2.z + s2.w;
844 |
845 | if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {
846 |
847 | // Both vertices lie entirely within all clip planes.
848 | return true;
849 |
850 | } else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) {
851 |
852 | // Both vertices lie entirely outside one of the clip planes.
853 | return false;
854 |
855 | } else {
856 |
857 | // The line segment spans at least one clip plane.
858 |
859 | if ( bc1near < 0 ) {
860 |
861 | // v1 lies outside the near plane, v2 inside
862 | alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );
863 |
864 | } else if ( bc2near < 0 ) {
865 |
866 | // v2 lies outside the near plane, v1 inside
867 | alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );
868 |
869 | }
870 |
871 | if ( bc1far < 0 ) {
872 |
873 | // v1 lies outside the far plane, v2 inside
874 | alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );
875 |
876 | } else if ( bc2far < 0 ) {
877 |
878 | // v2 lies outside the far plane, v2 inside
879 | alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );
880 |
881 | }
882 |
883 | if ( alpha2 < alpha1 ) {
884 |
885 | // The line segment spans two boundaries, but is outside both of them.
886 | // (This can't happen when we're only clipping against just near/far but good
887 | // to leave the check here for future usage if other clip planes are added.)
888 | return false;
889 |
890 | } else {
891 |
892 | // Update the s1 and s2 vertices to match the clipped line segment.
893 | s1.lerp( s2, alpha1 );
894 | s2.lerp( s1, 1 - alpha2 );
895 |
896 | return true;
897 |
898 | }
899 |
900 | }
901 |
902 | }
903 |
904 | };
905 |
--------------------------------------------------------------------------------
/public/web/netflix.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/web/nf.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youshandefeiyang/sub-web-modify/68422ba384475acb791fd65eb30ada7f38634a6b/public/web/nf.ico
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/assets/css/dark.min.css:
--------------------------------------------------------------------------------
1 | .dark-mode .channel{display:inline-block!important}.dark-mode .el-tabs__item:hover,.dark-mode .el-tabs__item.is-active{color:#409eff}.dark-mode .el-tabs__item,.dark-mode .el-dialog__title{color:#fff}.dark-mode .el-card{background:0 0!important}.dark-mode .el-popover{background:#000!important}.dark-mode .el-dialog{border:1px solid #313131!important}.dark-mode .el-message-box__title,.dark-mode .el-message-box__content{color:#fff!important}.dark-mode .el-collapse-item__content{padding-bottom:0!important}.dark-mode #canvas,dark-mode .canvas-wrap{display:none!important}.dark-mode .el-message-box{background-color:#000!important}.dark-mode #yejian,.dark-mode .bilibili,.dark-mode .dianbao,.dark-mode .youguan{display:none!important}.dark-mode .el-dialog__body,.dark-mode .el-dialog__footer,.dark-mode .el-dialog__header{background-color:#000!important;color:#fff!important}.dark-mode .el-input__count{color:#fff!important;background:rgba(128,128,128,.7)!important}.dark-mode .el-message-box__headerbtn .el-message-box__close{color:#fff!important}.dark-mode .el-textarea{background-color:rgba(255,255,255,0)!important;color:#fff!important}.dark-mode .el-notification__closeBtn,.dark-mode .el-notification__title,.dark-mode .el-notification__content,.dark-mode .el-message .el-icon-error,.dark-mode .el-message .el-icon-success,.dark-mode .el-notification .el-icon-warning,.dark-mode .el-message .el-icon-warning,.dark-mode .el-message--error .el-message__content,.dark-mode .el-message--success .el-message__content,.dark-mode .el-message--warning .el-message__content{color:#fff!important}.dark-mode .el-notification,.dark-mode .el-message--error,.dark-mode .el-message--success,.dark-mode .el-message--warning{background-color:rgb(0,0,0,.7)!important;border-color:#fff!important}.dark-mode .el-button--zhuti{color:#fff!important;font-size:14px!important;border:0!important;width:54px!important;padding:0 0!important;background-color:#000!important}.dark-mode .el-button--zhuti:active,.dark-mode .el-button--zhuti:focus,.dark-mode .el-button--zhuti:hover{color:#fff!important}.dark-mode,.dark-mode .el-button--danger,.dark-mode .el-button--primary,.dark-mode .el-button--success,.dark-mode .el-button--warning{background-color:#000!important}.dark-mode .el-collapse-item .el-button--limr{color:#fff!important;background:rgba(255,255,255,.5)!important;border-radius:4px!important;height:32px!important}.dark-mode .el-button--limr:focus,.dark-mode .el-button--limr:hover,.dark-mode .el-collapse-item .el-button--limr:active{color:#fff!important;border-color:#dcdfe6!important}.dark-mode .el-collapse-item__wrap{background:0 0!important;border-bottom:none!important}.dark-mode .el-collapse{border-top:none!important;border-bottom:none!important}.dark-mode .el-collapse-item__header{background:0 0!important;border-bottom:none!important;height:auto!important}.dark-mode .el-collapse-item__arrow{display:none!important}.dark-mode .el-card__header{background:rgba(0,0,0,.8)!important;position:relative;color:#fff}.dark-mode .el-card__body{background:rgba(0,0,0,.8);color:#000}.dark-mode .el-checkbox,.dark-mode .el-form-item__label,.dark-mode .el-input-group__append,.dark-mode .el-input__inner,.dark-mode .el-radio,.dark-mode .el-select .el-input .el-select__caret,.dark-mode .el-textarea__inner{color:#fff!important}.dark-mode .el-divider{background:rgba(255,255,255,.5)!important}.dark-mode .el-divider__text{background-color:#000!important;color:#fff!important}.dark-mode .el-input__inner,.dark-mode .el-textarea__inner{background:rgba(255,255,255,.5)!important}.dark-mode .el-input.is-active .el-input__inner,.dark-mode .el-input__inner:focus,.dark-mode .el-select .el-input.is-focus .el-input__inner,.dark-mode .el-textarea__inner:focus{border-color:#999!important}.dark-mode .el-checkbox.is-bordered,.dark-mode .el-checkbox__inner{border:1px solid #fff!important}.dark-mode .el-checkbox.is-bordered.is-checked{border-color:#fff!important}.dark-mode .el-radio__input.is-checked+.el-radio__label{color:#000!important}.dark-mode .el-radio__input.is-checked .el-radio__inner{border-color:#000!important;background:#000!important}.dark-mode .el-checkbox__input.is-checked .el-checkbox__inner,.dark-mode .el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#000!important}.dark-mode .el-checkbox__input.is-checked+.el-checkbox__label{color:#fff!important}.dark-mode .el-row--flex .el-checkbox__input.is-checked+.el-checkbox__label{color:#fff!important}.dark-mode .el-row--flex .el-checkbox__input.is-checked .el-checkbox__inner,.dark-mode .el-row--flex .el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#000!important;border-color:#fff!important}.dark-mode .el-row--flex .el-checkbox__inner:hover{border-color:#000!important}.dark-mode .el-row--flex .el-checkbox__input.is-focus .el-checkbox__inner{border-color:#fff!important}.dark-mode .el-checkbox.is-bordered.is-checked{background:rgba(0,0,0,.88)!important;color:#fff!important}.dark-mode .el-row span .el-button{background:0 0!important;border:1px solid #fff!important;color:#fff!important}.dark-mode .el-row span .el-button:focus,.dark-mode .el-row span .el-button:hover{color:#fff!important;background:rgba(0,0,0,.88)!important}.dark-mode .el-divider__text{border:1px solid rgba(0,0,0,.4);border-radius:3px}.dark-mode .el-select-dropdown__item.selected{background:#333!important;color:#fff!important}.dark-mode .el-input.is-disabled .el-input__inner{border:none}.dark-mode .el-form-item:last-child .el-button--primary{background-color:#303133!important;border-color:#303133!important}.dark-mode .el-form-item:last-child .el-button--primary:focus,.dark-mode .el-form-item:last-child .el-button--primary:hover{background:#666!important;border-color:#666!important}.dark-mode .el-form-item:last-child .el-button--primary.is-disabled{background:#999!important;border-color:#999!important}.dark-mode .el-row--flex{align-items:center;flex-wrap:wrap;justify-content:space-between}.dark-mode .el-row--flex .el-col-24{width:auto!important;margin:5px 0}.dark-mode .el-select-group__title{color:#999!important;background:rgba(0,0,0,.1);font-weight:600}.dark-mode .el-input-group__append button.el-button{border-color:#303133!important;background-color:#303133!important;color:#fff!important}.dark-mode .el-input-group__append,.dark-mode .el-input-group__prepend{border-color:#303133!important;background-color:#303133!important}.dark-mode .el-input__inner::-webkit-input-placeholder,.dark-mode .el-textarea__inner::-webkit-input-placeholder{color:rgba(255,255,255,.6)!important}.dark-mode .el-input__inner:-moz-placeholder,.dark-mode .el-textarea__inner:-moz-placeholder{color:rgba(255,255,255,.6)!important}.dark-mode .el-input__inner::-moz-placeholder,.dark-mode .el-textarea__inner::-moz-placeholder{color:rgba(255,255,255,.6)!important}.dark-mode .el-input__inner:-ms-input-placeholder,.dark-mode .el-textarea__inner:-ms-input-placeholder{color:rgba(255,255,255,.6)!important}.dark-mode .el-popover.el-popper .el-row:focus,.dark-mode .el-popover.el-popper .popper__arrow{outline:0}.dark-mode .el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{box-shadow:none!important}.dark-mode .el-radio__inner:hover{border-color:#000!important}.dark-mode .el-radio__inner{border:1px solid #999!important}.dark-mode .dialog-footer .el-button{background:0 0!important;border:1px solid #000!important;color:#000!important}.dark-mode .dialog-footer .el-button:focus,.dark-mode .dialog-footer .el-button:hover{color:#fff!important;background:#303133!important;border:1px solid #303133!important}.dark-mode .dialog-footer .el-button--primary{background-color:#303133!important;border-color:#303133!important;color:#fff!important}.dark-mode .dialog-footer .el-button--primary:focus,.dark-mode .dialog-footer .el-button--primary:hover{background:#666!important;border-color:#666!important}.dark-mode .dialog-footer .el-button--primary.is-disabled,.dark-mode .dialog-footer .el-button--primary.is-disabled:active,.dark-mode .dialog-footer .el-button--primary.is-disabled:focus,.dark-mode .dialog-footer .el-button--primary.is-disabled:hover{background:#999!important;border-color:#999!important;color:#fff!important}.dark-mode .el-link.el-link--primary{color:#fff!important}.dark-mode .el-link.el-link--primary:hover{color:#fff!important}.dark-mode .el-link.el-link--default:after,.dark-mode .el-link.el-link--primary.is-underline:hover:after,.dark-mode .el-link.el-link--primary:after{border-color:#000!important}
2 |
--------------------------------------------------------------------------------
/src/assets/css/element-ui.scss:
--------------------------------------------------------------------------------
1 | // cover some element-ui styles
2 |
3 | .el-breadcrumb__inner,
4 | .el-breadcrumb__inner a {
5 | font-weight: 400 !important;
6 | }
7 |
8 | .el-upload {
9 | input[type="file"] {
10 | display: none !important;
11 | }
12 | }
13 |
14 | .el-upload__input {
15 | display: none;
16 | }
17 |
18 | .cell {
19 | .el-tag {
20 | margin-right: 0px;
21 | }
22 | }
23 |
24 | .small-padding {
25 | .cell {
26 | padding-left: 5px;
27 | padding-right: 5px;
28 | }
29 | }
30 |
31 | .fixed-width {
32 | .el-button--mini {
33 | padding: 7px 10px;
34 | width: 60px;
35 | }
36 | }
37 |
38 | .status-col {
39 | .cell {
40 | padding: 0 10px;
41 | text-align: center;
42 |
43 | .el-tag {
44 | margin-right: 0px;
45 | }
46 | }
47 | }
48 |
49 | // to fixed https://github.com/ElemeFE/element/issues/2461
50 | .el-dialog {
51 | transform: none;
52 | left: 0;
53 | position: relative;
54 | margin: 0 auto;
55 | }
56 |
57 | // refine element ui upload
58 | .upload-container {
59 | .el-upload {
60 | width: 100%;
61 |
62 | .el-upload-dragger {
63 | width: 100%;
64 | height: 200px;
65 | }
66 | }
67 | }
68 |
69 | // dropdown
70 | .el-dropdown-menu {
71 | a {
72 | display: block
73 | }
74 | }
75 |
76 | // fix date-picker ui bug in filter-item
77 | .el-range-editor.el-input__inner {
78 | display: inline-flex !important;
79 | }
--------------------------------------------------------------------------------
/src/assets/css/element-variables.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * I think element-ui's default theme color is too light for long-term use.
3 | * So I modified the default color and you can modify it to your liking.
4 | **/
5 |
6 | /* theme color */
7 | $--color-primary: #304156;
8 | $--color-success: #65C934;
9 | $--color-warning: #E6A23C;
10 | $--color-danger: #F56C6C;
11 | // $--color-info: #1E1E1E;
12 |
13 | $--button-font-weight: 400;
14 |
15 | // $--color-text-regular: #1f2d3d;
16 |
17 | $--border-color-light: #dfe4ed;
18 | $--border-color-lighter: #e6ebf5;
19 |
20 | $--table-border:1px solid#dfe6ec;
21 |
22 | /* icon font path, required */
23 | $--font-path: '~element-ui/lib/theme-chalk/fonts';
24 |
25 | @import "~element-ui/packages/theme-chalk/src/index";
26 |
27 | // the :export directive is the magic sauce for webpack
28 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
29 | :export {
30 | theme: $--color-primary;
31 | }
--------------------------------------------------------------------------------
/src/assets/css/light.min.css:
--------------------------------------------------------------------------------
1 | *{touch-action:manipulation}html{margin:0;padding:0}.el-input__count{color:#000!important;background:rgba(255,255,255,.7)!important}.el-select-dropdown{max-width:80%}.eldiy .el-form-item__content{line-height:44px!important}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:20px!important}.el-divider__text{padding:0!important}.el-link.is-underline:hover:after{border-bottom:0!important}.light-mode #rijian,.light-mode .channel,#canvas-show{display:none}.light-mode #canvas-show{display:inline!important}.light-mode .el-button--zhuti{font-size:14px!important;border:0!important;width:54px!important;padding:0 0!important}.light-mode .el-button--zhuti:active,.light-mode .el-button--zhuti:focus,.light-mode .el-button--zhuti:hover{color:#000!important;background-color:#fff!important}.light-mode #canvas{width:100%;height:2160px;overflow:hidden;position:absolute}.light-mode .canvas-wrap{width:100%;height:100%;position:fixed;left:0;top:0}a,b,div,i,img,input,label,li,p,select,span,textarea,ul{outline:0!important}textarea{-webkit-appearance:none;appearance:none}#app .el-row:not(.el-row--flex){margin:0 auto!important;padding:16px;max-width:1032px}.el-message-box__headerbtn .el-message-box__close,.light-mode .el-notification__closeBtn,.light-mode .el-notification__title,.light-mode .el-notification__content,.light-mode .el-message .el-icon-error,.light-mode .el-message .el-icon-success,.light-mode .el-notification .el-icon-warning,.light-mode .el-message .el-icon-warning,.light-mode .el-message--error .el-message__content,.light-mode .el-message--success .el-message__content,.light-mode .el-message--warning .el-message__content{color:#000!important}.light-mode .el-notification,.light-mode .el-message--error,.light-mode .el-message--success,.light-mode .el-message--warning{background-color:rgba(255,255,255,.7)!important;border-color:#fff!important}.light-mode .el-card{background:0 0!important}.light-mode .el-collapse-item__content{padding-bottom:0!important}.light-mode .el-collapse-item .el-button--limr{background:rgba(255,255,255,.5)!important;border-radius:4px!important;height:32px!important}.light-mode .el-button--limr:focus,.light-mode .el-button--limr:hover,.light-mode .el-collapse-item .el-button--limr:active{color:#606266!important;border-color:#dcdfe6!important}.light-mode .el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:transparent}.light-mode .el-collapse-item__wrap{background:0 0!important;border-bottom:none!important}.light-mode .el-collapse{border-top:none!important;border-bottom:none!important}.light-mode .el-collapse-item__header{background:0 0!important;border-bottom:none!important;height:auto!important}.light-mode .el-collapse-item__arrow{display:none!important}.light-mode .el-card__header{position:relative;color:#fff}.light-mode .el-card__body{background:rgba(255,255,255,.8);color:#000}.light-mode .el-form-item__label,.light-mode .el-input-group__append,.light-mode .el-input__inner,.light-mode .el-radio,.light-mode .el-select .el-input .el-select__caret,.light-mode .el-textarea__inner{color:#000!important}.light-mode .el-divider{background:rgba(0,0,0,.2)!important}.light-mode .el-input__inner,.light-mode .el-textarea__inner{background:rgba(255,255,255,.5)!important}.light-mode .el-input.is-active .el-input__inner,.light-mode .el-input__inner:focus,.light-mode .el-select .el-input.is-focus .el-input__inner,.light-mode .el-textarea__inner:focus{border-color:#999!important}.light-mode .el-checkbox.is-bordered,.light-mode .el-checkbox__inner{border:1px solid #000!important}.light-mode .el-checkbox{color:#000!important}.light-mode .el-checkbox.is-bordered.is-checked{border-color:#000!important}.light-mode .el-radio__input.is-checked+.el-radio__label{color:#000!important}.light-mode .el-radio__input.is-checked .el-radio__inner{border-color:#000!important;background:#000!important}.light-mode .el-checkbox__input.is-checked .el-checkbox__inner,.light-mode .el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#000!important}.light-mode .el-checkbox__input.is-checked+.el-checkbox__label{color:#000!important}.light-mode .el-row--flex .el-checkbox__input.is-checked+.el-checkbox__label{color:#fff!important}.light-mode .el-row--flex .el-checkbox__input.is-checked .el-checkbox__inner,.light-mode .el-row--flex .el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#000!important;border-color:#fff!important}.light-mode .el-row--flex .el-checkbox__inner:hover{border-color:#000!important}.light-mode .el-row--flex .el-checkbox__input.is-focus .el-checkbox__inner{border-color:#fff!important}.light-mode .el-checkbox.is-bordered.is-checked{background:rgba(0,0,0,.88)!important;color:#fff!important}.light-mode .el-row span .el-button{background:0 0!important;border:1px solid #000!important;color:#000!important}.light-mode .el-row span .el-button:focus,.light-mode .el-row span .el-button:hover{color:#fff!important;background:rgba(0,0,0,.88)!important}.light-mode .el-divider__text{border:1px solid rgba(0,0,0,.4);border-radius:3px}.light-mode .el-select-dropdown__item.selected{background:#333!important;color:#fff!important}.light-mode .el-input.is-disabled .el-input__inner{border:none}.light-mode .el-form-item:last-child .el-button--primary{background-color:#303133!important;border-color:#303133!important}.light-mode .el-form-item:last-child .el-button--primary:focus,.light-mode .el-form-item:last-child .el-button--primary:hover{background:#666!important;border-color:#666!important}.light-mode .el-form-item:last-child .el-button--primary.is-disabled{background:#999!important;border-color:#999!important}.light-mode .el-row--flex{align-items:center;flex-wrap:wrap;justify-content:space-between}.light-mode .el-row--flex .el-col-24{width:auto!important;margin:5px 0}.light-mode .el-select-group__title{color:#999!important;background:rgba(0,0,0,.1);font-weight:600}.light-mode .el-input-group__append button.el-button{border-color:transparent!important;background-color:#303133!important;color:#fff!important}.light-mode .el-input__inner::-webkit-input-placeholder,.light-mode .el-textarea__inner::-webkit-input-placeholder{color:#777!important}.light-mode .el-input__inner:-moz-placeholder,.light-mode .el-textarea__inner:-moz-placeholder{color:#777!important}.light-mode .el-input__inner::-moz-placeholder,.light-mode .el-textarea__inner::-moz-placeholder{color:#777!important}.light-mode .el-input__inner:-ms-input-placeholder,.light-mode .el-textarea__inner:-ms-input-placeholder{color:#777!important}.light-mode .el-popover.el-popper .el-row:focus,.light-mode .el-popover.el-popper .popper__arrow{outline:0}.light-mode .el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{box-shadow:none!important}.light-mode .el-radio__inner:hover{border-color:#000!important}.light-mode .el-radio__inner{border:1px solid #999!important}.light-mode .dialog-footer .el-button{background:0 0!important;border:1px solid #000!important;color:#000!important}.light-mode .dialog-footer .el-button:focus,.light-mode .dialog-footer .el-button:hover{color:#fff!important;background:#303133!important;border:1px solid #303133!important}.light-mode .dialog-footer .el-button--primary{background-color:#303133!important;border-color:#303133!important;color:#fff!important}.light-mode .dialog-footer .el-button--primary:focus,.light-mode .dialog-footer .el-button--primary:hover{background:#666!important;border-color:#666!important}.light-mode .dialog-footer .el-button--primary.is-disabled,.light-mode .dialog-footer .el-button--primary.is-disabled:active,.light-mode .dialog-footer .el-button--primary.is-disabled:focus,.light-mode .dialog-footer .el-button--primary.is-disabled:hover{background:#999!important;border-color:#999!important;color:#fff!important}.light-mode .el-link.el-link--primary{color:#333!important}.light-mode .el-link.el-link--primary:hover{color:#000!important}.light-mode .el-link.el-link--default:after,.light-mode .el-link.el-link--primary.is-underline:hover:after,.light-mode .el-link.el-link--primary:after{border-color:#000!important}@media(max-width:460px){.msgbox {width:80%!important}}
2 |
--------------------------------------------------------------------------------
/src/components/SvgIcon/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
34 |
35 |
44 |
--------------------------------------------------------------------------------
/src/icons/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import SvgIcon from '@/components/SvgIcon'// svg component
3 |
4 | // register globally
5 | Vue.component('svg-icon', SvgIcon)
6 |
7 | const req = require.context('./svg', false, /\.svg$/)
8 | const requireAll = requireContext => requireContext.keys().map(requireContext)
9 | requireAll(req)
10 |
--------------------------------------------------------------------------------
/src/icons/svg/bilibili.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/telegram.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/youtube.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | require(`@/plugins/element-ui`)
5 | require(`@/plugins/clipboard`)
6 | require(`@/plugins/base64`)
7 | require(`@/plugins/axios`)
8 | require(`@/plugins/device`)
9 | require(`@/plugins/particles`)
10 |
11 |
12 | import 'element-ui/lib/theme-chalk/index.css'
13 | import './assets/css/light.min.css'
14 | import './assets/css/dark.min.css'
15 | import '@/icons' // icon
16 |
17 | Vue.config.productionTip = false
18 |
19 | new Vue({
20 | router,
21 | render: h => h(App)
22 | }).$mount('#app')
23 |
--------------------------------------------------------------------------------
/src/plugins/axios.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import axios from "axios"
3 |
4 | axios.defaults.timeout = 5000 //请求超时的时间设定
5 |
6 | Vue.prototype.$axios = axios
--------------------------------------------------------------------------------
/src/plugins/base64.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import btoa from 'btoa'
3 | import atob from 'atob'
4 |
5 | Vue.prototype.$btoa = (string) => btoa(string)
6 | Vue.prototype.$atob = (string) => atob(string)
7 |
--------------------------------------------------------------------------------
/src/plugins/clipboard.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import clipboard from 'vue-clipboard2'
3 |
4 | Vue.use(clipboard)
5 |
--------------------------------------------------------------------------------
/src/plugins/device.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | Vue.prototype.$getOS = () => {
4 | let ua = navigator.userAgent,
5 | isWindowsPhone = /(?:Windows Phone)/.test(ua),
6 | isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone,
7 | isAndroid = /(?:Android)/.test(ua),
8 | isFireFox = /(?:Firefox)/.test(ua),
9 | // isChrome = /(?:Chrome|CriOS)/.test(ua),
10 | isTablet = /(?:iPad|PlayBook)/.test(ua) || (isAndroid && !/(?:Mobile)/.test(ua)) || (isFireFox && /(?:Tablet)/.test(ua)),
11 | isIPhone = /(?:iPhone)/.test(ua) && !isTablet,
12 | isPc = !isIPhone && !isAndroid && !isSymbian && !isWindowsPhone;
13 |
14 | return {
15 | isTablet: isTablet,
16 | isIPhone: isIPhone,
17 | isAndroid: isAndroid,
18 | isPc: isPc
19 | };
20 | }
21 |
--------------------------------------------------------------------------------
/src/plugins/element-ui.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Element from 'element-ui'
3 | import locale from 'element-ui/lib/locale/lang/zh-CN'
4 | // import '@/assets/css/element-ui.scss'
5 | // import '@/assets/css/element-element-variables.scss'
6 |
7 | Vue.use(Element, {
8 | locale,
9 | size: 'small'
10 | })
11 |
12 | Vue.use(Element.Loading.directive);
13 |
14 | Vue.prototype.$loading = Element.Loading.service;
15 | Vue.prototype.$msgbox = Element.MessageBox;
16 | Vue.prototype.$alert = Element.MessageBox.alert;
17 | Vue.prototype.$confirm = Element.MessageBox.confirm;
18 | Vue.prototype.$prompt = Element.MessageBox.prompt;
19 | Vue.prototype.$notify = Element.Notification;
20 | Vue.prototype.$message = Element.Message;
21 |
--------------------------------------------------------------------------------
/src/plugins/particles.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueParticles from 'vue-particles'
3 |
4 | Vue.use(VueParticles)
5 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import VueRouter from "vue-router";
3 |
4 | Vue.use(VueRouter);
5 |
6 | const routes = [
7 | {
8 | path: "/",
9 | name: "SubConverter",
10 | component: () => import("../views/Subconverter.vue")
11 | }
12 | ];
13 |
14 | const router = new VueRouter({
15 | mode: "history",
16 | base: process.env.BASE_URL,
17 | routes
18 | });
19 |
20 | export default router;
21 |
--------------------------------------------------------------------------------
/src/views/Subconverter.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
12 |
13 |
15 |
订 阅 转 换
16 |
17 |
18 |
19 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
41 |
42 |
43 |
44 |
45 |
52 |
53 |
54 |
55 |
56 |
63 |
68 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | 点击显示/隐藏
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 | 更多选项
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
190 |
191 |
192 |
193 |
194 |
195 |
196 | 复制
203 |
204 |
205 |
206 |
207 |
209 | 复制
216 |
217 |
218 |
219 |
220 | 生成订阅链接
226 |
227 | 生成短链接
234 |
235 |
236 |
237 | 自定义配置
244 |
245 | 从URL解析
252 |
253 |
254 |
255 | 视频教程
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
275 |
276 | 基础视频教程
282 |
283 |
284 |
285 | 进阶视频教程
291 |
292 |
293 |
294 | 代理工具集合
300 |
301 |
302 |
303 |
310 |
311 |
312 |
313 | 参考案例
314 |
315 |
316 |
317 |
324 |
325 |
326 |
327 | 取 消
328 | 确 定
333 |
334 |
335 |
336 |
337 |
338 | 参考案例
339 |
340 |
341 |
342 |
350 |
351 |
352 |
353 | 取 消
354 | 确 定
359 |
360 |
361 |
362 |
363 |
364 | 参考案例
365 |
366 |
367 |
368 |
376 |
377 |
378 |
379 | 取 消
380 | 确 定
385 |
386 |
387 |
388 |
389 |
390 |
397 |
398 | 可以从生成的长/短链接中解析信息,填入页面中去
399 |
400 |
401 |
402 |
409 |
410 |
411 |
420 |
421 |
422 |
423 |
1416 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | function resolve(dir) {
4 | return path.join(__dirname, dir)
5 | }
6 |
7 | module.exports = {
8 | css: {
9 | loaderOptions: {
10 | less: {
11 | javascriptEnabled: true
12 | }
13 | }
14 | },
15 |
16 | chainWebpack: config => {
17 | // set svg-sprite-loader
18 | config.module
19 | .rule('svg')
20 | .exclude.add(resolve('src/icons'))
21 | .end()
22 | config.module
23 | .rule('icons')
24 | .test(/\.svg$/)
25 | .include.add(resolve('src/icons'))
26 | .end()
27 | .use('svg-sprite-loader')
28 | .loader('svg-sprite-loader')
29 | .options({
30 | symbolId: 'icon-[name]'
31 | })
32 | .end()
33 | }
34 | };
--------------------------------------------------------------------------------