{"_id":"@chenyican/vue-fabric-editor","_rev":"5-19a97a1687d2a5145978519c185bf105","name":"@chenyican/vue-fabric-editor","dist-tags":{"latest":"1.0.4"},"versions":{"1.0.0":{"name":"@chenyican/vue-fabric-editor","version":"1.0.0","license":"MIT","_id":"@chenyican/vue-fabric-editor@1.0.0","maintainers":[{"name":"chenyican","email":"472427714@qq.com"}],"homepage":"https://github.com/zhiqinyigu/vue2-fabric-editor#readme","bugs":{"url":"https://github.com/zhiqinyigu/vue2-fabric-editor/issues"},"dist":{"shasum":"1a07f97210de1aa49900993a2bf16c9e104b738e","tarball":"https://registry.npmjs.org/@chenyican/vue-fabric-editor/-/vue-fabric-editor-1.0.0.tgz","fileCount":29,"integrity":"sha512-6r+F3wbRiQR3vB9xJ05GEZrIwUXeQNC/Vkz69bs1bMIqHJ8qSanzE6V+W6cA+HkGQVRYVJ413ztw8gQxNZxd4A==","signatures":[{"sig":"MEYCIQD5YtTXQEJFzt0gITpCm7AU5n7LRndolOSWdUQnYX+srwIhAORIkrKfKYwwra6FjUCk4OHch3+uhUqCSdz10QGGFdV3","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4897104},"main":"dist/vue-fabric-editor/vue-fabric-editor.common.js","style":"dist/vue-fabric-editor/vue-fabric-editor.css","types":"types/index.d.ts","unpkg":"dist/vue-fabric-editor/vue-fabric-editor.umd.min.js","module":"dist/vue-fabric-editor/vue-fabric-editor.common.js","exports":{".":{"types":"./types/index.d.ts","import":"./dist/vue-fabric-editor/vue-fabric-editor.common.js","default":"./dist/vue-fabric-editor/vue-fabric-editor.common.js","require":"./dist/vue-fabric-editor/vue-fabric-editor.common.js"},"./style":"./dist/vue-fabric-editor/vue-fabric-editor.css","./package.json":"./package.json","./fabric-renderer":{"types":"./types/fabric-renderer.d.ts","import":"./dist/fabric-renderer/fabric-renderer.common.js","default":"./dist/fabric-renderer/fabric-renderer.common.js","require":"./dist/fabric-renderer/fabric-renderer.common.js"},"./fabric-renderer/style":"./dist/fabric-renderer/fabric-renderer.css"},"gitHead":"666408414c899a6543db17da068d89b22c2fe3cf","private":false,"scripts":{"lint":"vue-cli-service lint","test":"jest","build":"vue-cli-service build","serve":"vue-cli-service serve","build:lib":"vue-cli-service build --target lib --name vue-fabric-editor --dest dist/vue-fabric-editor src/lib/index.js","typecheck":"tsc -p tsconfig.types.json","build:prod":"vue-cli-service build --mode production","test:layer":"node test-layer.js","build:staging":"vue-cli-service build --mode staging","prepublishOnly":"npm run build:lib && npm run build:lib:renderer","build:lib:renderer":"vue-cli-service build --target lib --name fabric-renderer --dest dist/fabric-renderer src/lib/renderer.js"},"_npmUser":{"name":"chenyican","email":"472427714@qq.com"},"jsdelivr":"dist/vue-fabric-editor/vue-fabric-editor.umd.min.js","repository":{"url":"git+https://github.com/zhiqinyigu/vue2-fabric-editor.git","type":"git"},"_npmVersion":"8.3.1","description":"基于 Vue2.6 + Fabric.js 的图片设计编辑器（移植自 ikuaitu/vue-fabric-editor）","directories":{},"sideEffects":["**/*.css","**/*.less","**/*.vue"],"_nodeVersion":"16.14.0","dependencies":{"axios":"^1.3.4","colord":"^2.10.0","vue-router":"^3.5.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"typesVersions":{"*":{"fabric-renderer":["types/fabric-renderer.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.0.5","less":"^4.1.3","jsdom":"^19.0.0","eslint":"^7.32.0","prettier":"2.8.4","babel-jest":"^27.0.6","raw-loader":"^4.0.2","typescript":"^5.1.6","@babel/core":"^7.12.16","less-loader":"^7.3.0","babel-eslint":"^10.1.0","vue-svg-loader":"^0.16.0","@vue/cli-service":"~4.4.4","eslint-plugin-vue":"^8.0.3","@babel/eslint-parser":"^7.12.16","@vue/cli-plugin-babel":"~4.4.4","vue-template-compiler":"2.6.10","@vue/cli-plugin-eslint":"~4.4.4","eslint-config-prettier":"^8.6.0","eslint-plugin-prettier":"^4.2.1","jest-environment-jsdom":"^27.0.6"},"peerDependencies":{"qs":"^6.12.1","vue":"^2.6.10","uuid":"^8.3.2","dayjs":"^1.11.11","events":"^3.3.0","fabric":"~5.5.0","core-js":"^3.8.3","tapable":"^2.2.1","vue-i18n":"^8.28.2","jsbarcode":"^3.11.6","lodash-es":"^4.17.21","hotkeys-js":"^3.8.8","view-design":"^4.7.0","vue-cropper":"^0.5.10","vue-masonry":"^0.11.3","@webtoon/psd":"^0.4.0","vue-lazyload":"^1.3.4","vue-clipboard2":"^0.3.3","qr-code-styling":"^1.9.2","fontfaceobserver":"^2.1.0","number-precision":"^1.6.0","svg-path-editor-lib":"^1.0.4","@vue/composition-api":"^1.7.2"},"_npmOperationalInternal":{"tmp":"tmp/vue-fabric-editor_1.0.0_1789112869363_0.28685234708342766","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@chenyican/vue-fabric-editor","version":"1.0.1","license":"MIT","_id":"@chenyican/vue-fabric-editor@1.0.1","maintainers":[{"name":"chenyican","email":"472427714@qq.com"}],"homepage":"https://github.com/zhiqinyigu/vue2-fabric-editor#readme","bugs":{"url":"https://github.com/zhiqinyigu/vue2-fabric-editor/issues"},"dist":{"shasum":"44dbe213ca4107a6b1c51b164f786f61485d4226","tarball":"https://registry.npmjs.org/@chenyican/vue-fabric-editor/-/vue-fabric-editor-1.0.1.tgz","fileCount":29,"integrity":"sha512-sjko5oUq7CF9ZkJsxyZZD32QnOuvTvHm0n1fptv9uyvvqLAnNS7buR5SCrXOYt9i2LSWSlYOSYc5sh+rjtgMOw==","signatures":[{"sig":"MEUCIAlMbTL4jRzlYcqeA6meSsWGB3qanGsd9k9CxRS5YMz4AiEAo/0pDmCKCWKuKY7I6VDbJQJGcRuyfPg5eiS8Sufr3P4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCKk8C0ph8GuFReAkybOMGEaWMNnDJBXigUFxoz7WuW5AIhAMlmUAaLeMgnF11LhTPk3Gq9NyU1vsqBo2++9HVXOl4J","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4960358},"main":"dist/vue-fabric-editor/vue-fabric-editor.common.js","style":"dist/vue-fabric-editor/vue-fabric-editor.css","types":"types/index.d.ts","unpkg":"dist/vue-fabric-editor/vue-fabric-editor.umd.min.js","module":"dist/vue-fabric-editor/vue-fabric-editor.common.js","exports":{".":{"types":"./types/index.d.ts","import":"./dist/vue-fabric-editor/vue-fabric-editor.common.js","default":"./dist/vue-fabric-editor/vue-fabric-editor.common.js","require":"./dist/vue-fabric-editor/vue-fabric-editor.common.js"},"./style":"./dist/vue-fabric-editor/vue-fabric-editor.css","./package.json":"./package.json","./fabric-renderer":{"types":"./types/fabric-renderer.d.ts","import":"./dist/fabric-renderer/fabric-renderer.common.js","default":"./dist/fabric-renderer/fabric-renderer.common.js","require":"./dist/fabric-renderer/fabric-renderer.common.js"},"./fabric-renderer/style":"./dist/fabric-renderer/fabric-renderer.css"},"gitHead":"66d7caa06360c4c6ed387b4d167b746f038b01c3","private":false,"scripts":{"lint":"vue-cli-service lint","test":"jest","build":"vue-cli-service build","serve":"vue-cli-service serve","build:lib":"vue-cli-service build --target lib --name vue-fabric-editor --dest dist/vue-fabric-editor src/lib/index.js","typecheck":"tsc -p tsconfig.types.json","build:prod":"vue-cli-service build --mode production","test:layer":"node test-layer.js","build:staging":"vue-cli-service build --mode staging","prepublishOnly":"npm run build:lib && npm run build:lib:renderer","build:lib:renderer":"vue-cli-service build --target lib --name fabric-renderer --dest dist/fabric-renderer src/lib/renderer.js"},"_npmUser":{"name":"chenyican","email":"472427714@qq.com"},"jsdelivr":"dist/vue-fabric-editor/vue-fabric-editor.umd.min.js","repository":{"url":"git+https://github.com/zhiqinyigu/vue2-fabric-editor.git","type":"git"},"_npmVersion":"8.3.1","description":"基于 Vue2.6 + Fabric.js 的图片设计编辑器（移植自 ikuaitu/vue-fabric-editor）","directories":{},"sideEffects":["**/*.css","**/*.less","**/*.vue"],"_nodeVersion":"16.14.0","dependencies":{"axios":"^1.3.4","colord":"^2.10.0","vue-router":"^3.5.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"typesVersions":{"*":{"fabric-renderer":["types/fabric-renderer.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.0.5","less":"^4.1.3","jsdom":"^19.0.0","eslint":"^7.32.0","prettier":"2.8.4","babel-jest":"^27.0.6","raw-loader":"^4.0.2","typescript":"^5.1.6","@babel/core":"^7.12.16","less-loader":"^7.3.0","babel-eslint":"^10.1.0","vue-svg-loader":"^0.16.0","@vue/cli-service":"~4.4.4","eslint-plugin-vue":"^8.0.3","@babel/eslint-parser":"^7.12.16","@vue/cli-plugin-babel":"~4.4.4","vue-template-compiler":"2.6.10","@vue/cli-plugin-eslint":"~4.4.4","eslint-config-prettier":"^8.6.0","eslint-plugin-prettier":"^4.2.1","jest-environment-jsdom":"^27.0.6"},"peerDependencies":{"qs":"^6.12.1","vue":"^2.6.10","uuid":"^8.3.2","dayjs":"^1.11.11","events":"^3.3.0","fabric":"~5.5.0","tapable":"^2.2.1","vue-i18n":"^8.28.2","jsbarcode":"^3.11.6","lodash-es":"^4.17.21","hotkeys-js":"^3.8.8","view-design":"^4.7.0","vue-cropper":"^0.5.10","vue-masonry":"^0.11.3","@webtoon/psd":"^0.4.0","vue-lazyload":"^1.3.4","vue-clipboard2":"^0.3.3","qr-code-styling":"^1.9.2","fontfaceobserver":"^2.1.0","number-precision":"^1.6.0","svg-path-editor-lib":"^1.0.4","@vue/composition-api":"^1.7.2"},"_npmOperationalInternal":{"tmp":"tmp/vue-fabric-editor_1.0.1_1789129292204_0.10754114644086554","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@chenyican/vue-fabric-editor","version":"1.0.2","license":"MIT","_id":"@chenyican/vue-fabric-editor@1.0.2","maintainers":[{"name":"chenyican","email":"472427714@qq.com"}],"homepage":"https://github.com/zhiqinyigu/vue2-fabric-editor#readme","bugs":{"url":"https://github.com/zhiqinyigu/vue2-fabric-editor/issues"},"dist":{"shasum":"3058f6f13133038c7be6e0601a7b6197b42b16bb","tarball":"https://registry.npmjs.org/@chenyican/vue-fabric-editor/-/vue-fabric-editor-1.0.2.tgz","fileCount":29,"integrity":"sha512-o278J5zLoQgfkQnvaNy3bVfHcFwB7JrsTYCymVHIlpk/KROe+33Q3ohlp7mGI3g7h/i/OsKCb05bhSwINi+daQ==","signatures":[{"sig":"MEUCIBRGz3pytL7t4C4/C7cpNWCXuVumPcaBaNg+2Q9RWp7WAiEA6RPvOwjh5GP5xWFOZn90KXteoL2YjS2NUqLGDphSUy0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIBOz+Y+apSeJmPVxGUD/xshzr8aNNP08B0wwOCUqMbU/AiBxBMjUQv6PvVvUNVTjVzOwh7PltbuM+u8uYy+4AH1DTQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4978760},"main":"dist/vue-fabric-editor/vue-fabric-editor.common.js","style":"dist/vue-fabric-editor/vue-fabric-editor.css","types":"types/index.d.ts","unpkg":"dist/vue-fabric-editor/vue-fabric-editor.umd.min.js","module":"dist/vue-fabric-editor/vue-fabric-editor.common.js","exports":{".":{"types":"./types/index.d.ts","import":"./dist/vue-fabric-editor/vue-fabric-editor.common.js","default":"./dist/vue-fabric-editor/vue-fabric-editor.common.js","require":"./dist/vue-fabric-editor/vue-fabric-editor.common.js"},"./style":"./dist/vue-fabric-editor/vue-fabric-editor.css","./package.json":"./package.json","./fabric-renderer":{"types":"./types/fabric-renderer.d.ts","import":"./dist/fabric-renderer/fabric-renderer.common.js","default":"./dist/fabric-renderer/fabric-renderer.common.js","require":"./dist/fabric-renderer/fabric-renderer.common.js"},"./fabric-renderer/style":"./dist/fabric-renderer/fabric-renderer.css"},"gitHead":"66d7caa06360c4c6ed387b4d167b746f038b01c3","private":false,"scripts":{"lint":"vue-cli-service lint","test":"jest","build":"vue-cli-service build","serve":"vue-cli-service serve","build:lib":"vue-cli-service build --target lib --name vue-fabric-editor --dest dist/vue-fabric-editor src/lib/index.js","typecheck":"tsc -p tsconfig.types.json","build:prod":"vue-cli-service build --mode production","test:layer":"node test-layer.js","build:staging":"vue-cli-service build --mode staging","prepublishOnly":"npm run build:lib && npm run build:lib:renderer","build:lib:renderer":"vue-cli-service build --target lib --name fabric-renderer --dest dist/fabric-renderer src/lib/renderer.js"},"_npmUser":{"name":"chenyican","email":"472427714@qq.com"},"jsdelivr":"dist/vue-fabric-editor/vue-fabric-editor.umd.min.js","repository":{"url":"git+https://github.com/zhiqinyigu/vue2-fabric-editor.git","type":"git"},"_npmVersion":"8.3.1","description":"基于 Vue2.6 + Fabric.js 的图片设计编辑器（移植自 ikuaitu/vue-fabric-editor）","directories":{},"sideEffects":["**/*.css","**/*.less","**/*.vue"],"_nodeVersion":"16.14.0","dependencies":{"axios":"^1.3.4","colord":"^2.10.0","vue-router":"^3.5.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"typesVersions":{"*":{"fabric-renderer":["types/fabric-renderer.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.0.5","less":"^4.1.3","jsdom":"^19.0.0","eslint":"^7.32.0","prettier":"2.8.4","babel-jest":"^27.0.6","raw-loader":"^4.0.2","typescript":"^5.1.6","@babel/core":"^7.12.16","less-loader":"^7.3.0","babel-eslint":"^10.1.0","vue-svg-loader":"^0.16.0","@vue/cli-service":"~4.4.4","eslint-plugin-vue":"^8.0.3","@babel/eslint-parser":"^7.12.16","@vue/cli-plugin-babel":"~4.4.4","vue-template-compiler":"2.6.10","@vue/cli-plugin-eslint":"~4.4.4","eslint-config-prettier":"^8.6.0","eslint-plugin-prettier":"^4.2.1","jest-environment-jsdom":"^27.0.6"},"peerDependencies":{"qs":"^6.12.1","vue":"^2.6.10","uuid":"^8.3.2","dayjs":"^1.11.11","events":"^3.3.0","fabric":"~5.5.0","tapable":"^2.2.1","vue-i18n":"^8.28.2","jsbarcode":"^3.11.6","lodash-es":"^4.17.21","hotkeys-js":"^3.8.8","view-design":"^4.7.0","vue-cropper":"^0.5.10","vue-masonry":"^0.11.3","@webtoon/psd":"^0.4.0","vue-lazyload":"^1.3.4","vue-clipboard2":"^0.3.3","qr-code-styling":"^1.9.2","fontfaceobserver":"^2.1.0","number-precision":"^1.6.0","svg-path-editor-lib":"^1.0.4","@vue/composition-api":"^1.7.2"},"_npmOperationalInternal":{"tmp":"tmp/vue-fabric-editor_1.0.2_1789180072975_0.8368942389359018","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@chenyican/vue-fabric-editor","version":"1.0.3","license":"MIT","_id":"@chenyican/vue-fabric-editor@1.0.3","maintainers":[{"name":"chenyican","email":"472427714@qq.com"}],"homepage":"https://github.com/zhiqinyigu/vue2-fabric-editor#readme","bugs":{"url":"https://github.com/zhiqinyigu/vue2-fabric-editor/issues"},"dist":{"shasum":"14853fdfb34e3508dea9d0b34e9d7658d85484a5","tarball":"https://registry.npmjs.org/@chenyican/vue-fabric-editor/-/vue-fabric-editor-1.0.3.tgz","fileCount":32,"integrity":"sha512-AadoGAUj9i99A1oRKzlEF1bwH+MkHqBqLaBZaDexcrdxxN5eIaeKEuCgha7S/e9JyrDrJVd20DEqDSpcEZM0DQ==","signatures":[{"sig":"MEQCIHU9PRJ4gdBTfHSHTqSZioHjCL7ueqxYoE/cvnVGKtN5AiBaCzjxVkEavK7EHoqr4ssAb+hhOWpLrnTr2JGqfMVEow==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQC0n6t5smrG3Lm+3YPWGsXiUq/56yIGnkuhyDjVFAzC5QIgCJqLgHLAoKwQ5swiBEUL+3GLOlIGpB7y3O0f1paS+xo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5179232},"main":"dist/vue-fabric-editor/vue-fabric-editor.common.js","style":"dist/vue-fabric-editor/vue-fabric-editor.css","types":"types/index.d.ts","unpkg":"dist/vue-fabric-editor/vue-fabric-editor.umd.min.js","module":"dist/vue-fabric-editor/vue-fabric-editor.common.js","exports":{".":{"types":"./types/index.d.ts","import":"./dist/vue-fabric-editor/vue-fabric-editor.common.js","default":"./dist/vue-fabric-editor/vue-fabric-editor.common.js","require":"./dist/vue-fabric-editor/vue-fabric-editor.common.js"},"./style":"./dist/vue-fabric-editor/vue-fabric-editor.css","./loader/*":"./loader/*","./package.json":"./package.json","./assets-loader":"./loader/assets-loader.js","./webpack-plugin":"./loader/webpack-plugin.js","./fabric-renderer":{"types":"./types/fabric-renderer.d.ts","import":"./dist/fabric-renderer/fabric-renderer.common.js","default":"./dist/fabric-renderer/fabric-renderer.common.js","require":"./dist/fabric-renderer/fabric-renderer.common.js"},"./fabric-renderer/style":"./dist/fabric-renderer/fabric-renderer.css"},"gitHead":"bad6b9274f02a038318bff1029c4676fffd87e8a","private":false,"scripts":{"lint":"vue-cli-service lint","test":"jest","build":"vue-cli-service build","serve":"vue-cli-service serve","build:lib":"vue-cli-service build --target lib --name vue-fabric-editor --dest dist/vue-fabric-editor src/lib/index.js","typecheck":"tsc -p tsconfig.types.json","build:prod":"vue-cli-service build --mode production","test:layer":"node test-layer.js","build:staging":"vue-cli-service build --mode staging","prepublishOnly":"npm run build:lib && npm run build:lib:renderer","build:lib:renderer":"vue-cli-service build --target lib --name fabric-renderer --dest dist/fabric-renderer src/lib/renderer.js"},"_npmUser":{"name":"chenyican","email":"472427714@qq.com"},"jsdelivr":"dist/vue-fabric-editor/vue-fabric-editor.umd.min.js","repository":{"url":"git+https://github.com/zhiqinyigu/vue2-fabric-editor.git","type":"git"},"_npmVersion":"8.3.1","description":"基于 Vue2.6 + Fabric.js 的图片设计编辑器（移植自 ikuaitu/vue-fabric-editor）","directories":{},"sideEffects":["**/*.css","**/*.less","**/*.vue","**/renderPatches.js","**/objects/*.js"],"_nodeVersion":"16.14.0","dependencies":{"axios":"^1.3.4","colord":"^2.10.0","vue-router":"^3.5.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"typesVersions":{"*":{"fabric-renderer":["types/fabric-renderer.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"qs":"^6.12.1","jest":"^27.0.5","less":"^4.1.3","dayjs":"^1.11.11","jsdom":"^19.0.0","eslint":"^7.32.0","prettier":"2.8.4","babel-jest":"^27.0.6","raw-loader":"^4.0.2","typescript":"^5.1.6","@babel/core":"^7.12.16","less-loader":"^7.3.0","vue-masonry":"^0.11.3","babel-eslint":"^10.1.0","vue-lazyload":"^1.3.4","vue-svg-loader":"^0.16.0","@vue/cli-service":"~4.4.4","eslint-plugin-vue":"^8.0.3","@babel/eslint-parser":"^7.12.16","@vue/cli-plugin-babel":"~4.4.4","vue-template-compiler":"2.6.10","@vue/cli-plugin-eslint":"~4.4.4","eslint-config-prettier":"^8.6.0","eslint-plugin-prettier":"^4.2.1","jest-environment-jsdom":"^27.0.6"},"peerDependencies":{"vue":"^2.6.10","uuid":"^8.3.2","events":"^3.3.0","fabric":"~5.5.0","tapable":"^2.2.1","vue-i18n":"^8.28.2","jsbarcode":"^3.11.6","lodash-es":"^4.17.21","hotkeys-js":"^3.8.8","view-design":"^4.7.0","vue-cropper":"^0.5.10","@webtoon/psd":"^0.4.0","qr-code-styling":"^1.9.2","fontfaceobserver":"^2.1.0","number-precision":"^1.6.0","svg-path-editor-lib":"^1.0.4","@vue/composition-api":"^1.7.2"},"_npmOperationalInternal":{"tmp":"tmp/vue-fabric-editor_1.0.3_1789215669205_0.223425291471389","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"_id":"@chenyican/vue-fabric-editor@1.0.4","bugs":{"url":"https://github.com/zhiqinyigu/vue-fabric-editor/issues"},"dist":{"shasum":"8b27d780418dfe61d0a36f549bb1eb34dea29752","tarball":"https://registry.npmjs.org/@chenyican/vue-fabric-editor/-/vue-fabric-editor-1.0.4.tgz","fileCount":24,"integrity":"sha512-8t5SJmQ2IcK0pnmCJ3Cw41cFUcQSfyQlqHyBG/iEV9zkblNnvO46lJXi1WZLGUbmzXva7zSiwMMb2fPBPYWHQQ==","signatures":[{"sig":"MEUCIQD1FbZ+D8XkWYqT0OTFV76sDsvfRBhWmUFRyCkhQobkrAIgHAe6Nlkw5Vc/Cdbc0QyVAe6pYjxHfTg02R9K2jZ3mN8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDTOagl0w6den1QWcN1j9iWhNTqRfynB+d0mHumJSIcsgIgNRcKC3INyl0Fv6H2ZtS1WAlypWk9NS/B582JqDisNY0="}],"unpackedSize":5341805},"main":"dist/vue-fabric-editor/vue-fabric-editor.common.js","name":"@chenyican/vue-fabric-editor","style":"dist/vue-fabric-editor/vue-fabric-editor.css","types":"types/index.d.ts","unpkg":"dist/vue-fabric-editor/vue-fabric-editor.umd.min.js","module":"dist/vue-fabric-editor/vue-fabric-editor.common.js","exports":{".":{"types":"./types/index.d.ts","import":"./dist/vue-fabric-editor/vue-fabric-editor.common.js","default":"./dist/vue-fabric-editor/vue-fabric-editor.common.js","require":"./dist/vue-fabric-editor/vue-fabric-editor.common.js"},"./style":"./dist/vue-fabric-editor/vue-fabric-editor.css","./package.json":"./package.json","./fabric-renderer":{"types":"./types/fabric-renderer.d.ts","import":"./dist/fabric-renderer/fabric-renderer.common.js","default":"./dist/fabric-renderer/fabric-renderer.common.js","require":"./dist/fabric-renderer/fabric-renderer.common.js"},"./fabric-renderer/style":"./dist/fabric-renderer/fabric-renderer.css"},"gitHead":"c06e0cd9dff8eb1dc5b6795741f4460b1480d7de","license":"MIT","private":false,"scripts":{"lint":"vue-cli-service lint","test":"jest","build":"vue-cli-service build","serve":"vue-cli-service serve","build:lib":"vue-cli-service build --target lib --name vue-fabric-editor --dest dist/vue-fabric-editor src/lib/index.js","typecheck":"tsc -p tsconfig.types.json","build:prod":"vue-cli-service build --mode production","test:layer":"node test-layer.js","build:staging":"vue-cli-service build --mode staging","prepublishOnly":"npm run build:lib && npm run build:lib:renderer","build:lib:renderer":"vue-cli-service build --target lib --name fabric-renderer --dest dist/fabric-renderer src/lib/renderer.js"},"version":"1.0.4","_npmUser":{"name":"chenyican","email":"472427714@qq.com"},"homepage":"https://github.com/zhiqinyigu/vue-fabric-editor#readme","jsdelivr":"dist/vue-fabric-editor/vue-fabric-editor.umd.min.js","repository":{"url":"git+https://github.com/zhiqinyigu/vue-fabric-editor.git","type":"git"},"_npmVersion":"8.3.1","description":"基于 Vue2.6 + Fabric.js 的图片设计编辑器（移植自 ikuaitu/vue-fabric-editor）","directories":{},"maintainers":[{"name":"chenyican","email":"472427714@qq.com"}],"sideEffects":["**/*.css","**/*.less","**/*.vue","**/renderPatches.js","**/objects/*.js"],"_nodeVersion":"16.14.0","dependencies":{"axios":"^1.3.4","colord":"^2.10.0","vue-router":"^3.5.1","svg-path-editor-lib":"^1.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"typesVersions":{"*":{"fabric-renderer":["types/fabric-renderer.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"qs":"^6.12.1","jest":"^27.0.5","less":"^4.1.3","dayjs":"^1.11.11","jsdom":"^19.0.0","eslint":"^7.32.0","prettier":"2.8.4","babel-jest":"^27.0.6","raw-loader":"^4.0.2","typescript":"^5.1.6","@babel/core":"^7.12.16","less-loader":"^7.3.0","vue-masonry":"^0.11.3","babel-eslint":"^10.1.0","vue-lazyload":"^1.3.4","vue-svg-loader":"^0.16.0","@vue/cli-service":"~4.4.4","eslint-plugin-vue":"^8.0.3","@babel/eslint-parser":"^7.12.16","@vue/cli-plugin-babel":"~4.4.4","vue-template-compiler":"2.6.10","@vue/cli-plugin-eslint":"~4.4.4","eslint-config-prettier":"^8.6.0","eslint-plugin-prettier":"^4.2.1","jest-environment-jsdom":"^27.0.6"},"peerDependencies":{"vue":"^2.6.10","uuid":"^8.3.2","events":"^3.3.0","fabric":"~5.5.0","tapable":"^2.2.1","vue-i18n":"^8.28.2","jsbarcode":"^3.11.6","lodash-es":"^4.17.21","hotkeys-js":"^3.8.8","view-design":"^4.7.0","vue-cropper":"^0.5.10","@webtoon/psd":"^0.4.0","qr-code-styling":"^1.9.2","fontfaceobserver":"^2.1.0","number-precision":"^1.6.0","@vue/composition-api":"^1.7.2"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/vue-fabric-editor_1.0.4_1789381039503_0.8087575026514311"}}},"time":{"created":"2026-09-11T07:47:49.074Z","modified":"2026-09-14T10:17:19.775Z","1.0.0":"2026-09-11T07:47:49.517Z","1.0.1":"2026-09-11T12:21:32.385Z","1.0.2":"2026-09-12T02:27:53.124Z","1.0.3":"2026-09-12T12:21:09.343Z","1.0.4":"2026-09-14T10:17:19.641Z"},"bugs":{"url":"https://github.com/zhiqinyigu/vue-fabric-editor/issues"},"license":"MIT","homepage":"https://github.com/zhiqinyigu/vue-fabric-editor#readme","repository":{"url":"git+https://github.com/zhiqinyigu/vue-fabric-editor.git","type":"git"},"description":"基于 Vue2.6 + Fabric.js 的图片设计编辑器（移植自 ikuaitu/vue-fabric-editor）","maintainers":[{"name":"chenyican","email":"472427714@qq.com"}],"readme":"# vue-fabric-editor（Vue 2 版）\r\n\r\n基于 **Vue 2.6 + Fabric.js 5 + Vue CLI 4** 的图片 / 海报设计编辑器。\r\n移植自 [ikuaitu/vue-fabric-editor](https://github.com/ikuaitu/vue-fabric-editor)（Vue 3 + Vite 版），本仓库为 Vue 2 二次开发版。\r\n\r\n> 许可：MIT。详见 [LICENSE](./LICENSE)、[THIRD-PARTY-NOTICES.md](./THIRD-PARTY-NOTICES.md)、文末[致谢](#致谢)。\r\n\r\n## 交付物\r\n\r\n| 交付物 | 源码入口 | 构建产物 | 用途 |\r\n| --- | --- | --- | --- |\r\n| **编辑器库** `@chenyican/vue-fabric-editor` | `src/lib/index.js` | `dist/vue-fabric-editor/` | 完整编辑器组件 `FabricEditor` + 引擎 + 全部编辑插件 |\r\n| **前台渲染器** `@chenyican/vue-fabric-editor/fabric-renderer` | `src/lib/renderer.js` | `dist/fabric-renderer/` | 只读渲染组件 `FabricRenderer`，C 端展示 / 出图用，无编辑能力 |\r\n| **扩展示例** | `src/examples/` | — | 模板管理、在线图片、AI 工具、海报入口等，**拷贝进自己工程改造**使用 |\r\n\r\n---\r\n\r\n## 目录\r\n\r\n- [1. 本地跑起来](#1-本地跑起来)\r\n- [2. 作为组件使用](#2-作为组件使用)\r\n- [3. 组件文档](#3-组件文档)\r\n- [4. 扩展示例](#4-扩展示例)\r\n- [5. 二次开发](#5-二次开发)\r\n- [6. 常见问题（踩坑速查）](#6-常见问题踩坑速查)\r\n- [7. 发布 / 环境 / 字体 / 许可](#7-发布环境字体许可)\r\n\r\n---\r\n\r\n## 1. 本地体验/预览\r\n\r\n### 1.1 环境\r\n\r\n- **Node 12 ~ 16**（Vue CLI 4 + webpack 4）。Node 17+ 需额外设置 `NODE_OPTIONS=--openssl-legacy-provider`，否则 dev/build 会报 `ERR_OSSL_EVP_UNSUPPORTED`。\r\n- 首次执行 `npm install` 安装依赖。\r\n\r\n### 1.2 命令\r\n\r\n```bash\r\nnpm install                    # 安装依赖\r\n\r\nnpm run serve                  # 开发站点（默认 3000 端口，见 vue.config.js devServer）\r\nnpm run build                  # 构建演示站点 → dist/（index.html + js/css/fonts）\r\nnpm run build:staging          # 站点：staging 环境\r\nnpm run build:prod             # 站点：生产环境\r\n\r\nnpm run build:lib              # 构建编辑器库 → dist/vue-fabric-editor/\r\nnpm run build:lib:renderer     # 构建渲染器库 → dist/fabric-renderer/\r\n\r\nnpm test                       # jest 全量单测\r\nnpm run test:layer             # layer.vue 拖拽排序手动验证脚本（JSDOM，独立于 jest）\r\nnpm run typecheck              # 校验 types/*.d.ts\r\nnpm run lint                   # eslint\r\n```\r\n\r\n> **产物注意**：两个 lib 构建用 `--dest` 输出到不同子目录（不要改成同一个目录，后一次构建会清掉前一次产物）。\r\n> `npm run build`（站点）会清理 `dist/` 根目录，若同时需要 lib 产物，构建后重新执行对应 `build:lib*` 即可。`dist/` 已被 git 忽略。\r\n\r\n### 1.3 演示路由（`npm run serve` 后访问）\r\n\r\n| 路由 | 看什么 | 对应源码 |\r\n| --- | --- | --- |\r\n| `/demo` | **编辑器集成示例**：可跑示例，直接引 `src/` 源码 | `src/views/demo/index.vue` |\r\n| `/renderer-demo` | **渲染器集成示例**：模板 JSON + 数据 → 画布 | `src/views/renderer-demo/index.vue` |\r\n| `/legacy-demo` | 旧版数据（fabric 3.6.6 格式）渲染与转换 | `src/views/legacy-demo/index.vue` |\r\n| `/poster-entry-demo` | **运营后台集成示例**，海报配置入口：预览卡片 + 配置弹窗 + 跳编辑页 | `src/views/poster-entry-demo/index.vue` |\r\n| `/poster-editor-demo` | **运营后台集成示例**（配合上一条的跳转），海报编辑页 | `src/views/poster-entry-demo/editor.vue` |\r\n| `/` | 原[ikuaitu/vue-fabric-editor](https://github.com/ikuaitu/vue-fabric-editor)的演示页，用来校验功能完整性 | `src/views/home/index.vue` |\r\n| `/template` | 模板列表页 | `src/views/template/index.vue` |\r\n\r\n### 1.4 源码目录地图\r\n\r\n```\r\nsrc/\r\n├── lib/            # 包入口：index.js（编辑器）、renderer.js（渲染器）、FabricEditor.vue / FabricRenderer.vue\r\n├── core/           # 引擎：Editor / RendererCore / PluginEngine / 插件（plugin/）/ 纯函数（variableEngine、imageLoader…）\r\n├── components/     # 编辑器 UI（左栏面板、右栏属性、工具栏等）\r\n├── hooks/          # 组合式工具（useSelect / useI18n / useEditorContext…）\r\n├── views/          # 演示站点页面 + 业务外壳组件（RightPanel 等）\r\n├── examples/       # 扩展示例（拷贝改造用）\r\n└── language/       # 文案（zh / en / pt）\r\n```\r\n\r\n> **改源码前先读 [ARCHITECTURE.md](./ARCHITECTURE.md)**：它给出三条铁律、\"我要做 X 该改哪里\"速览表、双引擎约定与提交前检查清单（本文档只讲怎么用，不讲代码该写在哪）。\r\n\r\n---\r\n\r\n## 2. 作为组件使用\r\n\r\n### 2.1 安装\r\n\r\n```bash\r\nnpm i @chenyican/vue-fabric-editor\r\n```\r\n\r\n库的运行时依赖都声明在 `peerDependencies`：**npm 7+ 会自动装齐，npm 6 / `--legacy-peer-deps` 不会**。\r\n\r\n**① 查缺 + 生成补装命令**（在消费项目根目录执行，只读不改动文件；按接入方式选一条，输出可直接复制的 `npm i`）\r\n\r\n编辑器版：\r\n\r\n```bash\r\nnode -e \"const fs=require('fs'),p=require('@chenyican/vue-fabric-editor/package.json'),m=Object.keys(p.peerDependencies).filter(d=>!fs.existsSync('node_modules/'+d));console.log(m.length?'缺少 '+m.length+' 个，复制执行：\\n\\nnpm i '+m.join(' '):'编辑器依赖齐全，无需安装')\"\r\n```\r\n\r\n渲染器版（只检查渲染器必需的 9 个）：\r\n\r\n```bash\r\nnode -e \"const fs=require('fs'),need=['vue','@vue/composition-api','fabric','events','tapable','uuid','fontfaceobserver','jsbarcode','qr-code-styling'],m=need.filter(d=>!fs.existsSync('node_modules/'+d));console.log(m.length?'缺少 '+m.length+' 个，复制执行：\\n\\nnpm i '+m.join(' '):'渲染器依赖齐全，无需安装')\"\r\n```\r\n\r\n> 对照**所装版本**包内的 `peerDependencies` 检查根目录 `node_modules`。全新项目在空目录执行会输出\r\n> 完整的 16 / 9 个包命令，效果等同一次装齐。不跑命令也行：启动 / 构建报\r\n> `Module not found: Can't resolve 'xxx'` 时，按包名补装即可。\r\n\r\n> **从 1.0.3 及更早升级**：画布素材（控件图标 / 滤镜缩略图）已全部内联、`svg-path-editor-lib`\r\n> 已随包打包——消费项目里的 `VfeAssetsPlugin` 配置和 `transpileDependencies` 条目都可以删掉，\r\n> `npm i` 也不再有这两个包的要求。\r\n\r\n### 2.2 接入：编辑器（`FabricEditor`）\r\n\r\n两者是**独立入口、各自按需接入**：只做前台海报展示的项目看 §2.3 即可，不必引入 ViewUI / i18n 等编辑器专属依赖。\r\n\r\n**`main.js`**\r\n\r\n```js\r\nimport Vue from 'vue';\r\nimport ViewUI from 'view-design';\r\nimport 'view-design/dist/styles/iview.css';\r\nimport VueCompositionAPI from '@vue/composition-api';\r\nimport { createI18n, installRuntime } from '@chenyican/vue-fabric-editor';\r\nimport '@chenyican/vue-fabric-editor/style'; // 编辑器样式（渲染器用 /fabric-renderer/style）\r\nimport App from './App.vue';\r\n\r\nVue.use(VueCompositionAPI);\r\nVue.use(ViewUI);\r\n\r\n// 单实例注入：把本项目的 vue / composition-api 显式交给编辑器包（推荐，一行）\r\ninstallRuntime({ vue: Vue, compositionApi: VueCompositionAPI });\r\n\r\nnew Vue({ i18n: createI18n(), render: (h) => h(App) }).$mount('#app');\r\n```\r\n\r\n编辑器界面使用 `i-*` 组件，所以 `Vue.use(ViewUI)` 必须执行；根实例挂不挂 `i18n` 可选（不挂则 `t()` 退化为返回 key，文案显示为 key，功能不受影响）。\r\n\r\n关于那行 `installRuntime`：依赖树里若出现第二份 `vue` / `@vue/composition-api`，会分别导致 `_vm.$t is not a function` 与 `The setup binding property \"...\" is already declared`。入口调用一次即可消除，**跨打包器通用、不需要构建期配置**（渲染器同样适用，见 §2.3）。不调用则回退为历史行为，可用 `isRuntimeInjected()` 自检；原理见 [PACKAGING.md §4.6](./PACKAGING.md)。\r\n\r\n**`App.vue`**\r\n\r\n```vue\r\n<template>\r\n  <!-- 组件内部按 100vh 铺满，外层容器要给足高度 -->\r\n  <div style=\"height: 100vh; overflow: hidden\">\r\n    <FabricEditor\r\n      ref=\"editor\"\r\n      :adapters=\"adapters\"\r\n      :extensions=\"extensions\"\r\n      @ready=\"onReady\"\r\n      @save-request=\"onSave\"\r\n    />\r\n  </div>\r\n</template>\r\n\r\n<script>\r\nimport { FabricEditor } from '@chenyican/vue-fabric-editor';\r\n\r\nexport default {\r\n  components: { FabricEditor },\r\n  data() {\r\n    return {\r\n      adapters: {\r\n        font: { list: () => fetch('/api/fonts').then((r) => r.json()) },\r\n        size: { list: () => Promise.resolve([{ id: 1, name: '海报', width: 400, height: 600, unit: 'px' }]) },\r\n        variable: { list: () => Promise.resolve([{ path: 'course.name', label: '课程名', type: 'text' }]) },\r\n      },\r\n      extensions: [], // 见 §4\r\n    };\r\n  },\r\n  methods: {\r\n    onReady({ api }) {\r\n      // 业务自持初始加载\r\n      api.loadJSON(myTemplateJson);\r\n    },\r\n    async onSave({ json }) {\r\n      await fetch('/api/poster', { method: 'POST', body: JSON.stringify({ json }) });\r\n    },\r\n  },\r\n};\r\n</script>\r\n```\r\n\r\n### 2.3 接入：渲染器（`FabricRenderer`，只读展示）\r\n\r\n只渲染不编辑，**不需要 ViewUI、不需要 i18n**（svg-path-editor-lib 只服务编辑器且已随包打包）。\r\n\r\n**`main.js`**\r\n\r\n```js\r\nimport Vue from 'vue';\r\nimport VueCompositionAPI from '@vue/composition-api';\r\nimport { installRuntime } from '@chenyican/vue-fabric-editor/fabric-renderer';\r\nimport '@chenyican/vue-fabric-editor/fabric-renderer/style'; // 可选\r\nimport App from './App.vue';\r\n\r\nVue.use(VueCompositionAPI);\r\n// 单实例注入：作用与自检方式同 §2.2\r\ninstallRuntime({ vue: Vue, compositionApi: VueCompositionAPI });\r\n\r\nnew Vue({ render: (h) => h(App) }).$mount('#app');\r\n```\r\n\r\n**组件里用**\r\n\r\n```vue\r\n<template>\r\n  <div style=\"width: 400px; height: 600px\">\r\n    <FabricRenderer :json=\"json\" :data=\"data\" @error=\"onError\" />\r\n  </div>\r\n</template>\r\n\r\n<script>\r\nimport { FabricRenderer } from '@chenyican/vue-fabric-editor/fabric-renderer';\r\n\r\nexport default {\r\n  components: { FabricRenderer },\r\n  // json：编辑器保存的海报 JSON；data：变量数据（点路径取值，如 { user: { name: '张三' } }）\r\n  data: () => ({ json: null, data: {} }),\r\n};\r\n</script>\r\n```\r\n\r\n| 步骤 | 编辑器 | 渲染器 |\r\n| --- | --- | --- |\r\n| `Vue.use(VueCompositionAPI)` | 必须 | 必须 |\r\n| `Vue.use(ViewUI)` + `iview.css` | 必须 | 不需要 |\r\n| CSS 入口 | `/style` | `/fabric-renderer/style` |\r\n| `createI18n()` | 可选 | 不需要 |\r\n| `installRuntime({ vue, compositionApi })` | 推荐 | 推荐 |\r\n\r\n### 2.4 CSS / i18n / 类型\r\n\r\n| 项 | 现代栈（webpack5 / Vite） | webpack 4 |\r\n| --- | --- | --- |\r\n| 编辑器 JS | `import { FabricEditor } from '@chenyican/vue-fabric-editor'` | 相同 |\r\n| 编辑器 CSS | `import '@chenyican/vue-fabric-editor/style'` | `import '@chenyican/vue-fabric-editor/dist/vue-fabric-editor/vue-fabric-editor.css'` |\r\n| 渲染器 JS | `import { FabricRenderer } from '@chenyican/vue-fabric-editor/fabric-renderer'` | 相同 |\r\n| 渲染器 CSS | `import '@chenyican/vue-fabric-editor/fabric-renderer/style'` | `import '@chenyican/vue-fabric-editor/dist/fabric-renderer/fabric-renderer.css'` |\r\n\r\n- **i18n（仅编辑器）**：`createI18n()` 的实例挂到根实例 `i18n` 选项即可（见 §2.2）。未接入时 `t()` 退化为返回 key，界面仍可运行。\r\n- **类型**：包内自带 `.d.ts`（`types/index.d.ts`、`types/fabric-renderer.d.ts`），TS 项目开箱可用，无需 `declare module`。\r\n- **webpack4 + 根级 postcss 配置**：宿主根目录有 `postcss.config.js` 时，import 包内 css（`/style`、`/fabric-renderer/style`）或 iview.css 会报 `No PostCSS Config found`——postcss-loader 3 从 css 文件位置向上查找配置，node_modules 内的 css 找不到宿主根级配置。在 `vue.config.js` 显式指定：`css.loaderOptions.postcss.config.path = path.resolve(__dirname, 'postcss.config.js')`；宿主无 postcss 配置文件则不受影响。\r\n\r\n### 2.5 接入检查清单\r\n\r\n- [ ] `Vue.use(VueCompositionAPI)` 已执行（两个组件都依赖）\r\n- [ ] 已引入对应 CSS：编辑器 `/style`、渲染器 `/fabric-renderer/style`\r\n- [ ] 入口调用了 `installRuntime({ vue, compositionApi })`\r\n- [ ] **仅编辑器**：`Vue.use(ViewUI)` 已执行（模板使用 `i-*` 组件）\r\n- [ ] 外层容器给了高度（编辑器按 `100vh` 铺满）\r\n- [ ] 远程图片服务器支持 CORS（否则可显示但**无法导出 PNG**）\r\n\r\n---\r\n\r\n## 3. 组件文档\r\n\r\n| 组件 | 包内入口 | 说明 |\r\n| --- | --- | --- |\r\n| `FabricEditor` | `@chenyican/vue-fabric-editor` | 完整编辑器：顶栏 + 左栏面板 + 画布 + 右栏属性 + 全部编辑插件 |\r\n| `FabricRenderer` | `@chenyican/vue-fabric-editor/fabric-renderer` | 前台只读渲染：只加载与渲染，无编辑能力，体积更小 |\r\n\r\n### 3.1 `FabricEditor`\r\n\r\n#### 3.1.1 Props\r\n\r\n| 名称 | 类型 | 默认值 | 说明 |\r\n| --- | --- | --- | --- |\r\n| `adapters` | `Object` | `{}` | 能力适配器（业务数据源），见下表 |\r\n| `extensions` | `Array` | `[]` | 运行时扩展，见 [§3.1.6](#316-扩展extensions) |\r\n| `options` | `Object` | `{}` | 编辑器配置，见下表 |\r\n| `remoteImageMode` | `Boolean` | `false` | 强制远程图片模式：禁用本地上传与「在线图转 base64」，图片一律以远程 URL 入库 |\r\n| `defaultText` | `String` | `'新建文本'` | 新建文本元素默认内容 |\r\n| `defaultTextbox` | `String` | `'新建文本'` | 新建文本框元素默认内容 |\r\n| `defaultQrCodeData` | `String` | `'https://example.com'` | 二维码元素默认内容 |\r\n\r\n`options`：\r\n\r\n| 字段 | 类型 | 默认值 | 说明 |\r\n| --- | --- | --- | --- |\r\n| `showSaveButton` | `Boolean` | `true` | 是否显示顶栏「清空 / 保存 / 提交」；业务自持保存时置 `false` |\r\n| `messageDuration` | `Number` | `5` | 全局 Message 提示时长（秒），`0` 不自动关闭 |\r\n| `workspace` | `{ width, height }` | — | 初始化画布尺寸；不传由 `WorkspacePlugin` 按容器自适应 |\r\n| `cacheBust` | `Boolean \\| { param, getValue }` | `feDomain=location.hostname` | 远程图按接入域名分片缓存；`false` 关闭。JSON 存储态始终是干净 URL |\r\n| `useAssetManifest` | `Boolean` | `false` | 开启资源清单去重，相同素材只存一份 |\r\n| `crossOrigin` | `String \\| null` | `'anonymous'` | 图片跨域策略；`'strict'` 关闭回退（严格 CORS，失败即不显示） |\r\n\r\n`adapters` 契约：\r\n\r\n| key | 契约 | 说明 |\r\n| --- | --- | --- |\r\n| `font` | `{ list: () => Promise<[{ name, file, type, img }]> }` | 字体列表；不传则不用自定义字体 |\r\n| `size` | `{ list: () => Promise<[{ id, name, width, height, unit }]> }` | 画布尺寸预设 |\r\n| `variable` | `{ list: () => Promise<defs>, save?: (defs) => Promise }` | 变量表；未实现 `save` 时降级为「导出变量表 JSON」 |\r\n\r\n`adapters` 的 key 会原样注册进适配器注册表，扩展内可用 `api.getAdapter(key)` 取回；`font` / `size` / `variable` 由内置插件直接消费。\r\n\r\n#### 3.1.2 Events\r\n\r\n| 事件 | 载荷 | 说明 |\r\n| --- | --- | --- |\r\n| `ready` | `{ api, editor, canvas }` | 画布与全部插件初始化完成；`api` 为命令式接口 |\r\n| `save-request` | `{ json }` | 点击顶栏提交按钮；组件不落库，持久化由业务接管 |\r\n| `save-error` | `Error` | 导出失败（典型：跨域图片污染画布） |\r\n\r\n#### 3.1.3 Slot\r\n\r\n| 名称 | 说明 |\r\n| --- | --- |\r\n| `topbar` | 替换整个顶栏；不提供则用内置顶栏（导入 / 撤销重做 / 清空 / 快速预览 / 保存 / 提交） |\r\n\r\n#### 3.1.4 实例与上下文\r\n\r\n- `this.$refs.editor.api`：命令式 API，与 `ready` 事件里的 `api` 同源。\r\n- `provide('canvasEditor')` → 引擎实例；`provide('fabric')` → fabric 命名空间。\r\n- `useEditorContext()`：扩展组件内取 `{ canvas, editor, registry, ui, extensions, api, t, options }`。\r\n\r\n#### 3.1.5 `api` 方法\r\n\r\n| 分类 | 方法 | 说明 |\r\n| --- | --- | --- |\r\n| 画布 | `loadJSON(json)` | 加载模板 JSON |\r\n| | `getJSON()` | 取当前画布 JSON |\r\n| | `setSize(w, h)` / `getSize()` | 设置 / 读取画布尺寸 |\r\n| | `clear()` | 清空画布 |\r\n| | `preview()` | 预览 |\r\n| | `exportFile(type, multiplier)` | 导出 `'json'` / `'svg'` / `'png'`（`multiplier` 为 png 倍率） |\r\n| | `undo()` / `redo()` | 撤销 / 重做 |\r\n| | `getSelectMode()` | 当前选择模式 |\r\n| 注册表 | `registerAdapter(key, value)` | 注册适配器，返回注销函数 |\r\n| | `getAdapter(key)` / `hasAdapter(key)` | 读取 / 判断适配器 |\r\n| | `registerComponent(key, comp)` / `getComponent(key)` | 覆盖 / 读取内置 UI 组件 |\r\n| 扩展 | `registerExtension(ext)` / `unregisterExtension(id)` | 运行时注册 / 注销扩展 |\r\n| 事件 | `on(event, cb)` / `off(event, cb)` / `emit(event, payload)` | 引擎事件（如 `variable:previewChange`、`image:cors-fallback`） |\r\n| 插件 | `getPlugin(name)` | 取插件实例 |\r\n| 变量表 | `setVariableSchema(defs)` / `getVariableSchema()` | 注入 / 读取变量表（视为导入，只读） |\r\n| | `ensureVariableSchemaLoaded()` | 适配器懒加载（幂等） |\r\n| | `addCustomVariable` / `updateCustomVariable(path, patch)` / `removeCustomVariable(path)` | 自定义变量 CRUD |\r\n| | `isImportedVariable(path)` | 是否导入变量（只读） |\r\n| | `saveVariableSchema()` | 调 `adapters.variable.save` 落库 |\r\n| | `exportVariableSchema()` | 导出变量表 JSON 字符串 |\r\n| | `getVariableEntries()` | 扫描画布变量 → `[{ path, fields }]` |\r\n\r\n#### 3.1.6 扩展（extensions）\r\n\r\n```js\r\n{\r\n  id: 'template',                                            // 必填且唯一\r\n  services: { template: { list, get, create, update } },      // 自动注册进 adapter 注册表\r\n  panels: [                                                   // region: left / right / top\r\n    { region: 'left', tab: { key: 'tpl', label: '模板', icon: 'md-images' }, component: TplPanel },\r\n  ],\r\n  overrides: [{ component: 'TopbarImport', with: MyTopbarImport }], // 覆盖内置 UI 组件\r\n  lifecycle: { onReady(ctx), onDestroy(ctx) },\r\n}\r\n```\r\n\r\n- `panels` 注册即出现、注销即消失（reactive）；`left` 区排在「元素 / 图层」之后。\r\n- `services` / `overrides` 随扩展注销自动清理。\r\n\r\n### 3.2 `FabricRenderer`\r\n\r\n#### 3.2.1 Props\r\n\r\n| 名称 | 类型 | 默认值 | 说明 |\r\n| --- | --- | --- | --- |\r\n| `json` | `Object \\| String` | `null` | 编辑器输出的模板 JSON；字符串自动 `JSON.parse` |\r\n| `data` | `Object` | `{}` | 变量数据，按点路径取值，如 `{ user: { name: '张三' } }` |\r\n| `schema` | `Array` | `null` | 变量表（可选），用于 `defaultValue` 回退；未注入时回读模板 `variableMeta.schema` |\r\n| `adapters` | `Object` | `{}` | 与编辑器同契约；渲染期消费 `font.list()` |\r\n| `options` | `Object` | `{}` | 渲染配置，见下表 |\r\n\r\n> `schema` 优先级：`schema` prop > `options.schema` > 模板内 `variableMeta.schema`（不做 merge）。\r\n\r\n`options`：\r\n\r\n| 字段 | 类型 | 默认值 | 说明 |\r\n| --- | --- | --- | --- |\r\n| `delimiter` | `Object` | 模板 `variableMeta.delimiter` → 默认分隔符 | 变量分隔符 `{ start, end }` |\r\n| `defaultQrCodeData` | `String` | — | 二维码兜底内容 |\r\n| `schema` | `Array` | — | 等价于 `schema` prop（prop 优先） |\r\n| `cacheBust` | `Boolean \\| { param, getValue }` | 同编辑器 | `false` 关闭 |\r\n| `crossOrigin` | `String \\| null` | `'anonymous'` | 服务器不支持 CORS 时置 `null`（仅可显示、不可导出） |\r\n\r\n#### 3.2.2 Events\r\n\r\n| 事件 | 载荷 | 说明 |\r\n| --- | --- | --- |\r\n| `ready` | `{ core, canvas }` | 画布与渲染内核创建完成 |\r\n| `rendered` | `{ core, canvas }` | 一次渲染流程完成 |\r\n| `error` | `Error` | 渲染过程异常 |\r\n| `renderer-error` | `payload` | 资源加载失败（如背景图 CORS / URL 失效）；默认 `console.warn`，宿主可监听后自行提示 |\r\n\r\n#### 3.2.3 渲染规则\r\n\r\n- `json` / `data`（深度监听）/ `schema` 任一变化自动重渲染；并发渲染按序号丢弃过期结果。\r\n- 管线：变量替换（深拷贝，不污染传入 JSON）→ 资源清单展开 + 缺省字段补回 + 二维码/条码参数还原 + 字体加载 → `autoGrow` 增高 → 图片就绪后变量图拉伸 + 背景重排 → 上屏。\r\n- 画布按 JSON 实际像素 **1:1 显示，不缩放**；容器不足时滚动查看。\r\n- 组件卸载时自动 `core.destroy()`。\r\n\r\n---\r\n\r\n## 4. 扩展示例\r\n\r\n`src/examples/` 是**拷贝改造**用的工程示例，不是运行时依赖。本地可先看 `/demo` 路由（引源码实时可跑）。\r\n\r\n| 示例 | 位置 | 说明 |\r\n| --- | --- | --- |\r\n| template-extension | `src/examples/template-extension/` | 模板管理（列表 / 保存 / 加载）：`index.js`（扩展定义）+ `adapter.js`（服务实现）+ `TemplatePanel.vue`（面板） |\r\n| online-image | `src/examples/online-image/` | 在线图片：CDN 上传 + 素材面板 |\r\n| ai-tools-extension | `src/examples/ai-tools-extension/` | AI 工具面板 |\r\n| poster-entry | `src/examples/poster-entry/` | **海报入口范式**：预览舞台（`PosterEntryStage.vue`）+ 查看/配置弹窗（`PosterViewModal.vue`）+ 预览（`PosterPreview.vue`）+ 编辑页宿主（`PosterEditorHost.vue`）+ 跨页交接（`handoff.js`）+ 旧格式兼容（`admin/`） |\r\n| smart-poster/legacy | `src/examples/smart-poster/legacy/` | 旧版 fabric 3.6.6 数据渲染与转换（`normalizeLegacyObject`） |\r\n\r\n### 拷贝改造三步\r\n\r\n1. 把整个示例目录拷进你的工程（如 `src/extensions/template/`）。\r\n2. 把其中的接口（`adapter.js` / `services`）换成你的后端 API。\r\n3. 在 `FabricEditor` 的 `:extensions` 数组里引入：\r\n\r\n```js\r\nimport templateExtension from './extensions/template-extension';\r\nexport default { data: () => ({ extensions: [templateExtension] }) };\r\n```\r\n\r\n### 海报入口范式（`poster-entry`）\r\n\r\n适合\"后台配置海报 → 打开独立编辑页 → 保存回传\"的场景，闭环如下：\r\n\r\n1. 配置页用 `PosterEntryStage` 展示预览卡片；点「查看」打开弹窗（预览 / JSON 输入双模式），点「配置海报」跳编辑页。\r\n2. 编辑页（`PosterEditorHost.vue`）读取交接信封（`handoff.js`，基于 localStorage + token），\r\n   `ready` 后 `api.loadJSON(json)` 加载待编辑数据。\r\n3. 保存时 `save-request` → 最小化 JSON 回写信封 → 原页面消费结果或回跳来源页。\r\n\r\n真实落地参考：`admin_frontend` 项目的 `src/js/views/poster-editor/`。\r\n\r\n---\r\n\r\n## 5. 二次开发\r\n\r\n### 5.1 从哪里下手\r\n\r\n| 想做的事 | 改哪里 |\r\n| --- | --- |\r\n| 改编辑器 UI 结构 / 顶栏 / 左右栏 | `src/lib/FabricEditor.vue`、`src/views/home/components/*` |\r\n| 改工具 / 属性面板 | `src/components/*`（右侧属性见 `src/components/attrPanel/`） |\r\n| 改画布行为、加载/保存管线 | `src/core/Editor.js`、`src/core/ServersPlugin.js`、`src/core/plugin/*` |\r\n| 加一个编辑能力（插件） | 见 [§5.2](#52-新增一个插件) |\r\n| 加业务面板 / 覆盖内置 UI | 用 `extensions`（§3.1.6），无需改源码 |\r\n| 加命令式 API | `src/lib/api.js`（`createEditorApi`） |\r\n| 改变量能力 | `src/core/variableEngine.js`、`src/core/plugin/VariablePlugin.js` |\r\n| 加文案 | `src/language/{zh,en,pt}.json` |\r\n\r\n### 5.2 新增一个插件\r\n\r\n插件是\"编辑能力\"的标准扩展单位（内置 28 个插件都走这套协议）。\r\n\r\n```js\r\n// src/core/plugin/MyPlugin.js\r\nexport default class MyPlugin {\r\n  // 静态字段：唯一名、对外事件、代理到 editor 实例上的方法名\r\n  static pluginName = 'MyPlugin';\r\n  static events = ['myPlugin:change'];   // 可选：声明后可在 _checkPlugin 中查重\r\n  static apis = ['doSomething'];         // 可选：声明后 editor.doSomething() 可用\r\n\r\n  constructor(canvas, editor, options) {\r\n    this.canvas = canvas;\r\n    this.editor = editor;\r\n    this.options = options || {};\r\n    this.init();\r\n  }\r\n\r\n  init() {\r\n    // 订阅选择/画布事件、注册右键菜单、初始化状态\r\n  }\r\n\r\n  // ---- 生命周期 hooks（返回 Promise 或值；按注册顺序串行执行）----\r\n  hookImportBefore() { /* 加载 JSON 前 */ }\r\n  hookImportAfter() { /* 加载 JSON 后，可拿到画布已有对象 */ return Promise.resolve(); }\r\n  hookSaveBefore() { /* 取 JSON 前，可做收尾 */ }\r\n  hookSaveAfter() { /* 导出后 */ }\r\n  hookTransform() { /* 对象变换时（拖拽/缩放/旋转）*/ }\r\n\r\n  // ---- 可选能力 ----\r\n  // hotkeys = ['ctrl+z'];  hotkeyEvent(keyName, e) {}\r\n  // contextMenu() { return [{ text: '动作', callback: () => {} }]; }\r\n\r\n  // ---- 对外 API ----\r\n  doSomething(payload) {\r\n    this.canvas.requestRenderAll();\r\n    this.editor.emit('myPlugin:change', payload);\r\n  }\r\n\r\n  destroy() { /* 解绑事件、清理资源 */ }\r\n}\r\n```\r\n\r\n注册（`src/lib/FabricEditor.vue` 的 `.use(...)` 链）：\r\n\r\n```js\r\nimport MyPlugin from '@/core/plugin/MyPlugin';\r\neditor.use(MyPlugin, { someOption: true });\r\n```\r\n\r\n约定与坑：\r\n\r\n- `pluginName` 重复会直接抛错；`apis` / `events` 名称全局唯一（避免覆盖内置方法）。\r\n- hooks 是 `AsyncSeriesHook`（tapable）：必须返回 Promise 或值，**不要吞掉异常**，否则加载管线会静默中断。\r\n- 插件销毁由 `editor.destory()` 统一触发，`destroy()` 里记得 `canvas.off(...)`。\r\n- 需要与 UI 通信时：插件 `editor.emit('xxx')` → UI 监听；UI 调 `api.getPlugin('MyPlugin')` 拿实例。\r\n\r\n### 5.3 新增 / 覆盖 UI\r\n\r\n- **加面板**：扩展的 `panels`（region: `left` / `right` / `top`），无需改源码，见 §3.1.6。\r\n- **覆盖内置组件**：扩展的 `overrides: [{ component: 'TopbarImport', with: MyComp }]`；\r\n  内置可覆盖 key 见 `src/lib/index.js` 导出（`TopbarImport`、`RightPanel`）。\r\n- **整体替换顶栏**：用 `FabricEditor` 的 `topbar` 插槽。\r\n\r\n### 5.4 新增命令式 API\r\n\r\n在 `src/lib/api.js` 的 `createEditorApi(ctx)` 中追加方法（`ctx` 提供 `canvas / editor / registry / ui / extensions`），\r\n即可通过 `ready` 事件拿到的 `api` 或 `this.$refs.editor.api` 调用。\r\n\r\n### 5.5 改完怎么验\r\n\r\n```bash\r\nnpm run lint           # 代码规范\r\nnpm test               # 单测（新增行为建议补 tests/）\r\nnpm run typecheck      # 改了对外 API / Props 时同步 types/*.d.ts\r\nnpm run serve          # /demo 看效果\r\nnpm run build:lib && npm run build:lib:renderer   # 确认库产物可构建\r\n```\r\n\r\n> 对外 API（Props / 事件 / 命令式方法 / 扩展协议）有变更时，**必须同步更新** `types/index.d.ts` 与 `types/fabric-renderer.d.ts`（手写维护，已纳入 `npm run typecheck`）。\r\n\r\n---\r\n\r\n## 6. 常见问题（踩坑速查）\r\n\r\n| 现象 | 原因 | 处理 |\r\n| --- | --- | --- |\r\n| `The setup binding property ... is already declared` | 依赖树有两份 `@vue/composition-api` | 入口 `installRuntime({ vue, compositionApi })`；或 `npm dedupe` |\r\n| `_vm.$t is not a function` | 依赖树有两份 `vue` | 同上 |\r\n| webpack4 `Can't resolve '@chenyican/vue-fabric-editor/style'` | webpack4 不识别 `exports` 子路径 | 用完整路径 `.../dist/vue-fabric-editor/vue-fabric-editor.css`（§2.4） |\r\n| `No PostCSS Config found in: ...` | vue-cli4 / postcss-loader 3 对 node_modules 内 css（本包 style、iview.css）向上找不到宿主根级配置 | `vue.config.js` 指定 `css.loaderOptions.postcss.config.path`（§2.4）；无根级 postcss 配置文件则不受影响 |\r\n| `Module parse failed` / `class static block` 相关报错 | 宿主其它依赖含 ES2022 语法 | 在 `transpileDependencies` 加入该依赖（本包 1.0.4 起 `svg-path-editor-lib` 已随包打包，无需配置） |\r\n| `Cannot find module '.../loader/webpack-plugin.js'` | 1.0.4 起素材已内联，宿主接入插件已移除 | 删除消费项目 vue.config.js 里的 `VfeAssetsPlugin` 配置（见 §2.1 升级说明） |\r\n| 导出 PNG 报跨域（`SecurityError`） | 画布被无 CORS 头的远程图污染 | 图床返回 `Access-Control-Allow-Origin`；或用同源图片代理 |\r\n| 图片能显示但导出缺图 | 触发了 CORS 回退（画布已污染） | 同上；`options.crossOrigin = 'strict'` 可改为\"失败即不显示\" |\r\n| 字体不生效 | 未提供 `adapters.font` 或字体文件无 CORS | 实现字体适配器并确保字体可跨域访问 |\r\n| 画布空白 / 尺寸为 0 | 挂载时容器无高度 | 外层容器给足高度（组件按 `100vh` 铺满） |\r\n| `MaxListenersExceededWarning`（selectOne 等） | 多个属性组件合法订阅 | 1.0.2+ 已内置 `setMaxListeners(0)`，升级即可 |\r\n| dev/build 报 `ERR_OSSL_EVP_UNSUPPORTED` | Node 17+ 与 webpack4 的 OpenSSL 3 | 用 Node 12–16，或 `NODE_OPTIONS=--openssl-legacy-provider` |\r\n\r\n更多构建期 / 发布期问题见 [PACKAGING.md](./PACKAGING.md) 的排查清单。\r\n\r\n---\r\n\r\n## 7. 发布 / 环境 / 字体 / 许可\r\n\r\n### 7.1 发布\r\n\r\n打包、发布流程、CI（OIDC）与消费侧验证见 **[PACKAGING.md](./PACKAGING.md)**。\r\n\r\n### 7.2 环境配置（仅演示站点）\r\n\r\n`.env` 中的变量只供**演示站点与示例页面**使用；构建两个 lib 不依赖它们（库不读任何环境变量）。\r\n\r\n| 变量 | 说明 |\r\n| --- | --- |\r\n| `VUE_APP_TITLE` | 站点标题 |\r\n| `VUE_APP_BASE_PATH` | 部署基础路径（生产 `publicPath`） |\r\n| `VUE_APP_APIHOST` | 素材 / 模板等服务地址 |\r\n| `VUE_APP_ADMINAPIHOST` | 后台管理接口地址 |\r\n| `VUE_APP_FLAG` | 环境标识 `dev` / `staging` / `prod` |\r\n\r\n私有地址请写进 `.env.local`（已被 git 忽略），避免提交到仓库。\r\n\r\n### 7.3 字体\r\n\r\n仓库不内置字体（上游内置的商业中文字体已因版权移除）。如需内置，请使用可自由分发的字体\r\n（思源黑体、霞鹜文楷等 OFL / Apache-2.0 授权），放入 `src/assets/fonts/cn/` 并在\r\n`src/assets/fonts/font.css` 声明 `@font-face`。\r\n\r\n### 7.4 许可与致谢\r\n\r\n- 上游项目：[ikuaitu/vue-fabric-editor](https://github.com/ikuaitu/vue-fabric-editor)（MIT，Vue 3 + Vite + TS）。\r\n- 本仓库是其在 **Vue 2.6 + Vue CLI + JavaScript** 下的移植与二次开发版，沿用 MIT 协议，\r\n  保留上游源码中的版权与作者声明（各文件头 `@Author` 注释请勿批量删除）。\r\n- 第三方代码与资源清单： [THIRD-PARTY-NOTICES.md](./THIRD-PARTY-NOTICES.md)。\r\n\r\n#### 致谢\r\n\r\n- 上游作者 秦少卫（nihaojob）及 [vue-fabric-editor](https://github.com/ikuaitu/vue-fabric-editor) 全体贡献者\r\n- 刘明野（标尺功能）、palxiao（渐变组件）\r\n","readmeFilename":"README.md"}