├── .gitignore ├── MIT-LICENSE.txt ├── README.md ├── bower.json ├── css └── focuspoint.css ├── demos ├── css-js-comparison │ ├── comparison.css │ └── index.html ├── demo.css ├── full-screen │ ├── full-screen.css │ └── index.html ├── grid │ ├── bird.html │ ├── dolphin.html │ ├── grid.css │ ├── kangaroo.html │ └── lizard.html ├── helper │ ├── helper-tool.css │ └── index.html ├── img │ ├── bird.jpg │ ├── city_from_unsplash.jpg │ ├── demo.jpg │ ├── dolphin.jpg │ ├── focuspoint-target.png │ ├── grid.png │ ├── kangaroo.jpg │ └── lizard.jpg └── test │ ├── index.html │ └── test.css ├── focuspoint.jquery.json ├── js ├── jquery.focuspoint.helper-basic.js ├── jquery.focuspoint.helpertool.js ├── jquery.focuspoint.js ├── jquery.focuspoint.min.js └── jquery.min.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2014 Jonathon Menz and other contributors, 2 | https://github.com/jonom/jquery-focuspoint 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jQuery FocusPoint 2 | 3 | ## FocusPoint 2 4 | 5 | I started work on a major update to this plugin a couple of years ago, but it has been in limbo for a while and probably won't be picked up again unless someone wants to sponsor the work (please [get in touch](http://jonathonmenz.com) if you do!). I didn't get as far as removing the jQuery dependancy but please feel free to use the v-2-dev branch to benefit from a few new features: 6 | 7 | * Better resizing performance 8 | * More familiar coordinate system (like that used in CSS) 9 | * Suppor for ideal and minimum cropping region 10 | 11 | If you love this plugin feel free to send me an encouraging email or consider sponsoring an update. You're also welcome to make a [small donation](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5VUDD3ACRC4TC) if you like. I receive an average of one per year, so it won't go unnoticed. 😄💰 12 | 13 | ## Intelligent cropping for flexible image containers 14 | 15 | ![image](demos/img/demo.jpg?raw=true) 16 | 17 | Websites don't have a single layout any more. The space you have for an image may be portrait on a laptop, landscape on a tablet, and square on a mobile - particularly if you're using a full-screen image. 18 | 19 | If you have to use the same image file in all these contexts, you might not be happy with the results you get when you 'fill' the allocated space with your image. Your subject might be clipped or completely missing, or just really awkward looking. 20 | 21 | FocusPoint makes sure your image looks great in any container, by ensuring the 'spare' parts of your image (negative space) are cropped out before the important parts. 22 | 23 | For a quick overview of the plugin check out this [video by Petr Tichy](http://youtu.be/Wxmxsw65BQw?t=6m49s). 24 | 25 | ## Examples 26 | 27 | Here are some examples showing the same image cropped a variety of different ways at once. Make sure you play with resizing the browser window to get a feel for what FocusPoint does. 28 | 29 | * [Lizard](http://jonom.github.io/jquery-focuspoint/demos/grid/lizard.html) 30 | * [Kangaroo](http://jonom.github.io/jquery-focuspoint/demos/grid/kangaroo.html) 31 | * [Dolphin](http://jonom.github.io/jquery-focuspoint/demos/grid/dolphin.html) 32 | * [Bird](http://jonom.github.io/jquery-focuspoint/demos/grid/bird.html) 33 | 34 | And here is a [full screen](http://jonom.github.io/jquery-focuspoint/demos/full-screen/index.html) demo. 35 | 36 | ## How does it work? 37 | 38 | The idea is that most images have a focal point or subject that is the most important part of the image. In the case of a traditional portrait photo this would be the subject's face (or specifically the spot right between their eyes). In the image above it's arguably the point halfway between the two people's faces. 39 | 40 | FocusPoint requires you to indicate where this focal point is located within your image, and then works in the background to ensure that point is never cropped out. 41 | 42 | 43 | ## How to use 44 | 45 | #### 1. Calculate your image's focus point 46 | 47 | An image's focus point is made up of x (horizontal) and y (vertical) coordinates. The value of a coordinate can be a number with decimal points anywhere between -1 and +1, where 0 is the centre. X:-1 indicates the left edge of the image, x:1 the right edge. For the y axis, y:1 is the top edge and y:-1 is the bottom. 48 | 49 | ![image](demos/img/grid.png?raw=true) 50 | 51 | **Confused?** Don't worry, there's a handy script included to help you find the focus coordinates of an image with a single click. Check out the [helper tool](http://jonom.github.io/jquery-focuspoint/demos/helper/index.html) *(vastly improved courtesy of [@auginator](https://github.com/auginator)).* 52 | 53 | #### 2. Include javascript and CSS 54 | 55 | You'll need to include jQuery (v1.9 or greater), the FocusPoint script, and FocusPoint css file. Example: 56 | 57 | ```html 58 | 59 | 60 | 61 | ``` 62 | 63 | #### 3. Mark up your image container 64 | 65 | Specify the image dimensions and focus point coordinates on the image container. The image will take up whatever space is available in the container, so make sure there is some space to fill by setting a height for the container in your CSS. Example: 66 | 67 | ```html 68 |
73 | 74 |
75 | ``` 76 | 77 | Note: setting `data-image-w` and `data-image-h` is optional but recommended. Omitting these value means your image will not be positioned correctly inside the frame until it has finished loading, which may cause a visible jump. 78 | 79 | #### 4. Fire FocusPoint plugin 80 | 81 | Usually the best place for this will be inside your `$(document).ready()` function. 82 | 83 | ```javascript 84 | //Fire plugin 85 | $('.focuspoint').focusPoint(); 86 | ``` 87 | 88 | That's it! 89 | 90 | #### Configuration options 91 | 92 | FocusPoint comes with a few options you can change to suit your needs. 93 | 94 | | Option | Values | Default | Description | 95 | | ---------------------- | --------------------- | ------- | ----------- | 96 | | `reCalcOnWindowResize` | `true` or `false` | `true` | Whether or not to re-adjust image when the window is resized | 97 | | `throttleDuration` | Int e.g. `0` or `100` | `17` | Throttling rate in milliseconds. Set to `0` to disable throttling. | 98 | 99 | Example usage: 100 | 101 | ```javascript 102 | $('.focuspoint').focusPoint({ 103 | throttleDuration: 100 //re-focus images at most once every 100ms. 104 | }); 105 | ``` 106 | 107 | #### FocusPoint functions 108 | 109 | Once you have initialised FocusPoint on an image container you can access FocusPoint methods like this: `$(someContainer).data('focusPoint').methodName()`. 110 | 111 | Or the shorter way, like this: `$(someContainer).focusPoint('methodName')` 112 | 113 | | Function | Description | 114 | | --------------- | ----------- | 115 | | `adjustFocus()` | Re-do calculations and re-position an image in it's frame. Call if container dimensions change. | 116 | | `windowOn()` | Start window event listener and re-focus image when window is resized | 117 | | `windowOff()` | Stop re-focusing image when window is resized | 118 | 119 | #### Using FocusPoint in content sliders 120 | 121 | Currently FocusPoint can't do it's calculations properly if an image container or it's parent is set to `display:none`, as it won't have any dimensions. This can cause problems with sliders that hide non-active slides. A work-around for now is to trigger `adjustFocus()` on the image container as soon as it become visible. 122 | 123 | ## Tips & Tricks 124 | 125 | #### Image composition 126 | In order for this concept of 'fluid cropping' to work well, your images will need to include some negative space around the subject that you are happy to be cropped out when necessary. You don't need space on every side of the subject - but for maximum flexibility you'll want to include both some vertical and horizontal negative space. 127 | 128 | #### Pure CSS alternative 129 | 130 | You can get a similar effect to this technique using only CSS and the `background-position` and `background-size` properties. Browser support isn't as good (at the moment) and your image won't be positioned exactly the same way - but it's pretty close. The CSS technique leans towards preserving the original composition while FocusPoint is biased towards keeping the subject of the image in the centre of the frame. Depending on your requirements either technique may suit you better. 131 | 132 | * [Pure CSS example and comparison](http://jonom.github.io/jquery-focuspoint/demos/css-js-comparison/index.html) 133 | * [Helper tool for calculating CSS values](http://jonom.github.io/jquery-focuspoint/demos/helper/index.html) 134 | 135 | #### SilverStripe CMS integration 136 | 137 | This plugin plays really well with the [silverstripe-focuspoint](https://github.com/jonom/silverstripe-focuspoint) module, which lets you set the focuspoint on any image with just a click, and makes the info available in your front-end templates so you don't have to do any math. It also provides really easy 'destructive' cropping outputting resampled images cropped to a particular width and height based on the same logic. 138 | 139 | ## Feedback welcome! 140 | 141 | Nothing would encourage me to keep updating this script more than hearing how it's been used in the real world. Get in touch with me at [jonathonmenz.com](http://jonathonmenz.com) to let me know how you've used this plugin or any suggestions you have for improving it. Please [report bugs or issues on github](https://github.com/jonom/jquery-focuspoint/issues). 142 | 143 | **Note:** To date I'm not yet aware of any live websites (apart from my own) that use this plugin - so please get in touch if you launch a site that uses FocusPoint! 144 | 145 | #### Tip jar 146 | 147 | If FocusPoint helped you impress a client and you want to say thanks, you're welcome to [leave a small donation](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5VUDD3ACRC4TC) to help fund the purchase of coffee, which will help me stay awake during future development. 148 | 149 | [Donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5VUDD3ACRC4TC) 150 | 151 | Donations received / Warm fuzzies generated: **6** 152 | Caffé Lattes funded: **17** :coffee: :relieved: 153 | **Thanks!** Daniil, Cohan, Romulo, Lemuel, David 154 | 155 | ## Changelog 156 | 157 | #### v1.1.1 2014-09-23 158 | Minor fixes 159 | #### v1.1.0 2014-09-18 160 | Refactored code (thanks @xat) 161 | Added ability to start/stop window-resize listener (thanks @xat) 162 | Use % instead of px for positioning, for better scaling 163 | Added shortcuts to plugin methods 164 | #### v1.0.3 2014-09-06 165 | Throttled window resize updates 166 | #### v1.0.2 2014-09-05 167 | Made setting image width and height on shell optional (thanks @luruke) 168 | #### v1.0.1 2014-09-04 169 | Cleaned up variables 170 | #### v1.0.0 2014-08-19 171 | Initial release 172 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-focuspoint", 3 | "homepage": "https://github.com/jonom/jquery-focuspoint", 4 | "authors": [ 5 | "Jonathon Menz" 6 | ], 7 | "description": "jQuery plugin for 'responsive cropping'. Dynamically crop images to fill available space without cutting out the image's subject. Great for full-screen images.", 8 | "main": [ 9 | "js/jquery.focuspoint.js", 10 | "css/focuspoint.css" 11 | ], 12 | "keywords": [ 13 | "crop", 14 | "cropping", 15 | "image", 16 | "responive", 17 | "fill", 18 | "background", 19 | "full-screen", 20 | "focus", 21 | "focuspoint" 22 | ], 23 | "license": "MIT", 24 | "ignore": [ 25 | "**/.*", 26 | "demos", 27 | "node_modules", 28 | "bower_components", 29 | "test", 30 | "tests" 31 | ], 32 | "dependencies": { 33 | "jquery": ">=1.9" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /css/focuspoint.css: -------------------------------------------------------------------------------- 1 | /* !FOCUSED IMAGES */ 2 | /*-----------------------------------------*/ 3 | .focuspoint { 4 | position: relative; /*Any position but static should work*/ 5 | overflow: hidden; 6 | } 7 | .focuspoint img { 8 | position: absolute; 9 | left: 0; 10 | top: 0; 11 | margin: 0; 12 | display: block; 13 | /* fill and maintain aspect ratio */ 14 | width: auto; height: auto; 15 | min-width: 100%; min-height: 100%; 16 | max-height: none; max-width: none; 17 | } -------------------------------------------------------------------------------- /demos/css-js-comparison/comparison.css: -------------------------------------------------------------------------------- 1 | /* !CONTAINERS */ 2 | /*-----------------------------------------*/ 3 | 4 | html,body{ 5 | height: 100%; 6 | width: 100%; 7 | max-height: none; 8 | max-width: none; 9 | overflow: hidden;/*Prevent scrollbars in IE8*/ 10 | margin: 0; 11 | } 12 | body { 13 | position: fixed; 14 | left: 5px; 15 | right: 5px; 16 | top: 5px; 17 | bottom: 5px; 18 | height: auto; 19 | width: auto; 20 | } 21 | 22 | #Frame1, #Frame2 { 23 | position: absolute; 24 | overflow: hidden; 25 | border: 5px solid #fff; 26 | margin: -5px 0 0 -5px; 27 | width: 37.5%; 28 | height: 100%; 29 | left: 25%; 30 | top: 0; 31 | } 32 | #Frame2 { 33 | left: 62.5%; 34 | background-image: url(../img/bird.jpg); 35 | background-size: cover; 36 | background-position: 64.4677661% 64.2%; 37 | } -------------------------------------------------------------------------------- /demos/css-js-comparison/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | FocusPoint Example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 31 | 32 | 33 | 34 | 35 |
36 | 37 |
42 | 43 |
44 | 45 |
46 |
47 | 48 |
49 | 50 |
51 |
52 | 53 |

