├── .browserslistrc
├── babel.config.js
├── work
├── sketch.png
├── mindnode.png
├── artworks
│ ├── 00.png
│ ├── 01.png
│ ├── 03.png
│ ├── 04.png
│ └── 05.png
├── pixel-paint.pxcp
├── pixel-paint.sketch
├── pixel-paint.mindnode
│ ├── contents.xml
│ ├── viewState.plist
│ ├── QuickLook
│ │ └── Preview.jpg
│ └── style.mindnodestyle
│ │ ├── metadata.plist
│ │ └── contents.xml
└── convert.js
├── public
├── favicon.ico
└── index.html
├── src
├── assets
│ ├── logo.png
│ ├── BPdotsSquareBold.otf
│ └── icon-set.js
├── views
│ ├── About.vue
│ ├── Home.vue
│ ├── artwork.vue
│ └── edit.vue
├── App.vue
├── store
│ ├── getter.js
│ ├── actions.js
│ ├── index.js
│ ├── state.js
│ └── mutations.js
├── components
│ ├── common
│ │ ├── alert
│ │ │ ├── alert.js
│ │ │ ├── instance.js
│ │ │ └── alert.vue
│ │ ├── prompt.vue
│ │ └── confirm.vue
│ ├── edit
│ │ ├── cursor.vue
│ │ ├── grid-highlight.vue
│ │ ├── grid.vue
│ │ ├── rename.vue
│ │ ├── push.vue
│ │ ├── brush-list.vue
│ │ ├── touch.vue
│ │ ├── header-bar.vue
│ │ ├── sidebar.vue
│ │ └── draw.vue
│ ├── artwork
│ │ ├── add-new.vue
│ │ ├── canvas-item.vue
│ │ └── new-canvas.vue
│ └── HelloWorld.vue
├── svg
│ ├── clear.svg
│ ├── share.svg
│ ├── export.svg
│ ├── rename.svg
│ ├── pencil-add.svg
│ ├── undo.svg
│ ├── brush.svg
│ ├── redo.svg
│ ├── move.svg
│ ├── push.svg
│ ├── palette.svg
│ ├── cursor.svg
│ ├── fill.svg
│ ├── grid.svg
│ └── buttonDraw.svg
├── js
│ ├── uuid.js
│ ├── cache.js
│ ├── storage.js
│ └── jsonc.js
├── main.js
├── style
│ ├── global.scss
│ └── variable.scss
└── router.js
├── .editorconfig
├── .gitignore
├── .eslintrc.js
├── postcss.config.js
├── vue.config.js
├── .travis.yml
├── README.md
├── package.json
└── LICENSE
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/work/sketch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/work/sketch.png
--------------------------------------------------------------------------------
/work/mindnode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/work/mindnode.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/work/artworks/00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/work/artworks/00.png
--------------------------------------------------------------------------------
/work/artworks/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/work/artworks/01.png
--------------------------------------------------------------------------------
/work/artworks/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/work/artworks/03.png
--------------------------------------------------------------------------------
/work/artworks/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/work/artworks/04.png
--------------------------------------------------------------------------------
/work/artworks/05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/work/artworks/05.png
--------------------------------------------------------------------------------
/work/pixel-paint.pxcp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/work/pixel-paint.pxcp
--------------------------------------------------------------------------------
/work/pixel-paint.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/work/pixel-paint.sketch
--------------------------------------------------------------------------------
/src/assets/BPdotsSquareBold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/src/assets/BPdotsSquareBold.otf
--------------------------------------------------------------------------------
/src/views/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is an about page
4 |
5 |
6 |
--------------------------------------------------------------------------------
/work/pixel-paint.mindnode/contents.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/work/pixel-paint.mindnode/contents.xml
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/work/pixel-paint.mindnode/viewState.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/work/pixel-paint.mindnode/viewState.plist
--------------------------------------------------------------------------------
/work/pixel-paint.mindnode/QuickLook/Preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/journey-ad/pixel-paint/HEAD/work/pixel-paint.mindnode/QuickLook/Preview.jpg
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/src/store/getter.js:
--------------------------------------------------------------------------------
1 | export default {
2 | viewportSize (state) {
3 | return Math.min(Math.max(16, state.viewportSize), state.artwork.size)
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/store/actions.js:
--------------------------------------------------------------------------------
1 | export default {
2 | setCurrentOffset ({ commit }, offset) {
3 | commit('setCurrentOffset', offset)
4 | },
5 | psuhHistory ({ commit }, action) {
6 | commit('pushHistory', action)
7 | },
8 | psuhTempHistory ({ commit }, action) {
9 | commit('pushTempHistory', action)
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | temp
6 |
7 | # local env files
8 | .env.local
9 | .env.*.local
10 |
11 | # Log files
12 | npm-debug.log*
13 | yarn-debug.log*
14 | yarn-error.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import state from './state'
2 | import mutations from './mutations'
3 | import actions from './actions'
4 | import getters from './getter'
5 | import Vue from 'vue'
6 | import Vuex from 'vuex'
7 |
8 | Vue.use(Vuex)
9 |
10 | export default new Vuex.Store({
11 | state,
12 | mutations,
13 | actions,
14 | getters
15 | })
16 |
--------------------------------------------------------------------------------
/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/essential',
8 | '@vue/standard'
9 | ],
10 | rules: {
11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
13 | },
14 | parserOptions: {
15 | parser: 'babel-eslint'
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/common/alert/alert.js:
--------------------------------------------------------------------------------
1 | import Instance from './instance.js'
2 |
3 | let alertInstance
4 |
5 | function getAlertInstance () {
6 | alertInstance = alertInstance || Instance.newInstance()
7 | return alertInstance
8 | }
9 |
10 | function alert ({ title = 'Alert', content = '' }) {
11 | let instance = getAlertInstance()
12 | instance.show({
13 | title,
14 | content
15 | })
16 | }
17 | export default alert
18 |
--------------------------------------------------------------------------------
/src/svg/clear.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/svg/share.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/svg/export.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/svg/rename.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/work/pixel-paint.mindnode/style.mindnodestyle/metadata.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | author
6 | MindNode
7 | id
8 | 514DD5D6-7C79-481B-8CB1-A08FA9F5D3DF
9 | title
10 | Tropical
11 | version
12 | 3
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/js/uuid.js:
--------------------------------------------------------------------------------
1 | // https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript#answer-8809472
2 | export default () => {
3 | let d = Date.now()
4 | if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
5 | d += performance.now()
6 | }
7 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
8 | let r = (d + Math.random() * 16) % 16 | 0
9 | d = Math.floor(d / 16)
10 | return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
11 | })
12 | }
13 |
--------------------------------------------------------------------------------
/src/store/state.js:
--------------------------------------------------------------------------------
1 | export default {
2 | artwork: {
3 | id: '',
4 | title: '',
5 | size: -1,
6 | created: -1,
7 | updated: -1,
8 | brush: {
9 | title: '',
10 | colors: []
11 | },
12 | currentBrushColor: '',
13 | canvasData: [],
14 | thumb: ''
15 | },
16 | canvas: null,
17 | isPushing: false,
18 | isGridShow: true,
19 | viewportSize: -1,
20 | viewportOffset: { x: 0, y: 0 },
21 | currentOffset: { x: 0, y: 0 },
22 | undoHistory: [],
23 | redoHistory: []
24 | }
25 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {},
4 | 'postcss-px-to-viewport': {
5 | unitToConvert: 'px',
6 | viewportWidth: 375,
7 | unitPrecision: 5,
8 | propList: ['*'],
9 | viewportUnit: 'vw',
10 | fontViewportUnit: 'vw',
11 | selectorBlackList: [],
12 | minPixelValue: 1,
13 | mediaQuery: false,
14 | replace: true,
15 | exclude: [],
16 | landscape: false,
17 | landscapeUnit: 'vw',
18 | landscapeWidth: 568
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/svg/pencil-add.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import store from './store/index'
5 | import Icon from 'vue-svg-icon/Icon.vue'
6 | import Alert from './components/common/alert/alert'
7 | import Vue2TouchEvents from 'vue2-touch-events'
8 | import 'normalize.css'
9 | import './style/global.scss'
10 |
11 | Vue.config.productionTip = false
12 |
13 | Vue.component('icon', Icon)
14 |
15 | Vue.prototype.$Alert = Alert
16 |
17 | Vue.use(Vue2TouchEvents)
18 |
19 | new Vue({
20 | router,
21 | store,
22 | render: h => h(App)
23 | }).$mount('#app')
24 |
--------------------------------------------------------------------------------
/src/style/global.scss:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "pixel";
3 | src: url("../assets/BPdotsSquareBold.otf");
4 | }
5 |
6 | html,
7 | body {
8 | font-family: 'pixel', 'PingFang SC', 'STHeitiSC-Light', 'Helvetica-Light', arial, sans-serif, 'Droid Sans Fallback';
9 | letter-spacing: -0.02em;
10 | line-height: 1;
11 | user-select: none;
12 | -webkit-tap-highlight-color: transparent;
13 | background: $background-color;
14 | overscroll-behavior: none; // 禁止 Chrome 63+ 的下拉刷新行为
15 | image-rendering: pixelated; // 使用符合像素风格的临近算法渲染页面
16 | }
17 |
18 | *,
19 | ::after,
20 | ::before {
21 | box-sizing: border-box;
22 | }
--------------------------------------------------------------------------------
/src/components/common/alert/instance.js:
--------------------------------------------------------------------------------
1 | import Alert from './alert.vue'
2 | import Vue from 'vue'
3 |
4 | Alert.newInstance = properties => {
5 | const props = properties || {}
6 | const Instance = new Vue({
7 | data: props,
8 | render (h) {
9 | return h(Alert, {
10 | props: props
11 | })
12 | }
13 | })
14 |
15 | const component = Instance.$mount()
16 | document.body.appendChild(component.$el)
17 | const alert = Instance.$children[0]
18 |
19 | return {
20 | show (options) {
21 | alert.show(options)
22 | },
23 | ok () {
24 | alert.ok()
25 | }
26 | }
27 | }
28 |
29 | export default Alert
30 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
10 |
12 | pixel-paint
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/components/edit/cursor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
17 |
18 |
31 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | let webpack = require('webpack')
2 | let LodashModuleReplacementPlugin = require('lodash-webpack-plugin')
3 |
4 | module.exports = {
5 | publicPath: process.env.NODE_ENV === 'production'
6 | ? './.'
7 | : '/',
8 | css: {
9 | loaderOptions: {
10 | sass: {
11 | // @/ is an alias to src/
12 | // so this assumes you have a file named `src/variables.scss`
13 | data: '@import "@/style/variable.scss";'
14 | }
15 | }
16 | },
17 | chainWebpack: config => {
18 | config.plugin('ignore')
19 | .use(new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/))
20 | config.plugin('loadshReplace')
21 | .use(new LodashModuleReplacementPlugin())
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/svg/undo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/svg/brush.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/svg/redo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "11"
4 |
5 | install:
6 | - npm install
7 |
8 | script:
9 | - npm run build
10 |
11 | after_success:
12 | - cd ./dist
13 | - git init
14 | - git config --global user.name "${U_NAME}"
15 | - git config --global user.email "${U_EMAIL}"
16 | - git add .
17 | - git commit -m "Automatically publish from travis-ci"
18 | - git push --quiet --force "https://${GH_TOKEN}@${GH_REF}" master:${P_BRANCH}
19 |
20 | branches:
21 | only:
22 | - master
23 |
24 | notifications:
25 | email:
26 | - ad@imjad.cn
27 | on_failure: always
28 |
29 | # Note: you should set Environment Variables here or 'Settings' on travis-ci.org
30 | env:
31 | global:
32 | - GH_REF: github.com/journey-ad/pixel-paint.git
33 |
--------------------------------------------------------------------------------
/src/svg/move.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/icon-set.js:
--------------------------------------------------------------------------------
1 | import Brush from './icons/brush.svg'
2 | import ButtonDraw from './icons/buttonDraw.svg'
3 | import Clear from './icons/clear.svg'
4 | import Export from './icons/export.svg'
5 | import Fill from './icons/fill.svg'
6 | import Grid from './icons/grid.svg'
7 | import Move from './icons/move.svg'
8 | import Palette from './icons/palette.svg'
9 | import PencilAdd from './icons/pencil-add.svg'
10 | import Push from './icons/push.svg'
11 | import Redo from './icons/redo.svg'
12 | import Rename from './icons/rename.svg'
13 | import Share from './icons/share.svg'
14 | import Undo from './icons/undo.svg'
15 |
16 | export {
17 | Brush,
18 | ButtonDraw,
19 | Clear,
20 | Export,
21 | Fill,
22 | Grid,
23 | Move,
24 | Palette,
25 | PencilAdd,
26 | Push,
27 | Redo,
28 | Rename,
29 | Share,
30 | Undo
31 | }
32 |
--------------------------------------------------------------------------------
/src/svg/push.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/components/artwork/add-new.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | New Canvas
5 |
6 |
7 |
8 |
17 |
18 |
40 |
--------------------------------------------------------------------------------
/src/svg/palette.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/style/variable.scss:
--------------------------------------------------------------------------------
1 | $theme-color: #d46791;
2 | $theme-color-active: #6793d4;
3 | $theme-color-disabled: #9e9e9e;
4 | $item-color:#e9e9e9;
5 | $background-color: #f7f7f7;
6 | $background-color-overlay: #0009;
7 | $background-color-list: #fafafa;
8 | $background-color-sidebar: #333333;
9 | $background-color-warn: #f0ad4e;
10 | $background-color-danger: #bb2124;
11 | $border-color: #f2f2f2;
12 | $border-color-edit:#e0e0e0;
13 | $border-color-push: #000;
14 | $border-color-sidebar:#959595;
15 | $white-color: #ffffff;
16 | $black-color: #4a4a4a;
17 | $text-color:#ffffff;
18 | $text-title-color:#4a4a4a;
19 | $text-meta-color:#9b9b9b;
20 | $gray-color:#9b9b9b;
21 | $push-color:#4f4759;
22 |
23 | $box-shadow: 0px 2px 16px rgba(0, 0, 0, 0.12);
24 |
25 | $font-size-small-s: 10px;
26 | $font-size-small: 12px;
27 | $font-size-small-x: 14px;
28 | $font-size-medium: 16px;
29 | $font-size-medium-x: 18px;
30 | $font-size-large: 20px;
31 | $font-size-large-x: 22px;
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 像素绘板
2 |
3 | [](https://www.travis-ci.org/journey-ad/pixel-paint)
4 |
5 | ## 开坑中
6 |
7 | *功能和界面参考[dotpict](https://play.google.com/store/apps/details?id=net.dotpicko.dotpict)*
8 |
9 | [DEMO](https://journey-ad.github.io/pixel-paint)
10 |
11 | 
12 |
13 | ### 应用原型图
14 | 
15 |
16 |
17 | ### 思维导图
18 | 
19 |
20 | ## Project setup
21 | ```
22 | yarn install
23 | ```
24 |
25 | ### Compiles and hot-reloads for development
26 | ```
27 | yarn run serve
28 | ```
29 |
30 | ### Compiles and minifies for production
31 | ```
32 | yarn run build
33 | ```
34 |
35 | ### Run your tests
36 | ```
37 | yarn run test
38 | ```
39 |
40 | ### Lints and fixes files
41 | ```
42 | yarn run lint
43 | ```
44 |
45 | ### Customize configuration
46 | See [Configuration Reference](https://cli.vuejs.org/config/).
47 |
--------------------------------------------------------------------------------
/src/svg/cursor.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/router.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 |
4 | const Artwork = (resolve) => {
5 | import(/* webpackChunkName: "artwork" */ './views/artwork.vue').then((module) => {
6 | resolve(module)
7 | })
8 | }
9 |
10 | const Edit = (resolve) => {
11 | import(/* webpackChunkName: "edit" */ './views/edit.vue').then((module) => {
12 | resolve(module)
13 | })
14 | }
15 |
16 | Vue.use(Router)
17 |
18 | export default new Router({
19 | routes: [
20 | {
21 | path: '/',
22 | redirect: '/artwork'
23 | },
24 | {
25 | path: '/artwork',
26 | name: 'artwork',
27 | component: Artwork
28 | },
29 | {
30 | path: '/edit',
31 | name: 'edit',
32 | component: Edit
33 | },
34 | {
35 | path: '/about',
36 | name: 'about',
37 | // route level code-splitting
38 | // this generates a separate chunk (about.[hash].js) for this route
39 | // which is lazy-loaded when the route is visited.
40 | component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
41 | }
42 | ]
43 | })
44 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pixel-paint",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "core-js": "^2.6.5",
12 | "lodash": "^4.17.11",
13 | "moment": "^2.24.0",
14 | "normalize.css": "^8.0.1",
15 | "vue": "^2.6.10",
16 | "vue-router": "^3.0.3",
17 | "vue2-touch-events": "^2.0.0",
18 | "vuex": "^3.0.1"
19 | },
20 | "devDependencies": {
21 | "@vue/cli-plugin-babel": "^3.8.0",
22 | "@vue/cli-plugin-eslint": "^3.8.0",
23 | "@vue/cli-service": "^3.8.0",
24 | "@vue/eslint-config-standard": "^4.0.0",
25 | "babel-eslint": "^10.0.1",
26 | "eslint": "^5.16.0",
27 | "eslint-plugin-vue": "^5.0.0",
28 | "get-pixels": "^3.3.2",
29 | "lodash-webpack-plugin": "^0.11.5",
30 | "postcss-px-to-viewport": "^1.1.0",
31 | "sass": "^1.18.0",
32 | "sass-loader": "^7.1.0",
33 | "sharp": "^0.22.1",
34 | "vue-svg-icon": "^1.2.9",
35 | "vue-template-compiler": "^2.6.10"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Jad
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 |
--------------------------------------------------------------------------------
/src/svg/fill.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/svg/grid.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/js/cache.js:
--------------------------------------------------------------------------------
1 | import { LocalStorage } from './storage'
2 |
3 | const ARTWORK_KEY = '__PIXEL_PAINT_ARTWORK__'
4 |
5 | const insertArray = (arr, val, compare, max) => {
6 | const index = arr.findIndex(compare)
7 |
8 | if (index >= 0) {
9 | arr[index] = Object.assign({}, arr[index], val)
10 | } else {
11 | arr.unshift(val)
12 | }
13 |
14 | if (max && arr.length > max) {
15 | arr.pop()
16 | }
17 | }
18 |
19 | const deleteFromArray = (arr, compare) => {
20 | const index = arr.findIndex(compare)
21 |
22 | if (index > -1) {
23 | arr.splice(index, 1)
24 | }
25 | }
26 |
27 | export const loadArtwork = () => {
28 | return LocalStorage.get(ARTWORK_KEY)
29 | }
30 |
31 | export const saveArtwork = artwork => {
32 | let artworks = LocalStorage.get(ARTWORK_KEY, [])
33 |
34 | insertArray(artworks, artwork, item => {
35 | return artwork.id === item.id
36 | })
37 |
38 | return LocalStorage.set(ARTWORK_KEY, artworks)
39 | }
40 |
41 | export const deleteArtwork = id => {
42 | let artworks = LocalStorage.get(ARTWORK_KEY, [])
43 |
44 | deleteFromArray(artworks, item => {
45 | return item.id === id
46 | })
47 |
48 | return LocalStorage.set(ARTWORK_KEY, artworks)
49 | }
50 |
--------------------------------------------------------------------------------
/src/js/storage.js:
--------------------------------------------------------------------------------
1 | import { JSONC } from './jsonc'
2 |
3 | class Storage {
4 | get (key, def) {
5 | let result = this.drive.getItem(key)
6 | if (result) {
7 | return deserialize(result)
8 | } else {
9 | return def
10 | }
11 | }
12 |
13 | set (key, val) {
14 | if (val === undefined) {
15 | return this.remove(key)
16 | }
17 | this.drive.setItem(key, serialize(val))
18 | return val
19 | }
20 |
21 | has (key) {
22 | return this.get(key) !== undefined
23 | }
24 |
25 | remove (key) {
26 | this.drive.removeItem(key)
27 | }
28 |
29 | clear () {
30 | this.drive.clear()
31 | }
32 | }
33 |
34 | class Local extends Storage {
35 | constructor () {
36 | super()
37 | this.drive = window.localStorage
38 | }
39 | }
40 |
41 | class Session extends Storage {
42 | constructor () {
43 | super()
44 | this.drive = window.sessionStorage
45 | }
46 | }
47 |
48 | export const LocalStorage = new Local()
49 | export const SessionStorage = new Session()
50 |
51 | function serialize (val) {
52 | return JSONC.pack(val)
53 | }
54 |
55 | function deserialize (val) {
56 | if (typeof val !== 'string') {
57 | return undefined
58 | }
59 | try {
60 | return JSONC.unpack(val)
61 | } catch (e) {
62 | return val || undefined
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/components/edit/grid-highlight.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Ï
47 |
48 |
57 |
--------------------------------------------------------------------------------
/src/components/edit/grid.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
51 |
52 |
59 |
--------------------------------------------------------------------------------
/src/store/mutations.js:
--------------------------------------------------------------------------------
1 | export default {
2 | setCanvas (state, canvas) {
3 | state.canvas = canvas
4 | },
5 | setArtworkInfo (state, info) {
6 | state.artwork = info ? Object.assign({}, state.artwork, info) : {}
7 | },
8 | updateThumb (state, thumb) {
9 | state.artwork.thumb = thumb
10 | },
11 | setPushing (state, flag) {
12 | state.isPushing = flag
13 | },
14 | setViewportSize (state, size) {
15 | state.viewportSize = Math.min(Math.max(16, size), state.artwork.size)
16 | },
17 | setGridShow (state, flag) {
18 | state.isGridShow = flag
19 | },
20 | setViewportOffset (state, offset) {
21 | state.viewportOffset = Object.assign({}, state.viewportOffset, offset)
22 | },
23 | setCurrentOffset (state, offset) {
24 | state.currentOffset = Object.assign({}, state.currentOffset, offset)
25 | },
26 | UndoHistoryHandle (state, { action, data }) {
27 | if (typeof state.undoHistory === 'undefined') state.undoHistory = []
28 | switch (action) {
29 | case 'push':
30 | state.undoHistory.push(data)
31 | break
32 | case 'pop':
33 | state.undoHistory.pop()
34 | break
35 | case 'clear':
36 | state.undoHistory = []
37 | }
38 | },
39 | RedoHistoryHandle (state, { action, data }) {
40 | if (typeof state.redoHistory === 'undefined') state.redoHistory = []
41 | switch (action) {
42 | case 'push':
43 | state.redoHistory.push(data)
44 | break
45 | case 'pop':
46 | state.redoHistory.pop()
47 | break
48 | case 'clear':
49 | state.redoHistory = []
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/components/edit/rename.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
34 |
35 |
74 |
--------------------------------------------------------------------------------
/src/svg/buttonDraw.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/work/convert.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const _ = require('lodash')
3 | const argv = require('optimist').argv
4 | const sharp = require('sharp')
5 | const getPixels = require('get-pixels')
6 |
7 | if (!argv.p || !argv.s) return
8 |
9 | const uuid = () => {
10 | let d = Date.now()
11 | if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
12 | d += performance.now()
13 | }
14 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
15 | let r = (d + Math.random() * 16) % 16 | 0
16 | d = Math.floor(d / 16)
17 | return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
18 | })
19 | }
20 |
21 | sharp(argv.p)
22 | .extract({
23 | left: 0,
24 | top: 169,
25 | width: 1080,
26 | height: 1080
27 | })
28 | .resize(argv.s, argv.s, {
29 | kernel: 'nearest'
30 | })
31 | .toBuffer((_err, data, info) => {
32 | console.log(info)
33 | getPixels(data, 'image/png', function (err, pixels) {
34 | if (err) {
35 | console.log(err)
36 | return
37 | }
38 |
39 | let canvasData = []
40 |
41 | for (let y = 0; y < pixels.shape[1]; y++) {
42 | for (let x = 0; x < pixels.shape[0]; x++) {
43 | const r = pixels.get(x, y, 0).toString(16)
44 | const g = pixels.get(x, y, 1).toString(16)
45 | const b = pixels.get(x, y, 2).toString(16)
46 | const rgb = `#${r}${g}${b}`
47 | canvasData.push(rgb)
48 | }
49 | }
50 |
51 | let result = {
52 | id: uuid(),
53 | title: '',
54 | author: '',
55 | size: argv.size,
56 | created: Date.now(),
57 | updated: Date.now(),
58 | canvasData: _.chunk(canvasData, argv.s),
59 | brush: {
60 | title: 'Brush',
61 | colors: [...new Set(canvasData)]
62 | }
63 | }
64 |
65 | // console.log(result)
66 | fs.writeFileSync(`./artwork_${argv.s}.json`, JSON.stringify(result), 'utf-8')
67 | })
68 | })
69 |
--------------------------------------------------------------------------------
/src/components/common/prompt.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{title}}
4 |
5 |
13 |
14 |
15 |
16 |
41 |
42 |
87 |
--------------------------------------------------------------------------------
/src/components/common/confirm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{title}}
4 |
{{content}}
5 |
13 |
14 |
15 |
16 |
32 |
33 |
85 |
--------------------------------------------------------------------------------
/src/components/common/alert/alert.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{options.title}}
4 |
{{options.content}}
5 |
12 |
13 |
14 |
15 |
37 |
38 |
89 |
--------------------------------------------------------------------------------
/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 | For a guide and recipes on how to configure / customize this project,
6 | check out the
7 | vue-cli documentation.
8 |
9 |
Installed CLI Plugins
10 |
14 |
Essential Links
15 |
22 |
Ecosystem
23 |
30 |
31 |
32 |
33 |
41 |
42 |
43 |
59 |
--------------------------------------------------------------------------------
/src/components/edit/push.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
56 |
57 |
100 |
--------------------------------------------------------------------------------
/src/components/edit/brush-list.vue:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
78 |
79 |
107 |
--------------------------------------------------------------------------------
/src/components/edit/touch.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
97 |
98 |
105 |
--------------------------------------------------------------------------------
/src/components/edit/header-bar.vue:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
75 |
76 |
116 |
--------------------------------------------------------------------------------
/src/views/artwork.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
14 |
21 |
27 |
28 |
29 |
30 |
121 |
122 |
128 |
--------------------------------------------------------------------------------
/src/views/edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
20 |
21 |
22 |
23 |
143 |
144 |
150 |
--------------------------------------------------------------------------------
/src/components/artwork/canvas-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
{{artwork.title}}
13 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
97 |
98 |
173 |
--------------------------------------------------------------------------------
/src/components/edit/sidebar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
39 |
40 |
41 |
42 |
148 |
149 |
228 |
--------------------------------------------------------------------------------
/work/pixel-paint.mindnode/style.mindnodestyle/contents.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | allowNodeStrokeColorVariation
6 |
7 | backgroundColor
8 | {0.933333, 0.933333, 0.952941, 1.000000}
9 | baseSubnode
10 |
11 | shapeStyle
12 |
13 | borderStrokeStyle
14 |
15 | color
16 | {1.000000, 0.588235, 0.352941, 1.000000}
17 | dash
18 | 0
19 | width
20 | 6
21 |
22 | fillColor
23 | {1.000000, 1.000000, 1.000000, 1.000000}
24 | shapeType
25 | 0
26 |
27 | strokeStyle
28 |
29 | color
30 | {1.000000, 0.588235, 0.352941, 1.000000}
31 | dash
32 | 0
33 | width
34 | 6
35 |
36 | titleStyle
37 |
38 | alignment
39 | 0
40 | bold
41 |
42 | color
43 | {0.428090, 0.428100, 0.428094, 1.000000}
44 | fontName
45 | Helvetica
46 | fontSize
47 | 20
48 | italic
49 |
50 | strikethrough
51 |
52 | underline
53 |
54 |
55 |
56 | crossConnections
57 |
58 |
59 | arrowStyle
60 |
61 | endArrow
62 | 1
63 | startArrow
64 | 0
65 |
66 | pathStyle
67 |
68 | strokeStyle
69 |
70 | color
71 | {0.366349, 0.366358, 0.366353, 1.000000}
72 | dash
73 | 1
74 | width
75 | 1
76 |
77 |
78 | titleStyle
79 |
80 | alignment
81 | 1
82 | bold
83 |
84 | color
85 | {1.000000, 1.000000, 1.000000, 1.000000}
86 | fontName
87 | HelveticaNeue
88 | fontSize
89 | 14
90 | italic
91 |
92 | strikethrough
93 |
94 | underline
95 |
96 |
97 |
98 |
99 | mainNodes
100 |
101 |
102 | shapeStyle
103 |
104 | borderStrokeStyle
105 |
106 | color
107 | {1.000000, 1.000000, 1.000000, 1.000000}
108 | dash
109 | 0
110 | width
111 | 1
112 |
113 | fillColor
114 | {1.000000, 1.000000, 1.000000, 1.000000}
115 | shapeType
116 | 2
117 |
118 | strokeStyle
119 |
120 | color
121 | {0.294118, 0.294118, 0.294118, 1.000000}
122 | dash
123 | 0
124 | width
125 | 4
126 |
127 | titleStyle
128 |
129 | alignment
130 | 1
131 | bold
132 |
133 | color
134 | {0.292470, 0.292477, 0.292473, 1.000000}
135 | fontName
136 | Helvetica
137 | fontSize
138 | 24
139 | italic
140 |
141 |
142 |
143 |
144 | subnodeColors
145 |
146 |
147 | shapeStyle
148 |
149 | borderStrokeStyle
150 |
151 | color
152 | {1.000000, 0.588235, 0.352941, 1.000000}
153 |
154 | fillColor
155 | {1.000000, 1.000000, 1.000000, 1.000000}
156 |
157 | strokeStyle
158 |
159 | color
160 | {1.000000, 0.588235, 0.352941, 1.000000}
161 |
162 | titleStyle
163 |
164 | color
165 | {0.428090, 0.428100, 0.428094, 1.000000}
166 |
167 |
168 |
169 | shapeStyle
170 |
171 | borderStrokeStyle
172 |
173 | color
174 | {0.450980, 0.784314, 1.000000, 1.000000}
175 |
176 | fillColor
177 | {1.000000, 1.000000, 1.000000, 1.000000}
178 |
179 | strokeStyle
180 |
181 | color
182 | {0.450980, 0.784314, 1.000000, 1.000000}
183 |
184 | titleStyle
185 |
186 | color
187 | {0.428090, 0.428100, 0.428094, 1.000000}
188 |
189 |
190 |
191 | shapeStyle
192 |
193 | borderStrokeStyle
194 |
195 | color
196 | {0.686275, 0.313725, 0.784314, 1.000000}
197 |
198 | fillColor
199 | {1.000000, 1.000000, 1.000000, 1.000000}
200 |
201 | strokeStyle
202 |
203 | color
204 | {0.686275, 0.313725, 0.784314, 1.000000}
205 |
206 | titleStyle
207 |
208 | color
209 | {0.428090, 0.428100, 0.428094, 1.000000}
210 |
211 |
212 |
213 | shapeStyle
214 |
215 | borderStrokeStyle
216 |
217 | color
218 | {1.000000, 0.803922, 0.235294, 1.000000}
219 |
220 | fillColor
221 | {1.000000, 1.000000, 1.000000, 1.000000}
222 |
223 | strokeStyle
224 |
225 | color
226 | {1.000000, 0.803922, 0.235294, 1.000000}
227 |
228 | titleStyle
229 |
230 | color
231 | {0.428090, 0.428100, 0.428094, 1.000000}
232 |
233 |
234 |
235 | shapeStyle
236 |
237 | borderStrokeStyle
238 |
239 | color
240 | {1.000000, 0.372549, 0.411765, 1.000000}
241 |
242 | fillColor
243 | {1.000000, 1.000000, 1.000000, 1.000000}
244 |
245 | strokeStyle
246 |
247 | color
248 | {1.000000, 0.372549, 0.411765, 1.000000}
249 |
250 | titleStyle
251 |
252 | color
253 | {0.428090, 0.428100, 0.428094, 1.000000}
254 |
255 |
256 |
257 | shapeStyle
258 |
259 | borderStrokeStyle
260 |
261 | color
262 | {0.392157, 0.784314, 0.803922, 1.000000}
263 |
264 | fillColor
265 | {1.000000, 1.000000, 1.000000, 1.000000}
266 |
267 | strokeStyle
268 |
269 | color
270 | {0.392157, 0.784314, 0.803922, 1.000000}
271 |
272 | titleStyle
273 |
274 | color
275 | {0.428090, 0.428100, 0.428094, 1.000000}
276 |
277 |
278 |
279 | subnodeLevels
280 |
281 |
282 |
283 |
--------------------------------------------------------------------------------
/src/components/edit/draw.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NO DATA :-(
6 |
7 |
8 | id: {{artwork.id}}
9 |
10 | title: {{artwork.title}}
11 |
12 | size: {{artwork.size}}
13 |
14 | created: {{artwork.created}}
15 |
16 | updated: {{artwork.updated}}
17 |
18 | brush title: {{artwork.brush.title}}
19 |
20 |
21 |
22 |
23 |
29 |
30 |
31 |
32 |
266 |
267 |
288 |
--------------------------------------------------------------------------------
/src/components/artwork/new-canvas.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
17 |
18 |
19 |
Brush
20 |
{{brush.title}}
21 |
22 |
23 |
24 |
25 |
31 |
{{brush.title}}
32 |
33 |
34 |
35 |
36 |
37 |
Size
38 |
39 |
48 |
49 |
50 |
51 |
create canvas
52 |
53 |
54 |
55 |
56 |
249 |
250 |
379 |
--------------------------------------------------------------------------------
/src/js/jsonc.js:
--------------------------------------------------------------------------------
1 | // Copyright © 2013 Pieroxy
2 | // This work is free. You can redistribute it and/or modify it
3 | // under the terms of the WTFPL, Version 2
4 | // For more information see LICENSE.txt or http://www.wtfpl.net/
5 | //
6 | // LZ-based compression algorithm, version 1.0.2-rc1
7 | var LZString = {
8 |
9 | writeBit: function (value, data) {
10 | data.val = (data.val << 1) | value
11 | if (data.position == 15) {
12 | data.position = 0
13 | data.string += String.fromCharCode(data.val)
14 | data.val = 0
15 | } else {
16 | data.position++
17 | }
18 | },
19 |
20 | writeBits: function (numBits, value, data) {
21 | if (typeof (value) === 'string') { value = value.charCodeAt(0) }
22 | for (var i = 0; i < numBits; i++) {
23 | this.writeBit(value & 1, data)
24 | value = value >> 1
25 | }
26 | },
27 |
28 | produceW: function (context) {
29 | if (Object.prototype.hasOwnProperty.call(context.dictionaryToCreate, context.w)) {
30 | if (context.w.charCodeAt(0) < 256) {
31 | this.writeBits(context.numBits, 0, context.data)
32 | this.writeBits(8, context.w, context.data)
33 | } else {
34 | this.writeBits(context.numBits, 1, context.data)
35 | this.writeBits(16, context.w, context.data)
36 | }
37 | this.decrementEnlargeIn(context)
38 | delete context.dictionaryToCreate[context.w]
39 | } else {
40 | this.writeBits(context.numBits, context.dictionary[context.w], context.data)
41 | }
42 | this.decrementEnlargeIn(context)
43 | },
44 |
45 | decrementEnlargeIn: function (context) {
46 | context.enlargeIn--
47 | if (context.enlargeIn == 0) {
48 | context.enlargeIn = Math.pow(2, context.numBits)
49 | context.numBits++
50 | }
51 | },
52 |
53 | compress: function (uncompressed) {
54 | var context = {
55 | dictionary: {},
56 | dictionaryToCreate: {},
57 | c: '',
58 | wc: '',
59 | w: '',
60 | enlargeIn: 2, // Compensate for the first entry which should not count
61 | dictSize: 3,
62 | numBits: 2,
63 | result: '',
64 | data: { string: '', val: 0, position: 0 }
65 | }; var i
66 |
67 | for (i = 0; i < uncompressed.length; i += 1) {
68 | context.c = uncompressed.charAt(i)
69 | if (!Object.prototype.hasOwnProperty.call(context.dictionary, context.c)) {
70 | context.dictionary[context.c] = context.dictSize++
71 | context.dictionaryToCreate[context.c] = true
72 | }
73 |
74 | context.wc = context.w + context.c
75 | if (Object.prototype.hasOwnProperty.call(context.dictionary, context.wc)) {
76 | context.w = context.wc
77 | } else {
78 | this.produceW(context)
79 | // Add wc to the dictionary.
80 | context.dictionary[context.wc] = context.dictSize++
81 | context.w = String(context.c)
82 | }
83 | }
84 |
85 | // Output the code for w.
86 | if (context.w !== '') {
87 | this.produceW(context)
88 | }
89 |
90 | // Mark the end of the stream
91 | this.writeBits(context.numBits, 2, context.data)
92 |
93 | // Flush the last char
94 | while (context.data.val > 0) this.writeBit(0, context.data)
95 | return context.data.string
96 | },
97 |
98 | readBit: function (data) {
99 | var res = data.val & data.position
100 | data.position >>= 1
101 | if (data.position == 0) {
102 | data.position = 32768
103 | data.val = data.string.charCodeAt(data.index++)
104 | }
105 | // data.val = (data.val << 1);
106 | return res > 0 ? 1 : 0
107 | },
108 |
109 | readBits: function (numBits, data) {
110 | var res = 0
111 | var maxpower = Math.pow(2, numBits)
112 | var power = 1
113 | while (power != maxpower) {
114 | res |= this.readBit(data) * power
115 | power <<= 1
116 | }
117 | return res
118 | },
119 |
120 | decompress: function (compressed) {
121 | var dictionary = {}
122 | var next
123 | var enlargeIn = 4
124 | var dictSize = 4
125 | var numBits = 3
126 | var entry = '';
127 | var result = '';
128 | var i
129 | var w
130 | var c
131 | var errorCount = 0
132 | var literal
133 | var data = { string: compressed, val: compressed.charCodeAt(0), position: 32768, index: 1 }
134 |
135 | for (i = 0; i < 3; i += 1) {
136 | dictionary[i] = i
137 | }
138 |
139 | next = this.readBits(2, data)
140 | switch (next) {
141 | case 0:
142 | c = String.fromCharCode(this.readBits(8, data))
143 | break
144 | case 1:
145 | c = String.fromCharCode(this.readBits(16, data))
146 | break
147 | case 2:
148 | return ''
149 | }
150 | dictionary[3] = c
151 | w = result = c
152 | while (true) {
153 | c = this.readBits(numBits, data)
154 |
155 | switch (c) {
156 | case 0:
157 | if (errorCount++ > 10000) return 'Error'
158 | c = String.fromCharCode(this.readBits(8, data))
159 | dictionary[dictSize++] = c
160 | c = dictSize - 1
161 | enlargeIn--
162 | break
163 | case 1:
164 | c = String.fromCharCode(this.readBits(16, data))
165 | dictionary[dictSize++] = c
166 | c = dictSize - 1
167 | enlargeIn--
168 | break
169 | case 2:
170 | return result
171 | }
172 |
173 | if (enlargeIn == 0) {
174 | enlargeIn = Math.pow(2, numBits)
175 | numBits++
176 | }
177 |
178 | if (dictionary[c]) {
179 | entry = dictionary[c]
180 | } else {
181 | if (c === dictSize) {
182 | entry = w + w.charAt(0)
183 | } else {
184 | return null
185 | }
186 | }
187 | result += entry
188 |
189 | // Add w+entry[0] to the dictionary.
190 | dictionary[dictSize++] = w + entry.charAt(0)
191 | enlargeIn--
192 |
193 | w = entry
194 |
195 | if (enlargeIn == 0) {
196 | enlargeIn = Math.pow(2, numBits)
197 | numBits++
198 | }
199 | }
200 | return result
201 | }
202 | }/*global LZString */
203 | export const JSONC = (function () {
204 | var root
205 | var JSONC = {}
206 | var isNodeEnvironment
207 | var _nCode = -1
208 | var toString = {}.toString
209 |
210 | /**
211 | * set the correct root depending from the environment.
212 | * @type {Object}
213 | * @private
214 | */
215 | root = this
216 | /**
217 | * Check if JSONC is loaded in Node.js environment
218 | * @type {Boolean}
219 | * @private
220 | */
221 | isNodeEnvironment = typeof exports === 'object' && typeof module === 'object' && typeof module.exports === 'object' && typeof require === 'function'
222 | /**
223 | * Checks if the value exist in the array.
224 | * @param arr
225 | * @param v
226 | * @returns {boolean}
227 | */
228 | function contains (arr, v) {
229 | var nIndex
230 | var nLen = arr.length
231 | for (nIndex = 0; nIndex < nLen; nIndex++) {
232 | if (arr[nIndex][1] === v) {
233 | return true
234 | }
235 | }
236 | return false
237 | }
238 | /**
239 | * Removes duplicated values in an array
240 | * @param oldArray
241 | * @returns {Array}
242 | */
243 | function unique (oldArray) {
244 | var nIndex
245 | var nLen = oldArray.length
246 | var aArr = []
247 | for (nIndex = 0; nIndex < nLen; nIndex++) {
248 | if (!contains(aArr, oldArray[nIndex][1])) {
249 | aArr.push(oldArray[nIndex])
250 | }
251 | }
252 | return aArr
253 | }
254 | /**
255 | * Escapes a RegExp
256 | * @param text
257 | * @returns {*}
258 | */
259 | function escapeRegExp (text) {
260 | return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
261 | }
262 | /**
263 | * Returns if the obj is an object or not.
264 | * @param obj
265 | * @returns {boolean}
266 | * @private
267 | */
268 | function _isObject (obj) {
269 | return toString.call(obj) === '[object Object]'
270 | }
271 | /**
272 | * Returns if the obj is an array or not
273 | * @param obj
274 | * @returns {boolean}
275 | * @private
276 | */
277 | function _isArray (obj) {
278 | return toString.call(obj) === '[object Array]'
279 | }
280 | /**
281 | * Converts a bidimensional array to object
282 | * @param aArr
283 | * @returns {{}}
284 | * @private
285 | */
286 | function _biDimensionalArrayToObject (aArr) {
287 | var obj = {}
288 | var nIndex
289 | var nLen = aArr.length
290 | var oItem
291 | for (nIndex = 0; nIndex < nLen; nIndex++) {
292 | oItem = aArr[nIndex]
293 | obj[oItem[0]] = oItem[1]
294 | }
295 | return obj
296 | }
297 |
298 | /**
299 | * Convert a number to their ascii code/s.
300 | * @param index
301 | * @param totalChar
302 | * @param offset
303 | * @returns {Array}
304 | * @private
305 | */
306 | function _numberToKey (index, totalChar, offset) {
307 | var aArr = []
308 | var currentChar = index
309 | totalChar = totalChar || 26
310 | offset = offset || 65
311 | while (currentChar >= totalChar) {
312 | aArr.push((currentChar % totalChar) + offset)
313 | currentChar = Math.floor(currentChar / totalChar - 1)
314 | }
315 | aArr.push(currentChar + offset)
316 | return aArr.reverse()
317 | }
318 |
319 | /**
320 | * Returns the string using an array of ASCII values
321 | * @param aKeys
322 | * @returns {string}
323 | * @private
324 | */
325 | function _getSpecialKey (aKeys) {
326 | return String.fromCharCode.apply(String, aKeys)
327 | }
328 |
329 | /**
330 | * Traverse all the objects looking for keys and set an array with the new keys
331 | * @param json
332 | * @param aKeys
333 | * @returns {*}
334 | * @private
335 | */
336 | function _getKeys (json, aKeys) {
337 | var aKey,
338 | sKey,
339 | oItem
340 |
341 | for (sKey in json) {
342 | if (json.hasOwnProperty(sKey)) {
343 | oItem = json[sKey]
344 | if (_isObject(oItem) || _isArray(oItem)) {
345 | aKeys = aKeys.concat(unique(_getKeys(oItem, aKeys)))
346 | }
347 | if (isNaN(Number(sKey))) {
348 | if (!contains(aKeys, sKey)) {
349 | _nCode += 1
350 | aKey = []
351 | aKey.push(_getSpecialKey(_numberToKey(_nCode)), sKey)
352 | aKeys.push(aKey)
353 | }
354 | }
355 | }
356 | }
357 | return aKeys
358 | }
359 |
360 | /**
361 | * Method to compress array objects
362 | * @private
363 | * @param json
364 | * @param aKeys
365 | */
366 | function _compressArray (json, aKeys) {
367 | var nIndex,
368 | nLenKeys
369 |
370 | for (nIndex = 0, nLenKeys = json.length; nIndex < nLenKeys; nIndex++) {
371 | json[nIndex] = JSONC.compress(json[nIndex], aKeys)
372 | }
373 | }
374 |
375 | /**
376 | * Method to compress anything but array
377 | * @private
378 | * @param json
379 | * @param aKeys
380 | * @returns {*}
381 | */
382 | function _compressOther (json, aKeys) {
383 | var oKeys,
384 | aKey,
385 | str,
386 | nLenKeys,
387 | nIndex,
388 | obj
389 | aKeys = _getKeys(json, aKeys)
390 | aKeys = unique(aKeys)
391 | oKeys = _biDimensionalArrayToObject(aKeys)
392 |
393 | str = JSON.stringify(json)
394 | nLenKeys = aKeys.length
395 |
396 | for (nIndex = 0; nIndex < nLenKeys; nIndex++) {
397 | aKey = aKeys[nIndex]
398 | str = str.replace(new RegExp(escapeRegExp('"' + aKey[1] + '"'), 'g'), '"' + aKey[0] + '"')
399 | }
400 | obj = JSON.parse(str)
401 | obj._ = oKeys
402 | return obj
403 | }
404 |
405 | /**
406 | * Method to decompress array objects
407 | * @private
408 | * @param json
409 | */
410 | function _decompressArray (json) {
411 | var nIndex, nLenKeys
412 |
413 | for (nIndex = 0, nLenKeys = json.length; nIndex < nLenKeys; nIndex++) {
414 | json[nIndex] = JSONC.decompress(json[nIndex])
415 | }
416 | }
417 |
418 | /**
419 | * Method to decompress anything but array
420 | * @private
421 | * @param jsonCopy
422 | * @returns {*}
423 | */
424 | function _decompressOther (jsonCopy) {
425 | var oKeys, str, sKey
426 |
427 | oKeys = JSON.parse(JSON.stringify(jsonCopy._))
428 | delete jsonCopy._
429 | str = JSON.stringify(jsonCopy)
430 | for (sKey in oKeys) {
431 | if (oKeys.hasOwnProperty(sKey)) {
432 | str = str.replace(new RegExp('"' + sKey + '"', 'g'), '"' + oKeys[sKey] + '"')
433 | }
434 | }
435 | return str
436 | }
437 |
438 | /**
439 | * Compress a RAW JSON
440 | * @param json
441 | * @param optKeys
442 | * @returns {*}
443 | */
444 | JSONC.compress = function (json, optKeys) {
445 | if (!optKeys) {
446 | _nCode = -1
447 | }
448 | var aKeys = optKeys || []
449 | var obj
450 |
451 | if (_isArray(json)) {
452 | _compressArray(json, aKeys)
453 | obj = json
454 | } else {
455 | obj = _compressOther(json, aKeys)
456 | }
457 | return obj
458 | }
459 | /**
460 | * Use LZString to get the compressed string.
461 | * @param json
462 | * @param bCompress
463 | * @returns {String}
464 | */
465 | JSONC.pack = function (json, bCompress) {
466 | var str = JSON.stringify((bCompress ? JSONC.compress(json) : json))
467 | return LZString.compress(str)
468 | }
469 | /**
470 | * Decompress a compressed JSON
471 | * @param json
472 | * @returns {*}
473 | */
474 | JSONC.decompress = function (json) {
475 | var str
476 | var jsonCopy = JSON.parse(JSON.stringify(json))
477 | if (_isArray(jsonCopy)) {
478 | _decompressArray(jsonCopy)
479 | } else {
480 | str = _decompressOther(jsonCopy)
481 | }
482 | return str ? JSON.parse(str) : jsonCopy
483 | }
484 | /**
485 | * Returns the JSON object from the LZW string
486 | * @param lzw
487 | * @param bDecompress
488 | * @returns {Object}
489 | */
490 | JSONC.unpack = function (lzw, bDecompress) {
491 | var str = LZString.decompress(lzw)
492 | var json = JSON.parse(str)
493 | return bDecompress ? JSONC.decompress(json) : json
494 | }
495 | /*
496 | * Expose Hydra to be used in node.js, as AMD module or as global
497 | */
498 | return JSONC
499 | }.call(this))
500 |
--------------------------------------------------------------------------------