├── .gitignore
├── .npmignore
├── demo
├── src
│ ├── component
│ │ ├── User.vue
│ │ ├── Gallery.vue
│ │ ├── Welcome.vue
│ │ ├── Remove.vue
│ │ ├── App.vue
│ │ └── Setting.vue
│ ├── lib
│ │ ├── img
│ │ │ ├── demo_0.jpg
│ │ │ ├── demo_1.jpg
│ │ │ ├── demo_2.jpg
│ │ │ ├── demo_3.jpg
│ │ │ ├── demo_4.jpg
│ │ │ ├── demo_5.jpg
│ │ │ ├── demo_6.jpg
│ │ │ ├── backtotop.png
│ │ │ └── clipPath.svg
│ │ ├── pxgallery.scss
│ │ └── pxgallery.js
│ ├── reset.scss
│ ├── store.js
│ ├── main.js
│ └── variable.scss
├── .gitignore
├── .babelrc
├── index.html
├── README.md
├── package.json
└── webpack.config.js
├── .travis.yml
├── package.json
├── LICENSE
├── pxgallery.min.css
├── pxgallery.scss
├── readme.md
└── pxgallery.js
/.gitignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo/src/component/User.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /node_modules/
3 | npm-debug.log
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - stable
5 |
--------------------------------------------------------------------------------
/demo/src/lib/img/demo_0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StevenYuysy/PXGallery/HEAD/demo/src/lib/img/demo_0.jpg
--------------------------------------------------------------------------------
/demo/src/lib/img/demo_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StevenYuysy/PXGallery/HEAD/demo/src/lib/img/demo_1.jpg
--------------------------------------------------------------------------------
/demo/src/lib/img/demo_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StevenYuysy/PXGallery/HEAD/demo/src/lib/img/demo_2.jpg
--------------------------------------------------------------------------------
/demo/src/lib/img/demo_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StevenYuysy/PXGallery/HEAD/demo/src/lib/img/demo_3.jpg
--------------------------------------------------------------------------------
/demo/src/lib/img/demo_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StevenYuysy/PXGallery/HEAD/demo/src/lib/img/demo_4.jpg
--------------------------------------------------------------------------------
/demo/src/lib/img/demo_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StevenYuysy/PXGallery/HEAD/demo/src/lib/img/demo_5.jpg
--------------------------------------------------------------------------------
/demo/src/lib/img/demo_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StevenYuysy/PXGallery/HEAD/demo/src/lib/img/demo_6.jpg
--------------------------------------------------------------------------------
/demo/src/lib/img/backtotop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StevenYuysy/PXGallery/HEAD/demo/src/lib/img/backtotop.png
--------------------------------------------------------------------------------
/demo/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-2"],
3 | "plugins": ["transform-runtime"],
4 | "comments": false
5 | }
6 |
--------------------------------------------------------------------------------
/demo/src/component/Gallery.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
14 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | gallery_app
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/src/reset.scss:
--------------------------------------------------------------------------------
1 | // reset css
2 |
3 | body, div, dl, dt, dd, ul, ol, li,
4 | h1, h2, h3, h4, h5, h6, pre, code,
5 | form, fieldset, legend, input, button,
6 | textarea, p, blockquote, th, td {
7 | margin: 0;
8 | padding: 0;
9 | }
10 |
11 | body {
12 | font-family: Helvetica, Tahoma, Arial, STXihei, "华文细黑", "Microsoft YaHei", "微软雅黑", SimSun, "宋体", Heiti, "黑体", sans-serif;
13 | }
--------------------------------------------------------------------------------
/demo/src/lib/img/clipPath.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/demo/README.md:
--------------------------------------------------------------------------------
1 | # gallery_app
2 |
3 | > A Vue.js project
4 |
5 | ## Build Setup
6 |
7 | ``` bash
8 | # install dependencies
9 | npm install
10 |
11 | # serve with hot reload at localhost:8080
12 | npm run dev
13 |
14 | # build for production with minification
15 | npm run build
16 | ```
17 |
18 | For detailed explanation on how things work, consult the [docs for vue-loader](http://vuejs.github.io/vue-loader).
19 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pxgallery",
3 | "version": "1.0.0",
4 | "description": "A easy to use javascript plugin for different image layouts.",
5 | "main": "pxgallery.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/StevenYuysy/PXGallery.git"
9 | },
10 | "keywords": [
11 | "JavaScript",
12 | "Plugin"
13 | ],
14 | "author": "stevenYuysy",
15 | "license": "MIT",
16 | "bugs": {
17 | "url": "https://github.com/StevenYuysy/PXGallery/issues"
18 | },
19 | "homepage": "https://github.com/StevenYuysy/PXGallery#readme"
20 | }
21 |
--------------------------------------------------------------------------------
/demo/src/store.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | var store = {}
4 |
5 | export default store
6 |
7 | store.url = [
8 | "http://placehold.it/1300x1600/E97452/fff",
9 | "http://placehold.it/1300x1300/4C6EB4/fff",
10 | "http://placehold.it/1300x1250/449F93/fff",
11 | "http://placehold.it/800x400/936FBC/fff",
12 | // "http://placehold.it/1000x500/D25064/fff",
13 | "http://placehold.it/1300x1200/CF364A/fff"
14 | ];
15 |
16 | store.options = {
17 | layout : 4,
18 | puzzleHeight: 400,
19 | coulumn : 5,
20 | heightMin : 150,
21 | gutter : 10,
22 | mdSquareSize: 2,
23 | smSquareSize: 4,
24 | fullscreenState : true
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/demo/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import Welcome from './component/Welcome.vue'
4 | import App from './component/App.vue'
5 | import Setting from './component/Setting.vue'
6 | import Remove from './component/Remove.vue'
7 |
8 | Vue.config.debug = true
9 |
10 |
11 | // install router
12 | Vue.use(Router)
13 |
14 | // routing
15 | var router = new Router()
16 |
17 |
18 | router.map({
19 | '/':{
20 | component: Welcome
21 | },
22 | '/setting': {
23 | component: Setting
24 | },
25 | '/remove': {
26 | component: Remove
27 | }
28 | })
29 |
30 |
31 |
32 |
33 | router.start(App, '#app')
--------------------------------------------------------------------------------
/demo/src/variable.scss:
--------------------------------------------------------------------------------
1 | // define color
2 | $black: #111;
3 | $nav_gray: #2f2f38;
4 | $dark_gray: #3a3a3a;
5 | $main_gray: #4a4a4a;
6 | $gray: #929292;
7 | $font_gray: #edecee;
8 | $bg_gray: #f8f8f8;
9 | $light_blue: #7C7EFF;
10 | $blue: #2F33FF;
11 | $gray_blue: #3E3F7F;
12 | $dark_blue: #18197F;
13 | $white: #fff;
14 | $activeColor: $bg_gray;
15 | // mixin
16 | @mixin hover {
17 | -webkit-transition-duration: 0.3s;
18 | transition-duration: 0.3s;
19 | -webkit-transform: translateZ(0);
20 | transform: translateZ(0);
21 | -webkit-transition-property: color, background-color;
22 | transition-property: color, background-color;
23 | &:hover {
24 | color: #111;
25 | background-color: $activeColor;
26 | }
27 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2016 StevenYuysy
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gallery_app",
3 | "description": "A Vue.js project",
4 | "author": "StevenYu ",
5 | "private": true,
6 | "scripts": {
7 | "dev": "webpack-dev-server --inline --hot",
8 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
9 | },
10 | "dependencies": {
11 | "vue": "^1.0.0",
12 | "babel-runtime": "^6.0.0"
13 | },
14 | "devDependencies": {
15 | "babel-core": "^6.0.0",
16 | "babel-loader": "^6.0.0",
17 | "babel-plugin-transform-runtime": "^6.0.0",
18 | "babel-preset-es2015": "^6.0.0",
19 | "babel-preset-stage-2": "^6.0.0",
20 | "cross-env": "^1.0.6",
21 | "css-loader": "^0.23.0",
22 | "file-loader": "^0.8.4",
23 | "json-loader": "^0.5.4",
24 | "node-sass": "^3.7.0",
25 | "sass-loader": "^3.2.0",
26 | "url-loader": "^0.5.7",
27 | "vue-animated-list": "^1.0.2",
28 | "vue-hot-reload-api": "^1.2.0",
29 | "vue-html-loader": "^1.0.0",
30 | "vue-loader": "^8.2.1",
31 | "vue-router": "^0.7.13",
32 | "vue-style-loader": "^1.0.0",
33 | "webpack": "^1.12.2",
34 | "webpack-dev-server": "^1.12.0"
35 | }
36 | }
--------------------------------------------------------------------------------
/demo/src/component/Welcome.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
PXGallery
4 |
Showcase your photos the way they were meant to be seen.
5 |
6 |
7 |
8 |
9 |
10 |
46 |
--------------------------------------------------------------------------------
/demo/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var webpack = require('webpack')
3 |
4 | module.exports = {
5 | entry: './src/main.js',
6 | output: {
7 | path: path.resolve(__dirname, './dist'),
8 | publicPath: '/dist/',
9 | filename: 'build.js'
10 | },
11 | resolveLoader: {
12 | root: path.join(__dirname, 'node_modules'),
13 | },
14 | module: {
15 | loaders: [
16 | {
17 | test: /\.vue$/,
18 | loader: 'vue'
19 | },
20 | {
21 | test: /\.js$/,
22 | loader: 'babel',
23 | exclude: /node_modules/
24 | },
25 | {
26 | test: /\.json$/,
27 | loader: 'json'
28 | },
29 | {
30 | test: /\.html$/,
31 | loader: 'vue-html'
32 | },
33 | {
34 | test: /\.(png|jpg|gif|svg)$/,
35 | loader: 'url',
36 | query: {
37 | limit: 10000,
38 | name: '[name].[ext]'
39 | }
40 | }
41 | ]
42 | },
43 | devServer: {
44 | historyApiFallback: true,
45 | noInfo: true
46 | },
47 | devtool: '#eval-source-map'
48 | }
49 |
50 | if (process.env.NODE_ENV === 'production') {
51 | module.exports.devtool = '#source-map'
52 | // http://vuejs.github.io/vue-loader/workflow/production.html
53 | module.exports.plugins = (module.exports.plugins || []).concat([
54 | new webpack.DefinePlugin({
55 | 'process.env': {
56 | NODE_ENV: '"production"'
57 | }
58 | }),
59 | new webpack.optimize.UglifyJsPlugin({
60 | compress: {
61 | warnings: false
62 | }
63 | }),
64 | new webpack.optimize.OccurenceOrderPlugin()
65 | ])
66 | }
67 |
--------------------------------------------------------------------------------
/demo/src/component/Remove.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
![]()
6 |
7 |
8 |
No photo
9 |
10 |
11 |
12 |
46 |
47 |
--------------------------------------------------------------------------------
/demo/src/component/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
44 |
45 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/pxgallery.min.css:
--------------------------------------------------------------------------------
1 | .pxgalleryContainer{width:80%;overflow:hidden;margin:0 auto;position:relative}.pxgalleryContainer .pxgalleryBox{position:relative;box-sizing:border-box}.puzzle-1 .pxgalleryBox{width:100%;height:100%;overflow:hidden}.puzzle-2 .pxgalleryBox:nth-child(1){position:absolute;left:0;width:66.6%;height:100%;-webkit-clip-path:polygon(0 0,100% 0,50% 100%,0 100%)}.puzzle-2 .pxgalleryBox:nth-child(2){position:absolute;right:0;width:66.6%;height:100%;left:33.333%;-webkit-clip-path:polygon(50% 0,100% 0,100% 100%,0 100%)}.puzzle-3 .pxgalleryBox:nth-child(1){float:left;width:66.6%;height:100%}.puzzle-3 .pxgalleryBox:nth-child(2),.puzzle-3 .pxgalleryBox:nth-child(3){float:left;width:33.4%;height:50%}.puzzle-4 .pxgalleryBox{float:left;width:50%;height:50%}.puzzle-5 .pxgalleryBox{position:absolute}.puzzle-5 .pxgalleryBox:nth-child(1){top:0;left:0;width:66.6%;height:66.6%}.puzzle-5 .pxgalleryBox:nth-child(2){top:0;right:0;width:33.4%;height:66.6%}.puzzle-5 .pxgalleryBox:nth-child(3){bottom:0;right:0;width:33.3%;height:33.4%}.puzzle-5 .pxgalleryBox:nth-child(4){bottom:0;left:33.333%;width:33.333%;height:33.4%}.puzzle-5 .pxgalleryBox:nth-child(5){bottom:0;left:0;width:33.333%;height:33.4%}.puzzle-6 .pxgalleryBox{float:left;width:33.3%;height:33.3%}.puzzle-6 .pxgalleryBox:nth-child(1){width:66.6%;height:66.6%}.puzzle-6 .pxgalleryBox:nth-child(2),.puzzle-6 .pxgalleryBox:nth-child(3),.puzzle-6 .pxgalleryBox:nth-child(4){float:right;width:33.4%}.puzzle-1 img,.puzzle-2 img,.puzzle-3 img,.puzzle-4 img,.puzzle-5 img,.puzzle-6 img{height:100%;width:100%;object-fit:cover;object-position:center}.waterfallColumn{float:left}.waterfallColumn img{width:100%}.barrel{white-space:nowrap}.barrel .pxgalleryBox{display:inline-block}.barrel .pxgalleryBox img{height:100%}@media only screen and (min-width:769px){.square .col-md-1{width:8.33333%;float:left;overflow:hidden}}@media only screen and (max-width:768px){.square .col-sm-1{width:8.33333%;float:left;overflow:hidden}}@media only screen and (min-width:769px){.square .col-md-2{width:16.66667%;float:left;overflow:hidden}}@media only screen and (max-width:768px){.square .col-sm-2{width:16.66667%;float:left;overflow:hidden}}@media only screen and (min-width:769px){.square .col-md-3{width:25%;float:left;overflow:hidden}}@media only screen and (max-width:768px){.square .col-sm-3{width:25%;float:left;overflow:hidden}}@media only screen and (min-width:769px){.square .col-md-4{width:33.33333%;float:left;overflow:hidden}}@media only screen and (max-width:768px){.square .col-sm-4{width:33.33333%;float:left;overflow:hidden}}@media only screen and (min-width:769px){.square .col-md-5{width:41.66667%;float:left;overflow:hidden}}@media only screen and (max-width:768px){.square .col-sm-5{width:41.66667%;float:left;overflow:hidden}}@media only screen and (min-width:769px){.square .col-md-6{width:50%;float:left;overflow:hidden}}@media only screen and (max-width:768px){.square .col-sm-6{width:50%;float:left;overflow:hidden}}@media only screen and (min-width:769px){.square .col-md-7{width:58.33333%;float:left;overflow:hidden}}@media only screen and (max-width:768px){.square .col-sm-7{width:58.33333%;float:left;overflow:hidden}}@media only screen and (min-width:769px){.square .col-md-8{width:66.66667%;float:left;overflow:hidden}}@media only screen and (max-width:768px){.square .col-sm-8{width:66.66667%;float:left;overflow:hidden}}@media only screen and (min-width:769px){.square .col-md-9{width:75%;float:left;overflow:hidden}}@media only screen and (max-width:768px){.square .col-sm-9{width:75%;float:left;overflow:hidden}}@media only screen and (min-width:769px){.square .col-md-10{width:83.33333%;float:left;overflow:hidden}}@media only screen and (max-width:768px){.square .col-sm-10{width:83.33333%;float:left;overflow:hidden}}@media only screen and (min-width:769px){.square .col-md-11{width:91.66667%;float:left;overflow:hidden}}@media only screen and (max-width:768px){.square .col-sm-11{width:91.66667%;float:left;overflow:hidden}}@media only screen and (min-width:769px){.square .col-md-12{width:100%;float:left;overflow:hidden}}@media only screen and (max-width:768px){.square .col-sm-12{width:100%;float:left;overflow:hidden}}.square .pxgalleryBox:after{content:"";display:block;padding-bottom:100%}.square .pxgalleryBox img{position:absolute;width:100%;height:100%;object-fit:cover}.pxfullscreen{position:fixed;z-index:1;top:0;width:100%;height:100%;background-color:rgba(0,0,0,.8);display:flex;flex-direction:row;justify-content:center;align-items:center}.pxfullscreen img{max-height:100%;max-width:100%}.pxfullscreen .pxnext{display:block;position:absolute;top:50%;right:30px;border-top:30px solid transparent;border-bottom:30px solid transparent;border-left:30px solid #d3d3d3;transition:.5s ease-in-out}.pxfullscreen .pxnext:hover{border-left-color:#fff}.pxfullscreen .pxprev{display:block;position:absolute;top:50%;left:30px;border-top:30px solid transparent;border-bottom:30px solid transparent;border-right:30px solid #d3d3d3;transition:.5s ease-in-out}.pxfullscreen .pxprev:hover{border-right-color:#fff}.hidden{display:none}
--------------------------------------------------------------------------------
/pxgallery.scss:
--------------------------------------------------------------------------------
1 | .pxgalleryContainer {
2 | // Your custome style
3 | width: 80%;
4 | overflow: hidden;
5 | margin: 0 auto;
6 | position: relative;
7 |
8 | .pxgalleryBox {
9 | position: relative;
10 | box-sizing: border-box;
11 | }
12 | }
13 |
14 |
15 | // PUZZLE style
16 | // One image box selected
17 | .puzzle-1 {
18 | .pxgalleryBox {
19 | width: 100%;
20 | height: 100%;
21 | overflow: hidden;
22 | }
23 | }
24 | // Two image boxes selected
25 | .puzzle-2 {
26 | .pxgalleryBox:nth-child(1) {
27 | position: absolute;
28 | left: 0;
29 | width: 66.6%;
30 | height: 100%;
31 | // clip-path: url('img/clipPath.svg#clip1');
32 | -webkit-clip-path: polygon(0% 0%,100% 0%,50% 100%,0% 100%);
33 | }
34 | .pxgalleryBox:nth-child(2) {
35 | position: absolute;
36 | right: 0;
37 | width: 66.6%;
38 | height: 100%;
39 | left: 33.333%;
40 | // clip-path: url('img/clipPath.svg#clip2');
41 | -webkit-clip-path: polygon(50% 0%,100% 0%,100% 100%,0% 100%);
42 | }
43 | }
44 | //THree image boxes selected
45 | .puzzle-3 {
46 | .pxgalleryBox:nth-child(1) {
47 | float: left;
48 | width: 66.6%;
49 | height: 100%;
50 | }
51 | .pxgalleryBox:nth-child(2) {
52 | float: left;
53 | width: 33.4%;
54 | height: 50%;
55 | }
56 | .pxgalleryBox:nth-child(3) {
57 | float: left;
58 | width: 33.4%;
59 | height: 50%;
60 | }
61 | }
62 | //Four image boxes selected
63 | .puzzle-4 {
64 | .pxgalleryBox {
65 | float: left;
66 | width: 50%;
67 | height: 50%;
68 | }
69 | }
70 | //Five image boxes selected
71 | .puzzle-5 {
72 | .pxgalleryBox {
73 | position: absolute;
74 | }
75 | .pxgalleryBox:nth-child(1) {
76 | top: 0;
77 | left: 0;
78 | width: 66.6%;
79 | height: 66.6%;
80 | }
81 | .pxgalleryBox:nth-child(2) {
82 | top: 0;
83 | right: 0;
84 | width: 33.4%;
85 | height: 66.6%;
86 | }
87 | .pxgalleryBox:nth-child(3) {
88 | bottom: 0;
89 | right: 0;
90 | width: 33.3%;
91 | height: 33.4%;
92 | }
93 | .pxgalleryBox:nth-child(4) {
94 | bottom: 0;
95 | left: 33.333%;
96 | width: 33.333%;
97 | height: 33.4%;
98 | }
99 | .pxgalleryBox:nth-child(5) {
100 | bottom: 0;
101 | left: 0;
102 | width: 33.333%;
103 | height: 33.4%;
104 | }
105 | }
106 | //Six image boxes selected
107 | .puzzle-6 {
108 | .pxgalleryBox {
109 | float: left;
110 | width: 33.3%;
111 | height: 33.3%;
112 | }
113 | .pxgalleryBox:nth-child(1) {
114 | width: 66.6%;
115 | height: 66.6%;
116 | }
117 | .pxgalleryBox:nth-child(2),
118 | .pxgalleryBox:nth-child(3),
119 | .pxgalleryBox:nth-child(4) {
120 | float: right;
121 | width: 33.4%;
122 | }
123 | }
124 | @for $i from 1 through 6 {
125 | .puzzle-#{$i} {
126 | img {
127 | height: 100%;
128 | width: 100%;
129 | object-fit: cover;
130 | object-position: center;
131 | }
132 | }
133 | }
134 |
135 | //WATERFALL style
136 | .waterfallColumn {
137 | float: left;
138 |
139 | img {
140 | width: 100%;
141 | }
142 | }
143 |
144 | //BARREL style
145 | .barrel {
146 | white-space: nowrap;
147 |
148 | .pxgalleryBox {
149 | display: inline-block;
150 |
151 | img {
152 | height: 100%;
153 | }
154 | }
155 | }
156 |
157 | // SQUARE style
158 | .square {
159 |
160 | @for $i from 1 through 12 {
161 | .col-md-#{$i} { @media only screen and (min-width: 769px) {
162 | width: percentage(( $i / 12 ));
163 | float: left;
164 | overflow: hidden;
165 | }}
166 |
167 | .col-sm-#{$i} { @media only screen and (max-width: 768px) {
168 | width: percentage(( $i / 12 ));
169 | float: left;
170 | overflow: hidden;
171 | }}
172 | }
173 | .pxgalleryBox {
174 |
175 | &:after {
176 | content: "";
177 | display: block;
178 | padding-bottom: 100%;
179 | }
180 |
181 | img {
182 | position: absolute;
183 | width: 100%;
184 | height: 100%;
185 | object-fit: cover;
186 | }
187 | }
188 | }
189 |
190 | //FULLSCREEN style
191 | .pxfullscreen {
192 | position: fixed;
193 | z-index: 100;
194 | top: 0;
195 | width: 100%;
196 | height: 100%;
197 | background-color: rgba(0, 0, 0, .8);
198 | display: flex;
199 | flex-direction: row;
200 | justify-content: center;
201 | align-items: center;
202 |
203 | img {
204 | max-height: 100%;
205 | max-width: 100%;
206 | }
207 |
208 | .pxnext {
209 | display: block;
210 | position: absolute;
211 | top: 50%;
212 | right: 30px;
213 | border-top: 30px solid transparent;
214 | border-bottom: 30px solid transparent;
215 | border-left: 30px solid lightgray;
216 | transition: .5s ease-in-out;
217 |
218 | &:hover {
219 | border-left-color: white;
220 | }
221 | }
222 |
223 | .pxprev{
224 | display: block;
225 | position: absolute;
226 | top: 50%;
227 | left: 30px;
228 | border-top: 30px solid transparent;
229 | border-bottom: 30px solid transparent;
230 | border-right:30px solid lightgray;
231 |
232 | transition: .5s ease-in-out;
233 |
234 | &:hover {
235 | border-right-color: white;
236 | }
237 | }
238 | }
239 |
240 | .hidden {
241 | display: none;
242 | }
243 |
244 |
--------------------------------------------------------------------------------
/demo/src/lib/pxgallery.scss:
--------------------------------------------------------------------------------
1 | .pxgalleryContainer {
2 | // Your custome style
3 | width: 80%;
4 | overflow: hidden;
5 | margin: 0 auto;
6 | position: relative;
7 |
8 | .pxgalleryBox {
9 | position: relative;
10 | box-sizing: border-box;
11 | }
12 | }
13 |
14 |
15 | // PUZZLE style
16 | // One image box selected
17 | .puzzle-1 {
18 | .pxgalleryBox {
19 | width: 100%;
20 | height: 100%;
21 | overflow: hidden;
22 | }
23 | }
24 | // Two image boxes selected
25 | .puzzle-2 {
26 | .pxgalleryBox:nth-child(1) {
27 | position: absolute;
28 | left: 0;
29 | width: 66.6%;
30 | height: 100%;
31 | // clip-path: url('img/clipPath.svg#clip1');
32 | -webkit-clip-path: polygon(0% 0%,100% 0%,50% 100%,0% 100%);
33 | }
34 | .pxgalleryBox:nth-child(2) {
35 | position: absolute;
36 | right: 0;
37 | width: 66.6%;
38 | height: 100%;
39 | left: 33.333%;
40 | // clip-path: url('img/clipPath.svg#clip2');
41 | -webkit-clip-path: polygon(50% 0%,100% 0%,100% 100%,0% 100%);
42 | }
43 | }
44 | //THree image boxes selected
45 | .puzzle-3 {
46 | .pxgalleryBox:nth-child(1) {
47 | float: left;
48 | width: 66.6%;
49 | height: 100%;
50 | }
51 | .pxgalleryBox:nth-child(2) {
52 | float: left;
53 | width: 33.4%;
54 | height: 50%;
55 | }
56 | .pxgalleryBox:nth-child(3) {
57 | float: left;
58 | width: 33.4%;
59 | height: 50%;
60 | }
61 | }
62 | //Four image boxes selected
63 | .puzzle-4 {
64 | .pxgalleryBox {
65 | float: left;
66 | width: 50%;
67 | height: 50%;
68 | }
69 | }
70 | //Five image boxes selected
71 | .puzzle-5 {
72 | .pxgalleryBox {
73 | position: absolute;
74 | }
75 | .pxgalleryBox:nth-child(1) {
76 | top: 0;
77 | left: 0;
78 | width: 66.6%;
79 | height: 66.6%;
80 | }
81 | .pxgalleryBox:nth-child(2) {
82 | top: 0;
83 | right: 0;
84 | width: 33.4%;
85 | height: 66.6%;
86 | }
87 | .pxgalleryBox:nth-child(3) {
88 | bottom: 0;
89 | right: 0;
90 | width: 33.3%;
91 | height: 33.4%;
92 | }
93 | .pxgalleryBox:nth-child(4) {
94 | bottom: 0;
95 | left: 33.333%;
96 | width: 33.333%;
97 | height: 33.4%;
98 | }
99 | .pxgalleryBox:nth-child(5) {
100 | bottom: 0;
101 | left: 0;
102 | width: 33.333%;
103 | height: 33.4%;
104 | }
105 | }
106 | //Six image boxes selected
107 | .puzzle-6 {
108 | .pxgalleryBox {
109 | float: left;
110 | width: 33.3%;
111 | height: 33.3%;
112 | }
113 | .pxgalleryBox:nth-child(1) {
114 | width: 66.6%;
115 | height: 66.6%;
116 | }
117 | .pxgalleryBox:nth-child(2),
118 | .pxgalleryBox:nth-child(3),
119 | .pxgalleryBox:nth-child(4) {
120 | float: right;
121 | width: 33.4%;
122 | }
123 | }
124 | @for $i from 1 through 6 {
125 | .puzzle-#{$i} {
126 | img {
127 | height: 100%;
128 | width: 100%;
129 | object-fit: cover;
130 | object-position: center;
131 | }
132 | }
133 | }
134 |
135 | //WATERFALL style
136 | .waterfallColumn {
137 | float: left;
138 |
139 | img {
140 | width: 100%;
141 | }
142 | }
143 |
144 | //BARREL style
145 | .barrel {
146 | white-space: nowrap;
147 |
148 | .pxgalleryBox {
149 | display: inline-block;
150 |
151 | img {
152 | height: 100%;
153 | }
154 | }
155 | }
156 |
157 | // SQUARE style
158 | .square {
159 |
160 | @for $i from 1 through 12 {
161 | .col-md-#{$i} { @media only screen and (min-width: 769px) {
162 | width: percentage(( $i / 12 ));
163 | float: left;
164 | overflow: hidden;
165 | }}
166 |
167 | .col-sm-#{$i} { @media only screen and (max-width: 768px) {
168 | width: percentage(( $i / 12 ));
169 | float: left;
170 | overflow: hidden;
171 | }}
172 | }
173 | .pxgalleryBox {
174 |
175 | &:after {
176 | content: "";
177 | display: block;
178 | padding-bottom: 100%;
179 | }
180 |
181 | img {
182 | position: absolute;
183 | width: 100%;
184 | height: 100%;
185 | object-fit: cover;
186 | }
187 | }
188 | }
189 |
190 | //FULLSCREEN style
191 | .pxfullscreen {
192 | position: fixed;
193 | z-index: 100;
194 | top: 0;
195 | width: 100%;
196 | height: 100%;
197 | background-color: rgba(0, 0, 0, .8);
198 | display: flex;
199 | flex-direction: row;
200 | justify-content: center;
201 | align-items: center;
202 |
203 | img {
204 | max-height: 100%;
205 | max-width: 100%;
206 | }
207 |
208 | .pxnext {
209 | display: block;
210 | position: absolute;
211 | top: 50%;
212 | right: 30px;
213 | border-top: 30px solid transparent;
214 | border-bottom: 30px solid transparent;
215 | border-left: 30px solid lightgray;
216 | transition: .5s ease-in-out;
217 |
218 | &:hover {
219 | border-left-color: white;
220 | }
221 | }
222 |
223 | .pxprev{
224 | display: block;
225 | position: absolute;
226 | top: 50%;
227 | left: 30px;
228 | border-top: 30px solid transparent;
229 | border-bottom: 30px solid transparent;
230 | border-right:30px solid lightgray;
231 |
232 | transition: .5s ease-in-out;
233 |
234 | &:hover {
235 | border-right-color: white;
236 | }
237 | }
238 | }
239 |
240 | .hidden {
241 | display: none;
242 | }
243 |
244 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Description
2 |
3 | 
4 |
5 | PXGallery is a library which can set different layouts in pure javascript without any dependencies.
6 |
7 | # Demo
8 |
9 | [Demo](http://stevenyuysy.github.io/PXGallery/#!/setting)
10 |
11 | # Setup
12 |
13 | ## Easy setup
14 | Commonly, you can just install it with a css and javascript:
15 |
16 | ```html
17 |
18 | ```
19 |
20 | Include the Gallery script at the bottom of the body of your webpage:
21 |
22 | ```html
23 |
187 |
188 |
270 |
271 |
272 |
--------------------------------------------------------------------------------
/pxgallery.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * pxgallery v0.0.2
4 | * use with pxgallery.css
5 | * @author StevenYu
6 | */
7 |
8 | ;(function (root, factory) {
9 |
10 | if (typeof define === 'function' && define.amd) {
11 | define([], factory);
12 | } else if (typeof module === 'object' && module.exports) {
13 | module.exports = factory();
14 | } else {
15 | // Browser globals (root is window)
16 | root.pxgallery = factory();
17 | }
18 |
19 | }(this, function() {
20 |
21 | 'use strict';
22 |
23 | /**
24 | * @param {Object} opts - options used in plugin
25 | * @constructor
26 | */
27 |
28 | var pxgallery = function(opts) {
29 |
30 | opts = opts || {};
31 | var fullscreenSelector = opts.fullscreenSelector || '.pxfullscreen';
32 |
33 | this.containerSelector = opts.containerSelector || '.pxgalleryContainer';
34 | this.boxSelector = opts.boxSelector || '.pxgalleryBox';
35 | this.container = document.querySelector(this.containerSelector);
36 | this.fullscreen = document.querySelector(fullscreenSelector);
37 |
38 | this.layout = {
39 | NONE: 0, // no layout
40 | PUZZLE: 1, // puzzle layout
41 | WATERFALL: 2, // waterfall layout
42 | BARREL: 3, // barrel layout
43 | SQUARE: 4 // square layout
44 | };
45 |
46 | };
47 |
48 | /**
49 | * @private
50 | */
51 |
52 | var _options = {
53 | layout : '',
54 | puzzleHeight:'',
55 | coulumn : '',
56 | heightMin : '',
57 | gutter : '',
58 | mdSquareSize:'',
59 | smSquareSize:'',
60 | fullscreenState : '',
61 | images: []
62 | };
63 |
64 | // create a fullscreen for images with next and prev
65 | function _createFullscreen(event) {
66 |
67 | if (event.target.getAttribute('src').trim()) {
68 | var fullscreen = document.createElement('div');
69 | var img = document.createElement('img');
70 | var next = document.createElement('span');
71 | var prev = document.createElement('span');
72 | var currentImg = event.target.getAttribute('src');
73 | var currentImgIndex = _options.images.indexOf(currentImg);
74 | fullscreen.className = 'pxfullscreen';
75 | next.className = 'pxnext';
76 | prev.className = 'pxprev';
77 | img.src = currentImg;
78 | fullscreen.addEventListener('click', function(event) {
79 | if (event.target != next && event.target != prev) {
80 | this.remove();
81 | }
82 | }, false);
83 | next.addEventListener('click', function() {
84 | currentImgIndex++;
85 | if (currentImgIndex >= _options.images.length) currentImgIndex = 0;
86 | img.src = _options.images[currentImgIndex];
87 | }, false);
88 | prev.addEventListener('click', function() {
89 | currentImgIndex--;
90 | if (currentImgIndex <= 0) currentImgIndex = (_options.images.length - 1);
91 | img.src = _options.images[currentImgIndex];
92 | })
93 |
94 | fullscreen.appendChild(prev);
95 | fullscreen.appendChild(next);
96 | fullscreen.appendChild(img);
97 | this.parentNode.appendChild(fullscreen);
98 | }
99 | };
100 |
101 | // add the box into column or row
102 | function _addBox(ele, index) {
103 |
104 | switch (_options.layout) {
105 | case 2:
106 | this.columns ? this.columns[index].appendChild(ele) : this.container.appendChild(ele);
107 | break;
108 | case 3:
109 | this.rows ? this.rows[index].appendChild(ele) : this.container.appendChild(ele);
110 | break;
111 | default:
112 | this.container.appendChild(ele);
113 | this.setLayout(_options.layout);
114 | }
115 | };
116 |
117 |
118 | /**
119 | * init the album
120 | * It will replace the photos
121 | * @param {(Stirng | String[])} image - the URL of the photo or the URL array of the photos
122 | * @param {Object} opts - layout options
123 | */
124 |
125 | pxgallery.prototype.setImage = function(image, opts) {
126 |
127 | if (typeof image === 'string') {
128 | this.setImage([image]);
129 | return;
130 | }
131 |
132 | _options.layout = opts.layout || 2;
133 | _options.puzzleHeight = opts.puzzleHeight || 400;
134 | _options.fullscreenState = opts.fullscreenState || true;
135 | _options.column = opts.column || 5;
136 | _options.heightMin = opts.heightMin || 150;
137 | _options.mdSquareSize = opts.mdSquareSize || 3;
138 | _options.smSquareSize = opts.smSquareSize || 6;
139 | _options.gutter = opts.gutter || 10;
140 | var _this = this;
141 |
142 | this.addImage(image, true);
143 | this.setLayout(_options.layout);
144 | _options.fullscreenState ? this.enableFullscreen() : this.disableFullscreen();
145 |
146 | window.onload = function() {
147 | _this.setLayout(_options.layout);
148 | }
149 |
150 | window.onresize = function() {
151 | _this.setLayout(_options.layout);
152 | }
153 | };
154 |
155 | /**
156 | * get the DOM elements which contain the images
157 | * @return {HTMLelement[]} boxes
158 | */
159 |
160 | pxgallery.prototype.getImageDomElements = function() {
161 |
162 | var boxes = Array.prototype.slice.call(this.container.querySelectorAll(this.boxSelector));
163 | var url = [];
164 | boxes.forEach(function(ele) {
165 | ele.ratio = ele.clientWidth / ele.clientHeight;
166 | url.push(ele.querySelector('img').src);
167 | }, this);
168 | _options.images = url;
169 | return boxes;
170 | };
171 |
172 | /**
173 | * add images to the container
174 | * @param {(String | String[])} image - the URL of the photo or the URL array of the photos
175 | * @param {Boolean} raw - weather add the images to the container directly or not
176 | */
177 |
178 | pxgallery.prototype.addImage = function(image, raw) {
179 |
180 | if (typeof image === 'string') {
181 | this.addImage([image]);
182 | return;
183 | }
184 | if (!raw) {
185 | if (_options.layout === 2) var index = this.getWaterfallHeightMin();
186 | if (_options.layout === 3) var index = (this.rows.length - 1);
187 | }
188 |
189 | for (var i = 0; i < image.length; i++) {
190 | var div = document.createElement('div');
191 | var img = new Image();
192 | div.className = 'pxgalleryBox';
193 | div.style.border = _options.gutter / 2 + 'px solid transparent';
194 | img.src = image[i];
195 | _options.images.push(image[i]);
196 | div.appendChild(img);
197 | if (!raw) {
198 | (_options.layout === 2 || _options.layout === 3 ) ? _addBox.call(this, div, index) : _addBox.apply(this, [div]);
199 | }
200 | else {
201 | _addBox.apply(this, [div])
202 | }
203 | }
204 | };
205 |
206 | /**
207 | * remove the images
208 | * @param {(HTMLelement|HTMLelement[])} image - the images that need to be removed
209 | */
210 |
211 | pxgallery.prototype.removeImage = function(image) {
212 |
213 | image.forEach(function(ele) {
214 | var removeUrl = ele.querySelector('img').src;
215 | _options.images = _options.images.filter(function (url) {
216 | return url != removeUrl;
217 | })
218 | ele.remove();
219 | }, this)
220 |
221 | };
222 |
223 | /**
224 | * set the layout
225 | * @param {Number} - layoutValue
226 | */
227 |
228 | pxgallery.prototype.setLayout = function(layoutValue) {
229 |
230 | var boxes = this.getImageDomElements();
231 | this.clearLayout();
232 | _options.layout = layoutValue;
233 |
234 | switch (layoutValue) {
235 |
236 | case 0:
237 | break;
238 |
239 | case 1:
240 | if (boxes.length > 6) {
241 | console.error('PUZZLE layout only can contain 6 photos');
242 | break;
243 | }
244 | this.container.style.height = _options.puzzleHeight + 'px';
245 | this.container.className = this.containerSelector.slice(1) + ' puzzle-' + boxes.length;
246 | this.setPuzzleSquare(boxes.length);
247 | break;
248 |
249 | case 2:
250 | this.container.className = this.containerSelector.slice(1) + ' waterfall';
251 | this.initWaterfallColumn(_options.column);
252 | for (var i = 0; i < boxes.length; i++) {
253 | _addBox.call(this, boxes[i], this.getWaterfallHeightMin());
254 | }
255 | break;
256 |
257 | case 3:
258 | this.container.className = this.containerSelector.slice(1) + ' barrel';
259 | var rows = this.setBarrelBin();
260 | this.initBarrelBin(rows);
261 | var index = 0;
262 | for (var i = 0; i < boxes.length; i++) {
263 | if (i > rows[index].number) index ++;
264 | boxes[i].style.height = '100%';
265 | boxes[i].style.width = '';
266 | _addBox.call(this, boxes[i], index);
267 | }
268 | break;
269 |
270 | case 4:
271 | this.container.className = this.containerSelector.slice(1) + ' square';
272 | for (var i = 0; i < boxes.length; i++) {
273 | var md = 'col-md-' + _options.mdSquareSize;
274 | var sm = 'col-sm-' + _options.smSquareSize;
275 | boxes[i].className = this.boxSelector.slice(1) + ' ' + md + ' ' + sm;
276 | }
277 | }
278 | };
279 |
280 | /**
281 | * get current layout
282 | * @return {Number} -_options.layout
283 | */
284 |
285 | pxgallery.prototype.getLayout = function() {
286 |
287 | return _options.layout;
288 | };
289 |
290 | pxgallery.prototype.clearLayout = function() {
291 |
292 | var boxes = this.getImageDomElements();
293 | var _this = this;
294 | this.container.className = this.containerSelector.slice(1);
295 | this.container.style.height = '';
296 | boxes.forEach(function(ele) {
297 | ele.style.width = '';
298 | ele.style.height = '';
299 | }, this)
300 |
301 | if (this.columns) {
302 | this.columns.forEach(function(ele) {
303 | ele.remove();
304 | }, this)
305 | boxes.forEach(function(ele) {
306 | _this.container.appendChild(ele);
307 | }, this)
308 | }
309 |
310 | if (this.rows) {
311 | this.rows.forEach(function(ele) {
312 | ele.remove();
313 | }, this)
314 | boxes.forEach(function(ele) {
315 | _this.container.appendChild(ele);
316 | }, this)
317 | }
318 | _options.layout = 0;
319 | };
320 |
321 | /**
322 | * NOT RECOMMAND, it may effect the perfomance of the browser cause it change the DOM directly
323 | * set the gutter between images
324 | * @param {Number} gutter
325 | */
326 |
327 | pxgallery.prototype.setGutter = function(gutter) {
328 |
329 | _options.gutter = gutter;
330 | var boxes = this.getImageDomElements()
331 | boxes.forEach(function(ele) {
332 | ele.style.border = (gutter / 2) +'px solid transparent';
333 | }, this)
334 | };
335 |
336 | /**
337 | * enable fullscreen
338 | */
339 |
340 | pxgallery.prototype.enableFullscreen = function() {
341 |
342 | _options.fullscreenState = true;
343 | this.container.addEventListener('click', _createFullscreen, false);
344 | };
345 |
346 | /**
347 | * disable fullscreen
348 | */
349 |
350 | pxgallery.prototype.disableFullscreen = function() {
351 |
352 | _options.fullscreenState = false;
353 | this.container.removeEventListener('click', _createFullscreen, false);
354 | };
355 |
356 | /**
357 | * @return {Boolean} weather eenable fullscreen view
358 | */
359 |
360 | pxgallery.prototype.isFullscreenEnabled = function() {
361 |
362 | return _options.fullscreenState;
363 | };
364 |
365 | /**
366 | * set the 2nd image square
367 | * @param {Number} length -the number of the images
368 | */
369 |
370 | pxgallery.prototype.setPuzzleSquare = function(length) {
371 |
372 | var boxes = this.getImageDomElements();
373 | if (length === 3) {
374 | var sideLength = parseFloat(this.container.clientHeight) / 2;
375 | boxes[0].style.width = (this.container.clientWidth - sideLength) + 'px';
376 | boxes[1].style.height = sideLength + 'px';
377 | boxes[1].style.width = sideLength + 'px';
378 | boxes[2].style.height = sideLength + 'px';
379 | boxes[2].style.width = sideLength + 'px';
380 | } else if (length === 5) {
381 | var sideLength = parseFloat(this.container.clientWidth / 3);
382 | if (parseInt(sideLength + (_options.gutter * 2)) < parseInt(_options.puzzleHeight)) {
383 | boxes[0].style.width = parseFloat(this.container.clientWidth - sideLength) + 'px';
384 | boxes[1].style.width = sideLength + 'px';
385 | boxes[1].style.height = sideLength + 'px';
386 | boxes[2].style.width = sideLength + 'px';
387 | boxes[2].style.height = parseFloat(this.container.clientHeight - sideLength) + 'px';
388 | } else {
389 | boxes.forEach(function(ele) {
390 | ele.style.width = '';
391 | ele.style.height= '';
392 | }, this);
393 | }
394 | } else {
395 | return;
396 | }
397 | };
398 |
399 | /**
400 | * NOT RECOMMAND, it may effect the perfomance of the browser cause it change the DOM directly
401 | * set the height of the container
402 | * @param {Number} - height
403 | */
404 |
405 | pxgallery.prototype.setPuzzleHeight = function(height) {
406 | _options.puzzleHeight = height;
407 | if (_options.layout === 1) this.setLayout(_options.layout);
408 | };
409 |
410 | /**
411 | * NOT RECOMMAND, it may effect the perfomance of the browser cause it change the DOM directly
412 | * set the number of the column
413 | * @param {NUmber} - columnNum
414 | */
415 |
416 | pxgallery.prototype.setColumnNum = function(columnNum) {
417 | _options.column = columnNum;
418 | if (_options.layout === 2) this.setLayout(2);
419 | };
420 |
421 | /**
422 | * init the waterfall column only after clear the columns inside the container
423 | * @param {NUmber} - columnNum
424 | */
425 |
426 | pxgallery.prototype.initWaterfallColumn = function(columnNum) {
427 | // create column div
428 | this.columns = [];
429 | for (var i = 0; i < columnNum; i++) {
430 | var columnDiv = document.createElement('div');
431 | columnDiv.style.width = (100/columnNum) + '%';
432 | columnDiv.setAttribute('class','waterfallColumn');
433 | this.columns.push(columnDiv);
434 | this.container.appendChild(columnDiv);
435 | }
436 | };
437 |
438 | /**
439 | * get minimun height index of the column
440 | * @return {Number} - index
441 | */
442 |
443 | pxgallery.prototype.getWaterfallHeightMin = function() {
444 |
445 | var min = this.columns[0].clientHeight;
446 | var index = 0;
447 | for (var i = 0; i < this.columns.length; i++) {
448 | if (this.columns[i].clientHeight < min) {
449 | min = this.columns[i].clientHeight;
450 | index = i;
451 | }
452 | }
453 | return index;
454 | };
455 |
456 | /**
457 | * initaialize the barrel layout
458 | * @param {Object} - row, a row object which contain height
459 | */
460 |
461 | pxgallery.prototype.initBarrelBin = function(row) {
462 |
463 | this.rows = [];
464 | for (var i = 0; i < row.length; i++) {
465 | var rowDiv = document.createElement('div');
466 | rowDiv.className = 'barrelRow';
467 | rowDiv.style.height = row[i].height + 'px';
468 | this.rows.push(rowDiv);
469 | this.container.appendChild(rowDiv);
470 | }
471 | };
472 |
473 | /**
474 | * calculate the ratio
475 | * @return {Object} rows
476 | */
477 |
478 | pxgallery.prototype.setBarrelBin = function() {
479 |
480 | var boxes = this.getImageDomElements();
481 | var height = _options.heightMin;
482 | var rows = [];
483 | var width = 0;
484 | var count = 0;
485 | var ratio;
486 | var totalWidth;
487 | var totalHeight;
488 | var restWidth;
489 | var i;
490 |
491 | // compare the total width with the container width
492 | // if the total width is grater than container width
493 | // than push to the row array which include the number and height
494 | // clear data and loop again until end
495 |
496 | for (i = 0; i < boxes.length; i++) {
497 | boxes[i].style.height = height + 'px';
498 | boxes[i].style.width = (height * boxes[i].ratio) + 'px';
499 | width += height * boxes[i].ratio;
500 | if (width > this.container.clientWidth) {
501 | totalWidth = width - boxes[i].clientWidth;
502 | ratio = height / totalWidth;
503 | totalHeight = this.container.clientWidth * ratio;
504 | rows.push({number: i-1, height: totalHeight});
505 | width = boxes[i].clientWidth;
506 | }
507 | }
508 | rows.push({number: i, height: _options.heightMin});
509 |
510 | return rows;
511 |
512 | };
513 |
514 | /**
515 | * NOT RECOMMAND, it may effect the perfomance of the browser cause it change the DOM directly
516 | * set the height of the barrel
517 | * @param {Number} min
518 | */
519 |
520 | pxgallery.prototype.setBarrelHeight = function(min) {
521 |
522 | _options.heightMin = min;
523 | if (_options.layout === 3) this.setLayout(3);
524 | };
525 |
526 | /**
527 | * NOT RECOMMAND, it may effect the perfomance of the browser cause it change the DOM directly
528 | * Set the suqare size when over 768 px
529 | * @param {Number} size - (1-12)
530 | */
531 |
532 | pxgallery.prototype.setMdSquareSize = function(size) {
533 |
534 | _options.mdSquareSize = size;
535 | if (_options.layout === 4) this.setLayout(_options.layout)
536 | };
537 |
538 | /**
539 | * NOT RECOMMAND, it may effect the perfomance of the browser cause it change the DOM directly
540 | * Set the suqare size when under 768 px
541 | * @param {Number} size - (1-12)
542 | */
543 |
544 | pxgallery.prototype.setSmSquareSize = function(size) {
545 |
546 | _options.smSquareSize = size;
547 | if (_options.layout === 4) this.setLayout(_options.layout)
548 | };
549 |
550 | return pxgallery;
551 | }));
552 |
--------------------------------------------------------------------------------
/demo/src/lib/pxgallery.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * pxgallery v0.0.1
4 | * use with pxgallery.css
5 | * @author StevenYu
6 | */
7 |
8 | ;(function (root, factory) {
9 |
10 | if (typeof define === 'function' && define.amd) {
11 | define([], factory);
12 | } else if (typeof module === 'object' && module.exports) {
13 | module.exports = factory();
14 | } else {
15 | // Browser globals (root is window)
16 | root.pxgallery = factory();
17 | }
18 |
19 | }(this, function() {
20 |
21 | 'use strict';
22 |
23 | /**
24 | * @param {Object} opts - options used in plugin
25 | * @constructor
26 | */
27 |
28 | var pxgallery = function(opts) {
29 |
30 |
31 | opts = opts || {};
32 | var fullscreenSelector = opts.fullscreenSelector || '.pxfullscreen';
33 |
34 | this.containerSelector = opts.containerSelector || '.pxgalleryContainer';
35 | this.boxSelector = opts.boxSelector || '.pxgalleryBox';
36 | this.container = document.querySelector(this.containerSelector);
37 | this.fullscreen = document.querySelector(fullscreenSelector);
38 |
39 | this.layout = {
40 | NONE: 0, // no layout
41 | PUZZLE: 1, // puzzle layout
42 | WATERFALL: 2, // waterfall layout
43 | BARREL: 3, // barrel layout
44 | SQUARE: 4 // square layout
45 | };
46 |
47 | };
48 |
49 | /**
50 | * @private
51 | */
52 |
53 | var _options = {
54 | layout : '',
55 | puzzleHeight:'',
56 | coulumn : '',
57 | heightMin : '',
58 | gutter : '',
59 | mdSquareSize:'',
60 | smSquareSize:'',
61 | fullscreenState : '',
62 | images: []
63 | }
64 |
65 | // create a fullscreen for images with next and prev
66 | var _createFullscreen = function(event) {
67 | if (event.target.getAttribute('src').trim()) {
68 | var fullscreen = document.createElement('div');
69 | var img = document.createElement('img');
70 | var next = document.createElement('span');
71 | var prev = document.createElement('span');
72 | var currentImg = event.target.getAttribute('src');
73 | var currentImgIndex = _options.images.indexOf(currentImg);
74 | fullscreen.className = 'pxfullscreen';
75 | next.className = 'pxnext';
76 | prev.className = 'pxprev';
77 | img.src = currentImg;
78 | fullscreen.addEventListener('click', function(event) {
79 | if (event.target != next && event.target != prev) {
80 | this.remove();
81 | }
82 | }, false);
83 | next.addEventListener('click', function() {
84 | currentImgIndex++;
85 | if (currentImgIndex >= _options.images.length) currentImgIndex = 0;
86 | img.src = _options.images[currentImgIndex];
87 | }, false);
88 | prev.addEventListener('click', function() {
89 | currentImgIndex--;
90 | if (currentImgIndex <= 0) currentImgIndex = (_options.images.length - 1);
91 | img.src = _options.images[currentImgIndex];
92 | })
93 |
94 | fullscreen.appendChild(prev);
95 | fullscreen.appendChild(next);
96 | fullscreen.appendChild(img);
97 | this.parentNode.appendChild(fullscreen);
98 | }
99 | };
100 |
101 | // add the box into column or row
102 | var _addBox = function(ele, index) {
103 | switch (_options.layout) {
104 | case 2:
105 | this.columns ? this.columns[index].appendChild(ele) : this.container.appendChild(ele);
106 | break;
107 | case 3:
108 | this.rows ? this.rows[index].appendChild(ele) : this.container.appendChild(ele);
109 | break;
110 | default:
111 | this.container.appendChild(ele);
112 | this.setLayout(_options.layout);
113 | }
114 | }
115 |
116 |
117 | /**
118 | * init the album
119 | * It will replace the photos
120 | * @param {(Stirng | String[])} image - the URL of the photo or the URL array of the photos
121 | * @param {Object} opts - layout options
122 | */
123 |
124 | pxgallery.prototype.setImage = function(image, opts) {
125 |
126 | if (typeof image === 'string') {
127 | this.setImage([image]);
128 | return;
129 | }
130 |
131 | _options.layout = opts.layout || 2;
132 | _options.puzzleHeight = opts.puzzleHeight || 400;
133 | _options.fullscreenState = opts.fullscreenState || true;
134 | _options.column = opts.column || 5;
135 | _options.heightMin = opts.heightMin || 150;
136 | _options.mdSquareSize = opts.mdSquareSize || 3;
137 | _options.smSquareSize = opts.smSquareSize || 6;
138 | _options.gutter = opts.gutter || 10;
139 | var _this = this;
140 |
141 | this.addImage(image, true);
142 | this.setLayout(_options.layout);
143 | _options.fullscreenState ? this.enableFullscreen() : this.disableFullscreen();
144 |
145 | window.onload = function() {
146 | _this.setLayout(_options.layout);
147 | }
148 |
149 | window.onresize = function() {
150 | _this.setLayout(_options.layout);
151 | }
152 | };
153 |
154 | /**
155 | * get the DOM elements which contain the images
156 | * @return {HTMLelement[]} boxes
157 | */
158 |
159 | pxgallery.prototype.getImageDomElements = function() {
160 |
161 | var boxes = Array.prototype.slice.call(this.container.querySelectorAll(this.boxSelector));
162 | var url = [];
163 | boxes.forEach(function(ele) {
164 | ele.ratio = ele.clientWidth / ele.clientHeight;
165 | url.push(ele.querySelector('img').src);
166 | }, this);
167 | _options.images = url;
168 | return boxes;
169 | };
170 |
171 | /**
172 | * add images to the container
173 | * @param {(String | String[])} image - the URL of the photo or the URL array of the photos
174 | * @param {Boolean} raw - weather add the images to the container directly or not
175 | */
176 |
177 | pxgallery.prototype.addImage = function(image, raw) {
178 |
179 | if (typeof image === 'string') {
180 | this.addImage([image]);
181 | return;
182 | }
183 | if (!raw) {
184 | if (_options.layout === 2) var index = this.getWaterfallHeightMin();
185 | if (_options.layout === 3) var index = (this.rows.length - 1);
186 | }
187 |
188 | for (var i = 0; i < image.length; i++) {
189 | var div = document.createElement('div');
190 | var img = new Image();
191 | div.className = 'pxgalleryBox';
192 | div.style.border = _options.gutter / 2 + 'px solid transparent';
193 | img.src = image[i];
194 | _options.images.push(image[i]);
195 | div.appendChild(img);
196 | if (!raw) {
197 | (_options.layout === 2 || _options.layout === 3 ) ? _addBox.call(this, div, index) : _addBox.apply(this, [div]);
198 | }
199 | else {
200 | _addBox.apply(this, [div])
201 | }
202 | }
203 | };
204 |
205 | /**
206 | * remove the images
207 | * @param {(HTMLelement|HTMLelement[])} image - the images that need to be removed
208 | */
209 |
210 | pxgallery.prototype.removeImage = function(image) {
211 |
212 | image.forEach(function(ele) {
213 | var removeUrl = ele.querySelector('img').src;
214 | _options.images = _options.images.filter(function (url) {
215 | return url != removeUrl;
216 | })
217 | ele.remove();
218 | }, this)
219 |
220 | };
221 |
222 | /**
223 | * set the layout
224 | * @param {Number} - layoutValue
225 | */
226 |
227 | pxgallery.prototype.setLayout = function(layoutValue) {
228 |
229 | var boxes = this.getImageDomElements();
230 | this.clearLayout();
231 | _options.layout = layoutValue;
232 |
233 | switch (layoutValue) {
234 |
235 | case 0:
236 | break;
237 |
238 | case 1:
239 | if (boxes.length > 6) {
240 | console.error('PUZZLE layout only can contain 6 photos');
241 | break;
242 | }
243 | this.container.style.height = _options.puzzleHeight + 'px';
244 | this.container.className = this.containerSelector.slice(1) + ' puzzle-' + boxes.length;
245 | this.setPuzzleSquare(boxes.length);
246 | break;
247 |
248 | case 2:
249 | this.container.className = this.containerSelector.slice(1) + ' waterfall';
250 | this.initWaterfallColumn(_options.column);
251 | for (var i = 0; i < boxes.length; i++) {
252 | _addBox.call(this, boxes[i], this.getWaterfallHeightMin());
253 | }
254 | break;
255 |
256 | case 3:
257 | this.container.className = this.containerSelector.slice(1) + ' barrel';
258 | var rows = this.setBarrelBin();
259 | this.initBarrelBin(rows);
260 | var index = 0;
261 | for (var i = 0; i < boxes.length; i++) {
262 | if (i > rows[index].number) index ++;
263 | boxes[i].style.height = '100%';
264 | boxes[i].style.width = '';
265 | _addBox.call(this, boxes[i], index);
266 | }
267 | break;
268 |
269 | case 4:
270 | this.container.className = this.containerSelector.slice(1) + ' square';
271 | for (var i = 0; i < boxes.length; i++) {
272 | var md = 'col-md-' + _options.mdSquareSize;
273 | var sm = 'col-sm-' + _options.smSquareSize;
274 | boxes[i].className = this.boxSelector.slice(1) + ' ' + md + ' ' + sm;
275 | }
276 | }
277 | };
278 |
279 | /**
280 | * get current layout
281 | * @return {Number} -_options.layout
282 | */
283 |
284 | pxgallery.prototype.getLayout = function() {
285 | return _options.layout;
286 | };
287 |
288 | pxgallery.prototype.clearLayout = function() {
289 |
290 | var boxes = this.getImageDomElements();
291 | var _this = this;
292 | this.container.className = this.containerSelector.slice(1);
293 | this.container.style.height = '';
294 | boxes.forEach(function(ele) {
295 | ele.style.width = '';
296 | ele.style.height = '';
297 | }, this)
298 |
299 | if (this.columns) {
300 | this.columns.forEach(function(ele) {
301 | ele.remove();
302 | }, this)
303 | boxes.forEach(function(ele) {
304 | _this.container.appendChild(ele);
305 | }, this)
306 | }
307 |
308 | if (this.rows) {
309 | this.rows.forEach(function(ele) {
310 | ele.remove();
311 | }, this)
312 | boxes.forEach(function(ele) {
313 | _this.container.appendChild(ele);
314 | }, this)
315 | }
316 | _options.layout = 0;
317 | };
318 |
319 | /**
320 | * NOT RECOMMAND, it may effect the perfomance of the browser cause it change the DOM directly
321 | * set the gutter between images
322 | * @param {Number} - gutter
323 | */
324 |
325 | pxgallery.prototype.setGutter = function(gutter) {
326 |
327 | _options.gutter = gutter;
328 | var boxes = this.getImageDomElements()
329 | boxes.forEach(function(ele) {
330 | ele.style.border = (gutter / 2) +'px solid transparent';
331 | }, this)
332 | };
333 |
334 | /**
335 | * enable fullscreen
336 | */
337 |
338 | pxgallery.prototype.enableFullscreen = function() {
339 |
340 | _options.fullscreenState = true;
341 | this.container.addEventListener('click', _createFullscreen, false);
342 | };
343 |
344 | /**
345 | * disable fullscreen
346 | */
347 |
348 | pxgallery.prototype.disableFullscreen = function() {
349 |
350 | _options.fullscreenState = false;
351 | this.container.removeEventListener('click', _createFullscreen, false);
352 | };
353 |
354 | /**
355 | * @return {Boolean} weather eenable fullscreen view
356 | */
357 |
358 | pxgallery.prototype.isFullscreenEnabled = function() {
359 |
360 | return _options.fullscreenState;
361 | };
362 |
363 | /**
364 | * set the 2nd image square
365 | * @param {Number} length -the number of the images
366 | */
367 |
368 | pxgallery.prototype.setPuzzleSquare = function(length) {
369 |
370 | var boxes = this.getImageDomElements();
371 | if (length === 3) {
372 | var sideLength = parseFloat(this.container.clientHeight) / 2;
373 | boxes[0].style.width = (this.container.clientWidth - sideLength) + 'px';
374 | boxes[1].style.height = sideLength + 'px';
375 | boxes[1].style.width = sideLength + 'px';
376 | boxes[2].style.height = sideLength + 'px';
377 | boxes[2].style.width = sideLength + 'px';
378 | } else if (length === 5) {
379 | var sideLength = parseFloat(this.container.clientWidth / 3);
380 | if (parseInt(sideLength + (_options.gutter * 2)) < parseInt(_options.puzzleHeight)) {
381 | boxes[0].style.width = parseFloat(this.container.clientWidth - sideLength) + 'px';
382 | boxes[1].style.width = sideLength + 'px';
383 | boxes[1].style.height = sideLength + 'px';
384 | boxes[2].style.width = sideLength + 'px';
385 | boxes[2].style.height = parseFloat(this.container.clientHeight - sideLength) + 'px';
386 | } else {
387 | boxes.forEach(function(ele) {
388 | ele.style.width = '';
389 | ele.style.height= '';
390 | }, this);
391 | }
392 | } else {
393 | return;
394 | }
395 | };
396 |
397 | /**
398 | * NOT RECOMMAND, it may effect the perfomance of the browser cause it change the DOM directly
399 | * set the height of the container
400 | * @param {Number} - height
401 | */
402 |
403 | pxgallery.prototype.setPuzzleHeight = function(height) {
404 | _options.puzzleHeight = height;
405 | if (_options.layout === 1) this.setLayout(_options.layout);
406 | };
407 |
408 | /**
409 | * NOT RECOMMAND, it may effect the perfomance of the browser cause it change the DOM directly
410 | * set the number of the column
411 | * @param {NUmber} - columnNum
412 | */
413 |
414 | pxgallery.prototype.setColumnNum = function(columnNum) {
415 | _options.column = columnNum;
416 | if (_options.layout === 2) this.setLayout(2);
417 | };
418 |
419 | /**
420 | * init the waterfall column only after clear the columns inside the container
421 | * @param {NUmber} - columnNum
422 | */
423 |
424 | pxgallery.prototype.initWaterfallColumn = function(columnNum) {
425 | // create column div
426 | this.columns = [];
427 | for (var i = 0; i < columnNum; i++) {
428 | var columnDiv = document.createElement('div');
429 | columnDiv.style.width = (100/columnNum) + '%';
430 | columnDiv.setAttribute('class','waterfallColumn');
431 | this.columns.push(columnDiv);
432 | this.container.appendChild(columnDiv);
433 | }
434 | };
435 |
436 | /**
437 | * get minimun height index of the column
438 | * @return {Number} - index
439 | */
440 |
441 | pxgallery.prototype.getWaterfallHeightMin = function() {
442 |
443 | var min = this.columns[0].clientHeight;
444 | var index = 0;
445 | for (var i = 0; i < this.columns.length; i++) {
446 | if (this.columns[i].clientHeight < min) {
447 | min = this.columns[i].clientHeight;
448 | index = i;
449 | }
450 | }
451 | return index;
452 | };
453 |
454 | /**
455 | * initaialize the barrel layout
456 | * @param {Object} - row, a row object which contain height
457 | */
458 |
459 | pxgallery.prototype.initBarrelBin = function(row) {
460 |
461 | this.rows = [];
462 | for (var i = 0; i < row.length; i++) {
463 | var rowDiv = document.createElement('div');
464 | rowDiv.className = 'barrelRow';
465 | rowDiv.style.height = row[i].height + 'px';
466 | this.rows.push(rowDiv);
467 | this.container.appendChild(rowDiv);
468 | }
469 | };
470 |
471 | /**
472 | * calculate the ratio
473 | * @return {Object} - rows
474 | */
475 |
476 | pxgallery.prototype.setBarrelBin = function() {
477 |
478 | var boxes = this.getImageDomElements();
479 | var height = _options.heightMin;
480 | var rows = [];
481 | var width = 0;
482 | var count = 0;
483 | var ratio;
484 | var totalWidth;
485 | var totalHeight;
486 | var restWidth;
487 | var i;
488 |
489 | // compare the total width with the container width
490 | // if the total width is grater than container width
491 | // than push to the row array which include the number and height
492 | // clear data and loop again until end
493 |
494 | for (i = 0; i < boxes.length; i++) {
495 | boxes[i].style.height = height + 'px';
496 | boxes[i].style.width = (height * boxes[i].ratio) + 'px';
497 | width += height * boxes[i].ratio;
498 | if (width > this.container.clientWidth) {
499 | totalWidth = width - boxes[i].clientWidth;
500 | ratio = height / totalWidth;
501 | totalHeight = this.container.clientWidth * ratio;
502 | rows.push({number: i-1, height: totalHeight});
503 | width = boxes[i].clientWidth;
504 | }
505 | }
506 | rows.push({number: i, height: _options.heightMin});
507 |
508 | return rows;
509 |
510 | };
511 |
512 | /**
513 | * NOT RECOMMAND, it may effect the perfomance of the browser cause it change the DOM directly
514 | * set the height of the barrel
515 | * @param {Number} - min
516 | */
517 |
518 | pxgallery.prototype.setBarrelHeight = function(min) {
519 |
520 | _options.heightMin = min;
521 | if (_options.layout === 3) this.setLayout(3);
522 | };
523 |
524 | /**
525 | * NOT RECOMMAND, it may effect the perfomance of the browser cause it change the DOM directly
526 | * Set the suqare size when over 768 px
527 | * @param {Number} size - (1-12)
528 | */
529 |
530 | pxgallery.prototype.setMdSquareSize = function(size) {
531 |
532 | _options.mdSquareSize = size;
533 | if (_options.layout === 4) this.setLayout(_options.layout)
534 | };
535 |
536 | /**
537 | * NOT RECOMMAND, it may effect the perfomance of the browser cause it change the DOM directly
538 | * Set the suqare size when under 768 px
539 | * @param {Number} size - (1-12)
540 | */
541 |
542 | pxgallery.prototype.setSmSquareSize = function(size) {
543 |
544 | _options.smSquareSize = size;
545 | if (_options.layout === 4) this.setLayout(_options.layout)
546 | };
547 |
548 | return pxgallery;
549 | }));
550 |
--------------------------------------------------------------------------------