Original

54 |
55 |

Try resizing the window. Watch how the frames change to use all of 56 | the available space while preserving the focus of the image. 57 | The left frame uses FocusPoint to control the crop, while the right frame uses only CSS. 58 | » Project Home

59 |
60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /demos/demo.css: -------------------------------------------------------------------------------- 1 | /* !TYPOGRAPHY */ 2 | /*-----------------------------------------*/ 3 | body { 4 | font-family: sans-serif; 5 | color: #717171; 6 | font-size: 12px; 7 | } 8 | a { 9 | color: #2697ff; 10 | text-decoration: none; 11 | } 12 | a:hover, 13 | a:focus, 14 | a:active { 15 | color: #0074de; 16 | } 17 | 18 | /* !INFO */ 19 | /*-----------------------------------------*/ 20 | #Info { 21 | position: absolute; 22 | left: 2%; 23 | top: 2%; 24 | width: 20%; 25 | box-shadow: 0px 0px 13px rgba(0,0,0,0.6); 26 | background: #fff; 27 | border: 1px solid #fff; 28 | } 29 | #Info p { 30 | font-size: 12px; 31 | padding: 10px; 32 | margin: 0; 33 | } 34 | #Original { 35 | position: relative; 36 | } 37 | #Original img { 38 | width: auto; 39 | height: auto; 40 | max-width: 100%; 41 | display: block; 42 | margin: 0; 43 | } 44 | #Original h4 { 45 | position: absolute; 46 | left: 0; 47 | bottom: 15px; 48 | width: 100%; 49 | text-align: center; 50 | margin: 0; 51 | } 52 | #Original h4 span { 53 | font-size: 12px; 54 | padding: 3px 10px; 55 | border-radius: 100px; 56 | background: rgba(0,0,0,0.32); 57 | color: #fff; 58 | } -------------------------------------------------------------------------------- /demos/full-screen/full-screen.css: -------------------------------------------------------------------------------- 1 | /* !FULL SCREEN IMAGE */ 2 | /*-----------------------------------------*/ 3 | 4 | html,body,.focuspoint{ 5 | height: 100%; 6 | width: 100%; 7 | max-height: none; 8 | max-width: none; 9 | overflow: hidden;/*Prevent scrollbars in IE8*/ 10 | margin: 0; 11 | } 12 | a { 13 | position: fixed; 14 | left: 0; 15 | top: 0; 16 | background: #fff; 17 | padding: 5px 10px; 18 | } -------------------------------------------------------------------------------- /demos/full-screen/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | FocusPoint Example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 31 | 32 | 33 | 34 | 35 |
40 | 41 |
42 | 43 | » Project Home 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /demos/grid/bird.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | FocusPoint Example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 31 | 32 | 33 | 34 | 35 |
36 | 37 |
42 | 43 |
44 | 45 |
50 | 51 |
52 | 53 |
58 | 59 |
60 | 61 |
66 | 67 |
68 | 69 |
74 | 75 |
76 | 77 |
82 | 83 |
84 | 85 |
90 | 91 |
92 | 93 |
98 | 99 |
100 | 101 |
106 | 107 |
108 | 109 |
110 | 111 |
112 |
113 | 114 |

Original

115 |
116 |

Try resizing the window. Watch how the frames change to use all of the available space while preserving the focus of the image. » Project Home

117 |
118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /demos/grid/dolphin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | FocusPoint Example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 37 | 38 | 39 | 40 | 41 |
42 | 43 |
48 | 49 |
50 | 51 |
56 | 57 |
58 | 59 |
64 | 65 |
66 | 67 |
72 | 73 |
74 | 75 |
80 | 81 |
82 | 83 |
88 | 89 |
90 | 91 |
96 | 97 |
98 | 99 |
104 | 105 |
106 | 107 |
112 | 113 |
114 | 115 |
116 | 117 |
118 |
119 | 120 |

Original

121 |
122 |

Try resizing the window. Watch how the frames change to use all of the available space while preserving the focus of the image. » Project Home

123 |
124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /demos/grid/grid.css: -------------------------------------------------------------------------------- 1 | /* !CONTAINERS */ 2 | /*-----------------------------------------*/ 3 | 4 | html,body{ 5 | height: 100%; 6 | width: 100%; 7 | max-height: none; 8 | max-width: none; 9 | overflow: hidden;/*Prevent scrollbars in IE8*/ 10 | margin: 0; 11 | } 12 | body { 13 | position: fixed; 14 | left: 5px; 15 | right: 5px; 16 | top: 5px; 17 | bottom: 5px; 18 | height: auto; 19 | width: auto; 20 | } 21 | #Frame1, #Frame2, #Frame3, #Frame4, #Frame5, #Frame6, #Frame7, #Frame8, #Frame9 { 22 | position: absolute; 23 | overflow: hidden; 24 | border: 5px solid #fff; 25 | margin: -5px 0 0 -5px; 26 | } 27 | #Frame1, #Frame4, #Frame7 { 28 | width: 66.6666667%; 29 | left: 0; 30 | } 31 | #Frame2, #Frame5, #Frame8 { 32 | width: 22.2222222%; 33 | left: 66.6666667%; 34 | } 35 | #Frame3, #Frame6, #Frame9 { 36 | width: 11.1111111%; 37 | left: 88.8888889%; 38 | } 39 | #Frame1, #Frame2, #Frame3 { 40 | height: 66.6666667%; 41 | top: 0; 42 | } 43 | #Frame4, #Frame5, #Frame6 { 44 | height: 22.2222222%; 45 | top: 66.6666667%; 46 | } 47 | #Frame7, #Frame8, #Frame9 { 48 | height: 11.1111111%; 49 | top: 88.8888889%; 50 | } -------------------------------------------------------------------------------- /demos/grid/kangaroo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | FocusPoint Example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 37 | 38 | 39 | 40 | 41 |
42 | 43 |
48 | 49 |
50 | 51 |
56 | 57 |
58 | 59 |
64 | 65 |
66 | 67 |
72 | 73 |
74 | 75 |
80 | 81 |
82 | 83 |
88 | 89 |
90 | 91 |
96 | 97 |
98 | 99 |
104 | 105 |
106 | 107 |
112 | 113 |
114 | 115 |
116 | 117 |
118 |
119 | 120 |

Original

121 |
122 |

Try resizing the window. Watch how the frames change to use all of the available space while preserving the focus of the image. » Project Home

123 |
124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /demos/grid/lizard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | FocusPoint Example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 31 | 32 | 33 | 34 | 35 |
36 | 37 |
42 | 43 |
44 | 45 |
50 | 51 |
52 | 53 |
58 | 59 |
60 | 61 |
66 | 67 |
68 | 69 |
74 | 75 |
76 | 77 |
82 | 83 |
84 | 85 |
90 | 91 |
92 | 93 |
98 | 99 |
100 | 101 |
106 | 107 |
108 | 109 |
110 | 111 |
112 |
113 | 114 |

Original

115 |
116 |

Try resizing the window. Watch how the frames change to use all of the available space while preserving the focus of the image. » Project Home

117 |
118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /demos/helper/helper-tool.css: -------------------------------------------------------------------------------- 1 | 2 | /* !HELPER TOOL GUI */ 3 | /*-----------------------------------------*/ 4 | #Info { 5 | width:320px; 6 | } 7 | #Info .helper-tool h1 { 8 | font-size:14px; 9 | } 10 | #Info .helper-tool p { 11 | font-size: 0.825rem; 12 | padding:0; 13 | margin:0 0 1em; 14 | } 15 | .helper-tool, .helper-tool * { 16 | box-sizing:border-box; 17 | } 18 | .helper-tool { 19 | padding:12px; 20 | border:1px solid #fcfcfc; 21 | } 22 | .helper-tool input { 23 | position:relative; 24 | width:100%; 25 | } 26 | 27 | /* !HELPER TOOL TARGETING SYSTEM */ 28 | .focuspoint img { 29 | transition: all 500ms ease-in-out; 30 | -webkit-transition: all 500ms ease-in-out; 31 | -moz-transition: all 500ms ease-in-out; 32 | } 33 | 34 | /* !HELPER TOOL TARGETING SYSTEM */ 35 | .helper-tool-target { 36 | position: relative; 37 | width: 300px; 38 | overflow: hidden; 39 | margin-bottom:1em; 40 | } 41 | .helper-tool-target img { 42 | display: block; 43 | max-width: 100%; 44 | height:auto; 45 | } 46 | .helper-tool-target img.target-overlay, .helper-tool-target img.reticle { 47 | position: absolute; 48 | top: 0; 49 | left: 0; 50 | } 51 | .helper-tool-target img.target-overlay { 52 | cursor:pointer; 53 | opacity: 0.01; 54 | } 55 | .helper-tool-target img.reticle { 56 | -webkit-transform: translate(-50%, -50%); 57 | -ms-transform: translate(-50%, -50%); 58 | transform: translate(-50%, -50%); 59 | top:50%; 60 | left:50%; 61 | transition: all 500ms ease-in-out; 62 | -webkit-transition: all 500ms ease-in-out; 63 | -moz-transition: all 500ms ease-in-out; 64 | } 65 | -------------------------------------------------------------------------------- /demos/helper/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | FocusPoint Helper Tool 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 |
32 |
33 |

Click the image to set the FocusPoint.

34 | 35 |
36 | 37 | 38 | 39 |
40 |

41 | 42 | 43 |

44 |

45 | 46 | 47 |

48 |

49 | 50 | 51 |

52 |

» Project Home

53 |
54 |
55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /demos/img/bird.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonom/jquery-focuspoint/14ea26bbcf59a059b46455827da8b7389feb8082/demos/img/bird.jpg -------------------------------------------------------------------------------- /demos/img/city_from_unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonom/jquery-focuspoint/14ea26bbcf59a059b46455827da8b7389feb8082/demos/img/city_from_unsplash.jpg -------------------------------------------------------------------------------- /demos/img/demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonom/jquery-focuspoint/14ea26bbcf59a059b46455827da8b7389feb8082/demos/img/demo.jpg -------------------------------------------------------------------------------- /demos/img/dolphin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonom/jquery-focuspoint/14ea26bbcf59a059b46455827da8b7389feb8082/demos/img/dolphin.jpg -------------------------------------------------------------------------------- /demos/img/focuspoint-target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonom/jquery-focuspoint/14ea26bbcf59a059b46455827da8b7389feb8082/demos/img/focuspoint-target.png -------------------------------------------------------------------------------- /demos/img/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonom/jquery-focuspoint/14ea26bbcf59a059b46455827da8b7389feb8082/demos/img/grid.png -------------------------------------------------------------------------------- /demos/img/kangaroo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonom/jquery-focuspoint/14ea26bbcf59a059b46455827da8b7389feb8082/demos/img/kangaroo.jpg -------------------------------------------------------------------------------- /demos/img/lizard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonom/jquery-focuspoint/14ea26bbcf59a059b46455827da8b7389feb8082/demos/img/lizard.jpg -------------------------------------------------------------------------------- /demos/test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | FocusPoint Tests 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 57 | 58 | 59 | 60 | 61 |

FocusPoint Tests » Project Home

62 | 63 |
68 | 69 | Default behaviour 70 |
71 | 72 |
75 | 76 | Missing image-w and image-h 77 |
78 | 79 |
84 | 85 | Slow redraw (high throttleDuration) 86 |
87 | 88 |
93 | 94 | No throttling 95 |
96 | 97 |
102 | 103 | Don't adjust on window resize 104 | » Adjust Focus 105 | » Adjust Focus (old method) 106 | » Window On 107 | » Window Off 108 | 109 |
110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /demos/test/test.css: -------------------------------------------------------------------------------- 1 | /* !CONTAINERS */ 2 | /*-----------------------------------------*/ 3 | 4 | .focuspoint { 5 | height: 200px; 6 | margin-bottom: 20px; 7 | } 8 | .focuspoint .label { 9 | position: absolute; 10 | left: 0; 11 | bottom: 0; 12 | right: 0; 13 | padding: 5px; 14 | background: rgba(0,0,0,0.5); 15 | color: #fff; 16 | } -------------------------------------------------------------------------------- /focuspoint.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "focuspoint", 3 | "title": "jQuery FocusPoint", 4 | "description": "jQuery plugin for 'responsive cropping'. Dynamically crop images to fill available space without cutting out the image's subject. Great for full-screen images.", 5 | "keywords": [ 6 | "crop", 7 | "cropping", 8 | "image", 9 | "responsive", 10 | "fill", 11 | "background", 12 | "full-screen", 13 | "focus", 14 | "focuspoint" 15 | ], 16 | "version": "1.1.1", 17 | "author": { 18 | "name": "Jonathon Menz", 19 | "url": "http://jonathonmenz.com" 20 | }, 21 | "licenses": [ 22 | { 23 | "type": "MIT", 24 | "url": "https://github.com/jonom/jquery-focuspoint/blob/1.1.1/MIT-LICENSE.txt" 25 | } 26 | ], 27 | "bugs": "https://github.com/jonom/jquery-focuspoint/issues", 28 | "homepage": "https://github.com/jonom/jquery-focuspoint", 29 | "demo": "http://jonom.github.io/jquery-focuspoint/demos/grid/lizard.html", 30 | "dependencies": { 31 | "jquery": ">=1.9" 32 | } 33 | } -------------------------------------------------------------------------------- /js/jquery.focuspoint.helper-basic.js: -------------------------------------------------------------------------------- 1 | //Get focus point coordinates from an image - adapt to suit your needs. 2 | 3 | (function($) { 4 | $(document).ready(function() { 5 | 6 | $('img').click(function(e){ 7 | 8 | var imageW = $(this).width(); 9 | var imageH = $(this).height(); 10 | 11 | //Calculate FocusPoint coordinates 12 | var offsetX = e.pageX - $(this).offset().left; 13 | var offsetY = e.pageY - $(this).offset().top; 14 | var focusX = (offsetX/imageW - .5)*2; 15 | var focusY = (offsetY/imageH - .5)*-2; 16 | 17 | //Calculate CSS Percentages 18 | var percentageX = (offsetX/imageW)*100; 19 | var percentageY = (offsetY/imageH)*100; 20 | var backgroundPosition = percentageX.toFixed(0) + '% ' + percentageY.toFixed(0) + '%'; 21 | var backgroundPositionCSS = 'background-position: ' + backgroundPosition + ';'; 22 | 23 | window.alert('FocusX:' + focusX.toFixed(2) + ', FocusY:' + focusY.toFixed(2) + ' (For CSS version: ' + backgroundPositionCSS + ')'); 24 | 25 | }); 26 | 27 | }); 28 | }(jQuery)); -------------------------------------------------------------------------------- /js/jquery.focuspoint.helpertool.js: -------------------------------------------------------------------------------- 1 | // Gets focus point coordinates from an image - adapt to suit your needs. 2 | 3 | (function($) { 4 | $(document).ready(function() { 5 | 6 | var defaultImage; 7 | var $dataAttrInput; 8 | var $cssAttrInput; 9 | var $focusPointContainers; 10 | var $focusPointImages; 11 | var $helperToolImage; 12 | 13 | //This stores focusPoint's data-attribute values 14 | var focusPointAttr = { 15 | x: 0, 16 | y: 0, 17 | w: 0, 18 | h: 0 19 | }; 20 | 21 | //Initialize Helper Tool 22 | (function() { 23 | 24 | //Initialize Variables 25 | defaultImage = '../img/city_from_unsplash.jpg'; 26 | $dataAttrInput = $('.helper-tool-data-attr'); 27 | $cssAttrInput = $('.helper-tool-css3-val'); 28 | $helperToolImage = $('img.helper-tool-img, img.target-overlay'); 29 | 30 | //Create Grid Elements 31 | for(var i = 1; i < 10; i++) { 32 | $('#Frames').append('
'); 33 | } 34 | //Store focus point containers 35 | $focusPointContainers = $('.focuspoint'); 36 | $focusPointImages = $('.focuspoint img'); 37 | 38 | //Set the default source image 39 | setImage( defaultImage ); 40 | 41 | })(); 42 | 43 | /*-----------------------------------------*/ 44 | 45 | // function setImage() 46 | // Set a new image to use in the demo, requires URI to an image 47 | 48 | /*-----------------------------------------*/ 49 | 50 | function setImage(imgURL) { 51 | //Get the dimensions of the image by referencing an image stored in memory 52 | $("") 53 | .attr("src", imgURL) 54 | .load(function() { 55 | focusPointAttr.w = this.width; 56 | focusPointAttr.h = this.height; 57 | 58 | //Set src on the thumbnail used in the GUI 59 | $helperToolImage.attr('src', imgURL); 60 | 61 | //Set src on all .focuspoint images 62 | $focusPointImages.attr('src', imgURL); 63 | 64 | //Set up initial properties of .focuspoint containers 65 | 66 | /*-----------------------------------------*/ 67 | // Note --- 68 | // Setting these up with attr doesn't really make a difference 69 | // added to demo only so changes are made visually in the dom 70 | // for users inspecting it. Because of how FocusPoint uses .data() 71 | // only the .data() assignments that follow are necessary. 72 | /*-----------------------------------------*/ 73 | $focusPointContainers.attr({ 74 | 'data-focus-x':focusPointAttr.x, 75 | 'data-focus-y':focusPointAttr.y, 76 | 'data-image-w': focusPointAttr.w, 77 | 'data-image-h': focusPointAttr.h 78 | }); 79 | 80 | /*-----------------------------------------*/ 81 | // These assignments using .data() are what counts. 82 | /*-----------------------------------------*/ 83 | $focusPointContainers.data('focusX', focusPointAttr.x); 84 | $focusPointContainers.data('focusY', focusPointAttr.y); 85 | $focusPointContainers.data('imageW', focusPointAttr.w); 86 | $focusPointContainers.data('imageH', focusPointAttr.h); 87 | 88 | //Run FocusPoint for the first time. 89 | $('.focuspoint').focusPoint(); 90 | 91 | //Update the data attributes shown to the user 92 | printDataAttr(); 93 | 94 | }); 95 | } 96 | 97 | /*-----------------------------------------*/ 98 | 99 | // Update the data attributes shown to the user 100 | 101 | /*-----------------------------------------*/ 102 | 103 | function printDataAttr(){ 104 | $dataAttrInput.val('data-focus-x="'+focusPointAttr.x.toFixed(2)+'" data-focus-y="'+focusPointAttr.y.toFixed(2)+'" data-image-w="'+focusPointAttr.w+'" data-image-h="'+focusPointAttr.h+'"'); 105 | } 106 | 107 | /*-----------------------------------------*/ 108 | 109 | // Bind to helper image click event 110 | // Adjust focus on Click / provides focuspoint and CSS3 properties 111 | 112 | /*-----------------------------------------*/ 113 | 114 | $helperToolImage.click(function(e){ 115 | 116 | var imageW = $(this).width(); 117 | var imageH = $(this).height(); 118 | 119 | //Calculate FocusPoint coordinates 120 | var offsetX = e.pageX - $(this).offset().left; 121 | var offsetY = e.pageY - $(this).offset().top; 122 | var focusX = (offsetX/imageW - .5)*2; 123 | var focusY = (offsetY/imageH - .5)*-2; 124 | focusPointAttr.x = focusX; 125 | focusPointAttr.y = focusY; 126 | 127 | //Write values to input 128 | printDataAttr(); 129 | 130 | //Update focus point 131 | updateFocusPoint(); 132 | 133 | //Calculate CSS Percentages 134 | var percentageX = (offsetX/imageW)*100; 135 | var percentageY = (offsetY/imageH)*100; 136 | var backgroundPosition = percentageX.toFixed(0) + '% ' + percentageY.toFixed(0) + '%'; 137 | var backgroundPositionCSS = 'background-position: ' + backgroundPosition + ';'; 138 | $cssAttrInput.val(backgroundPositionCSS); 139 | 140 | //Leave a sweet target reticle at the focus point. 141 | $('.reticle').css({ 142 | 'top':percentageY+'%', 143 | 'left':percentageX+'%' 144 | }); 145 | }); 146 | 147 | /*-----------------------------------------*/ 148 | 149 | // Change image on paste/blur 150 | // When you paste an image into the specified input, it will be used for the demo 151 | 152 | /*-----------------------------------------*/ 153 | 154 | $('input.helper-tool-set-src').on('paste blur', function(e){ 155 | var element = this; 156 | setTimeout(function () { 157 | var text = $(element).val(); 158 | setImage(text); 159 | }, 100); 160 | }); 161 | 162 | /*-----------------------------------------*/ 163 | 164 | /* Update Helper */ 165 | // This function is used to update the focuspoint 166 | 167 | /*-----------------------------------------*/ 168 | 169 | function updateFocusPoint(){ 170 | /*-----------------------------------------*/ 171 | // See note in setImage() function regarding these attribute assignments. 172 | //TLDR - You don't need them for this to work. 173 | /*-----------------------------------------*/ 174 | $focusPointContainers.attr({ 175 | 'data-focus-x': focusPointAttr.x, 176 | 'data-focus-y': focusPointAttr.y 177 | }); 178 | /*-----------------------------------------*/ 179 | // These you DO need :) 180 | /*-----------------------------------------*/ 181 | $focusPointContainers.data('focusX', focusPointAttr.x); 182 | $focusPointContainers.data('focusY', focusPointAttr.y); 183 | $focusPointContainers.adjustFocus(); 184 | }; 185 | }); 186 | }(jQuery)); -------------------------------------------------------------------------------- /js/jquery.focuspoint.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery FocusPoint; version: 1.1.3 3 | * Author: http://jonathonmenz.com 4 | * Source: https://github.com/jonom/jquery-focuspoint 5 | * Copyright (c) 2014 J. Menz; MIT License 6 | * @preserve 7 | */ 8 | ; 9 | (function($) { 10 | 11 | var defaults = { 12 | reCalcOnWindowResize: true, 13 | throttleDuration: 17 //ms - set to 0 to disable throttling 14 | }; 15 | 16 | //Setup a container instance 17 | var setupContainer = function($el) { 18 | var imageSrc = $el.find('img').attr('src'); 19 | $el.data('imageSrc', imageSrc); 20 | 21 | resolveImageSize(imageSrc, function(err, dim) { 22 | $el.data({ 23 | imageW: dim.width, 24 | imageH: dim.height 25 | }); 26 | adjustFocus($el); 27 | }); 28 | }; 29 | 30 | //Get the width and the height of an image 31 | //by creating a new temporary image 32 | var resolveImageSize = function(src, cb) { 33 | //Create a new image and set a 34 | //handler which listens to the first 35 | //call of the 'load' event. 36 | $('').one('load', function() { 37 | //'this' references to the new 38 | //created image 39 | cb(null, { 40 | width: this.width, 41 | height: this.height 42 | }); 43 | }).attr('src', src); 44 | }; 45 | 46 | //Create a throttled version of a function 47 | var throttle = function(fn, ms) { 48 | var isRunning = false; 49 | return function() { 50 | var args = Array.prototype.slice.call(arguments, 0); 51 | if (isRunning) return false; 52 | isRunning = true; 53 | setTimeout(function() { 54 | isRunning = false; 55 | fn.apply(null, args); 56 | }, ms); 57 | }; 58 | }; 59 | 60 | //Calculate the new left/top values of an image 61 | var calcShift = function(conToImageRatio, containerSize, imageSize, focusSize, toMinus) { 62 | var containerCenter = Math.floor(containerSize / 2); //Container center in px 63 | var focusFactor = (focusSize + 1) / 2; //Focus point of resize image in px 64 | var scaledImage = Math.floor(imageSize / conToImageRatio); //Can't use width() as images may be display:none 65 | var focus = Math.floor(focusFactor * scaledImage); 66 | if (toMinus) focus = scaledImage - focus; 67 | var focusOffset = focus - containerCenter; //Calculate difference between focus point and center 68 | var remainder = scaledImage - focus; //Reduce offset if necessary so image remains filled 69 | var containerRemainder = containerSize - containerCenter; 70 | if (remainder < containerRemainder) focusOffset -= containerRemainder - remainder; 71 | if (focusOffset < 0) focusOffset = 0; 72 | 73 | return (focusOffset * -100 / containerSize) + '%'; 74 | }; 75 | 76 | //Re-adjust the focus 77 | var adjustFocus = function($el) { 78 | var imageW = $el.data('imageW'); 79 | var imageH = $el.data('imageH'); 80 | var imageSrc = $el.data('imageSrc'); 81 | 82 | if (!imageW && !imageH && !imageSrc) { 83 | return setupContainer($el); //Setup the container first 84 | } 85 | 86 | var containerW = $el.width(); 87 | var containerH = $el.height(); 88 | var focusX = parseFloat($el.data('focusX')); 89 | var focusY = parseFloat($el.data('focusY')); 90 | var $image = $el.find('img').first(); 91 | 92 | //Amount position will be shifted 93 | var hShift = 0; 94 | var vShift = 0; 95 | 96 | if (!(containerW > 0 && containerH > 0 && imageW > 0 && imageH > 0)) { 97 | return false; //Need dimensions to proceed 98 | } 99 | 100 | //Which is over by more? 101 | var wR = imageW / containerW; 102 | var hR = imageH / containerH; 103 | 104 | //Reset max-width and -height 105 | $image.css({ 106 | 'max-width': '', 107 | 'max-height': '' 108 | }); 109 | 110 | //Minimize image while still filling space 111 | if (imageW > containerW && imageH > containerH) { 112 | $image.css((wR > hR) ? 'max-height' : 'max-width', '100%'); 113 | } 114 | 115 | if (wR > hR) { 116 | hShift = calcShift(hR, containerW, imageW, focusX); 117 | } else if (wR < hR) { 118 | vShift = calcShift(wR, containerH, imageH, focusY, true); 119 | } 120 | 121 | $image.css({ 122 | top: vShift, 123 | left: hShift 124 | }); 125 | }; 126 | 127 | var $window = $(window); 128 | 129 | var focusPoint = function($el, settings) { 130 | var thrAdjustFocus = settings.throttleDuration ? 131 | throttle(function(){adjustFocus($el);}, settings.throttleDuration) 132 | : function(){adjustFocus($el);};//Only throttle when desired 133 | var isListening = false; 134 | 135 | adjustFocus($el); //Focus image in container 136 | 137 | //Expose a public API 138 | return { 139 | 140 | adjustFocus: function() { 141 | return adjustFocus($el); 142 | }, 143 | 144 | windowOn: function() { 145 | if (isListening) return; 146 | //Recalculate each time the window is resized 147 | $window.on('resize', thrAdjustFocus); 148 | return isListening = true; 149 | }, 150 | 151 | windowOff: function() { 152 | if (!isListening) return; 153 | //Stop listening to the resize event 154 | $window.off('resize', thrAdjustFocus); 155 | isListening = false; 156 | return true; 157 | } 158 | 159 | }; 160 | }; 161 | 162 | $.fn.focusPoint = function(optionsOrMethod) { 163 | //Shortcut to functions - if string passed assume method name and execute 164 | if (typeof optionsOrMethod === 'string') { 165 | return this.each(function() { 166 | var $el = $(this); 167 | $el.data('focusPoint')[optionsOrMethod](); 168 | }); 169 | } 170 | //Otherwise assume options being passed and setup 171 | var settings = $.extend({}, defaults, optionsOrMethod); 172 | return this.each(function() { 173 | var $el = $(this); 174 | var fp = focusPoint($el, settings); 175 | //Stop the resize event of any previous attached 176 | //focusPoint instances 177 | if ($el.data('focusPoint')) $el.data('focusPoint').windowOff(); 178 | $el.data('focusPoint', fp); 179 | if (settings.reCalcOnWindowResize) fp.windowOn(); 180 | }); 181 | 182 | }; 183 | 184 | $.fn.adjustFocus = function() { 185 | //Deprecated v1.2 186 | return this.each(function() { 187 | adjustFocus($(this)); 188 | }); 189 | }; 190 | 191 | })(jQuery); -------------------------------------------------------------------------------- /js/jquery.focuspoint.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery FocusPoint; version: 1.1.3 3 | * Author: http://jonathonmenz.com 4 | * Source: https://github.com/jonom/jquery-focuspoint 5 | * Copyright (c) 2014 J. Menz; MIT License 6 | * @preserve 7 | */ 8 | !function($){var t={reCalcOnWindowResize:!0,throttleDuration:17},n=function(t){var n=t.find("img").attr("src");t.data("imageSrc",n),i(n,function(n,i){t.data({imageW:i.width,imageH:i.height}),r(t)})},i=function(t,n){$("").one("load",function(){n(null,{width:this.width,height:this.height})}).attr("src",t)},a=function(t,n){var i=!1;return function(){var a=Array.prototype.slice.call(arguments,0);if(i)return!1;i=!0,setTimeout(function(){i=!1,t.apply(null,a)},n)}},o=function(t,n,i,a,o){var r=Math.floor(n/2),e=(a+1)/2,u=Math.floor(i/t),f=Math.floor(e*u);o&&(f=u-f);var c=f-r,s=u-f,h=n-r;return s0&&u>0&&i>0&&a>0))return!1;var l=i/e,w=a/u;s.css({"max-width":"","max-height":""}),i>e&&a>u&&s.css(l>w?"max-height":"max-width","100%"),l>w?h=o(w,e,i,f):l0&&t-1 in e)}function r(e){var t=Tt[e]={};return st.each(e.match(lt)||[],function(e,n){t[n]=!0}),t}function i(e,n,r,i){if(st.acceptData(e)){var o,a,s=st.expando,u="string"==typeof n,l=e.nodeType,c=l?st.cache:e,f=l?e[s]:e[s]&&s;if(f&&c[f]&&(i||c[f].data)||!u||r!==t)return f||(l?e[s]=f=K.pop()||st.guid++:f=s),c[f]||(c[f]={},l||(c[f].toJSON=st.noop)),("object"==typeof n||"function"==typeof n)&&(i?c[f]=st.extend(c[f],n):c[f].data=st.extend(c[f].data,n)),o=c[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[st.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[st.camelCase(n)])):a=o,a}}function o(e,t,n){if(st.acceptData(e)){var r,i,o,a=e.nodeType,u=a?st.cache:e,l=a?e[st.expando]:st.expando;if(u[l]){if(t&&(r=n?u[l]:u[l].data)){st.isArray(t)?t=t.concat(st.map(t,st.camelCase)):t in r?t=[t]:(t=st.camelCase(t),t=t in r?[t]:t.split(" "));for(i=0,o=t.length;o>i;i++)delete r[t[i]];if(!(n?s:st.isEmptyObject)(r))return}(n||(delete u[l].data,s(u[l])))&&(a?st.cleanData([e],!0):st.support.deleteExpando||u!=u.window?delete u[l]:u[l]=null)}}}function a(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(Nt,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:wt.test(r)?st.parseJSON(r):r}catch(o){}st.data(e,n,r)}else r=t}return r}function s(e){var t;for(t in e)if(("data"!==t||!st.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function u(){return!0}function l(){return!1}function c(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function f(e,t,n){if(t=t||0,st.isFunction(t))return st.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return st.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=st.grep(e,function(e){return 1===e.nodeType});if(Wt.test(t))return st.filter(t,r,!n);t=st.filter(t,r)}return st.grep(e,function(e){return st.inArray(e,t)>=0===n})}function p(e){var t=zt.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function d(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function h(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function g(e){var t=nn.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function m(e,t){for(var n,r=0;null!=(n=e[r]);r++)st._data(n,"globalEval",!t||st._data(t[r],"globalEval"))}function y(e,t){if(1===t.nodeType&&st.hasData(e)){var n,r,i,o=st._data(e),a=st._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)st.event.add(t,n,s[n][r])}a.data&&(a.data=st.extend({},a.data))}}function v(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!st.support.noCloneEvent&&t[st.expando]){r=st._data(t);for(i in r.events)st.removeEvent(t,i,r.handle);t.removeAttribute(st.expando)}"script"===n&&t.text!==e.text?(h(t).text=e.text,g(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),st.support.html5Clone&&e.innerHTML&&!st.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Zt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}function b(e,n){var r,i,o=0,a=e.getElementsByTagName!==t?e.getElementsByTagName(n||"*"):e.querySelectorAll!==t?e.querySelectorAll(n||"*"):t;if(!a)for(a=[],r=e.childNodes||e;null!=(i=r[o]);o++)!n||st.nodeName(i,n)?a.push(i):st.merge(a,b(i,n));return n===t||n&&st.nodeName(e,n)?st.merge([e],a):a}function x(e){Zt.test(e.type)&&(e.defaultChecked=e.checked)}function T(e,t){if(t in e)return t;for(var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Nn.length;i--;)if(t=Nn[i]+n,t in e)return t;return r}function w(e,t){return e=t||e,"none"===st.css(e,"display")||!st.contains(e.ownerDocument,e)}function N(e,t){for(var n,r=[],i=0,o=e.length;o>i;i++)n=e[i],n.style&&(r[i]=st._data(n,"olddisplay"),t?(r[i]||"none"!==n.style.display||(n.style.display=""),""===n.style.display&&w(n)&&(r[i]=st._data(n,"olddisplay",S(n.nodeName)))):r[i]||w(n)||st._data(n,"olddisplay",st.css(n,"display")));for(i=0;o>i;i++)n=e[i],n.style&&(t&&"none"!==n.style.display&&""!==n.style.display||(n.style.display=t?r[i]||"":"none"));return e}function C(e,t,n){var r=mn.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function k(e,t,n,r,i){for(var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;4>o;o+=2)"margin"===n&&(a+=st.css(e,n+wn[o],!0,i)),r?("content"===n&&(a-=st.css(e,"padding"+wn[o],!0,i)),"margin"!==n&&(a-=st.css(e,"border"+wn[o]+"Width",!0,i))):(a+=st.css(e,"padding"+wn[o],!0,i),"padding"!==n&&(a+=st.css(e,"border"+wn[o]+"Width",!0,i)));return a}function E(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=ln(e),a=st.support.boxSizing&&"border-box"===st.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=un(e,t,o),(0>i||null==i)&&(i=e.style[t]),yn.test(i))return i;r=a&&(st.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+k(e,t,n||(a?"border":"content"),r,o)+"px"}function S(e){var t=V,n=bn[e];return n||(n=A(e,t),"none"!==n&&n||(cn=(cn||st("