carrierwave-crop 0.0.10.alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +108 -0
- data/Rakefile +6 -0
- data/carrierwave-crop.gemspec +28 -0
- data/lib/carrierwave/crop.rb +8 -0
- data/lib/carrierwave/crop/engine.rb +6 -0
- data/lib/carrierwave/crop/helpers.rb +46 -0
- data/lib/carrierwave/crop/model_additions.rb +67 -0
- data/lib/carrierwave/crop/railtie.rb +12 -0
- data/lib/carrierwave/crop/version.rb +5 -0
- data/lib/generators/cropper_generator.rb +12 -0
- data/lib/generators/templates/carrierwave_cropper.js.coffee +24 -0
- data/spec/crop/model_additions_spec.rb +12 -0
- data/spec/crop_spec.rb +2 -0
- data/spec/spec_helper.rb +2 -0
- data/vendor/assets/images/Jcrop.gif +0 -0
- data/vendor/assets/javascripts/jquery.jcrop.js +1694 -0
- data/vendor/assets/stylesheets/jquery.jcrop.css +165 -0
- metadata +161 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 55ff6ba0e684d207e2b8cc074245062fbea34a12
|
4
|
+
data.tar.gz: 3f78cf5b312a14017b60cd348feb1eb68e3c1286
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 86275835d5512a8326a708ba9cc8327de4260b291572f22655dd4eebc2e02b6e5aa9d170f5ed8e99318b341b31ee03a3aa01408af809c58c4a7613243a99861d
|
7
|
+
data.tar.gz: 1a200f12c4be8c3da9c3c58d69274865f29f6457b21a44267bf71435dbb08a7ff22c998b285f4ea07becc64ba9ad9ac8019a1108d9ab1a8d8cc329d38b2da9a9
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 kirtithorat
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# Carrierwave-Crop
|
2
|
+
|
3
|
+
[](https://travis-ci.org/kirtithorat/carrierwave-crop)
|
4
|
+
|
5
|
+
Carrierwave extension to crop uploaded images using Jcrop plugin with preview.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Install the latest stable release:
|
10
|
+
|
11
|
+
$[sudo] gem install carrierwave
|
12
|
+
|
13
|
+
In Rails, add it to your Gemfile:
|
14
|
+
|
15
|
+
gem 'carrierwave-crop'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Finally, restart the server to apply the changes.
|
22
|
+
|
23
|
+
## Getting Started
|
24
|
+
|
25
|
+
Add the required files in assets
|
26
|
+
|
27
|
+
In `application.js`
|
28
|
+
|
29
|
+
//= require jquery
|
30
|
+
//= require jquery.jcrop
|
31
|
+
|
32
|
+
In `application.css`
|
33
|
+
|
34
|
+
*= require jquery.jcrop
|
35
|
+
|
36
|
+
Generate a coffeescript for cropping:
|
37
|
+
|
38
|
+
rails generate cropper user avatar
|
39
|
+
|
40
|
+
this should give you a file in:
|
41
|
+
|
42
|
+
app/assets/javascripts/users.js.coffee
|
43
|
+
|
44
|
+
## Usage
|
45
|
+
|
46
|
+
Open your model file and add the cropper:
|
47
|
+
|
48
|
+
class User < ActiveRecord::Base
|
49
|
+
mount_uploader :avatar, AvatarUploader
|
50
|
+
crop_uploaded :avatar ## Add this
|
51
|
+
end
|
52
|
+
|
53
|
+
Render a view after creating/updating a user, add a `crop` action in your `controller.` For example:
|
54
|
+
|
55
|
+
def create
|
56
|
+
@user = User.new(user_params)
|
57
|
+
respond_to do |format|
|
58
|
+
if @user.save
|
59
|
+
format.html {
|
60
|
+
if params[:user][:avatar].present?
|
61
|
+
render :crop ## Render the view for cropping
|
62
|
+
else
|
63
|
+
redirect_to @user, notice: 'User was successfully created.'
|
64
|
+
end
|
65
|
+
}
|
66
|
+
format.json { render action: 'show', status: :created, location: @user }
|
67
|
+
else
|
68
|
+
format.html { render action: 'new' }
|
69
|
+
format.json { render json: @user.errors, status: :unprocessable_entity }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
For `Rails 4.x`, whitelist the cropping attributes - `fieldname_crop_x`, `fieldname_crop_y`, `fieldname_crop_w`, `fieldname_crop_h`.
|
75
|
+
|
76
|
+
For example:
|
77
|
+
|
78
|
+
def user_params
|
79
|
+
params.require(:user).permit(:avatar_crop_x, :avatar_crop_y, :avatar_crop_w, :avatar_crop_h, ....)
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
In the view, say `crop.html.erb`:
|
84
|
+
|
85
|
+
<%= form_for @user do |f| %>
|
86
|
+
<%= f.cropbox :avatar %>
|
87
|
+
<%= f.cropped_preview :avatar %>
|
88
|
+
<%= f.submit 'Crop' %>
|
89
|
+
<% end %>
|
90
|
+
|
91
|
+
In the carrierwave uploader, say `AvatarUploader`:
|
92
|
+
|
93
|
+
Call process on the version you would like to be cropped:
|
94
|
+
|
95
|
+
## If ONLY "thumb" version is to be cropped
|
96
|
+
version :jumbo do
|
97
|
+
resize_to_limit(600,600)
|
98
|
+
end
|
99
|
+
|
100
|
+
version :thumb do
|
101
|
+
process crop: :avatar ## Add this
|
102
|
+
resize_to_limit(100,100)
|
103
|
+
end
|
104
|
+
|
105
|
+
### Credits and resources
|
106
|
+
* [Carrierwave](https://github.com/carrierwaveuploader/carrierwave)
|
107
|
+
* [Deep Liquid's JCrop](http://deepliquid.com/content/Jcrop.html)
|
108
|
+
* And Ryan Bates [Railscast#182](http://railscasts.com/episodes/182-cropping-images/)
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'carrierwave/crop/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "carrierwave-crop"
|
8
|
+
spec.version = Carrierwave::Crop::VERSION
|
9
|
+
spec.authors = ["kirtithorat"]
|
10
|
+
spec.email = ["kirti.brenz@gmail.com"]
|
11
|
+
spec.summary = %q{Carrierwave extension for cropping images with preview.}
|
12
|
+
spec.description = %q{Carrierwave extension to crop uploaded images using Jcrop plugin.}
|
13
|
+
spec.homepage = "https://github.com/kirtithorat/carrierwave-crop"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split("\n")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "rails", ">= 3.1"
|
22
|
+
spec.add_dependency "jquery-rails"
|
23
|
+
spec.add_dependency "carrierwave", [">= 0.8.0", "< 0.11.0"]
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Carrierwave
|
2
|
+
module Crop
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
def cropped_preview(attachment, opts = {})
|
6
|
+
attachment = attachment.to_sym
|
7
|
+
width = opts[:width] || 100
|
8
|
+
height = (width / 1).round
|
9
|
+
|
10
|
+
if(self.object.send(attachment).class.ancestors.include? CarrierWave::Uploader::Base )
|
11
|
+
wrapper_options = {
|
12
|
+
:id => "#{attachment}_crop_preview_wrapper",
|
13
|
+
:style => "width:#{width}px; height:#{height}px; overflow:hidden"
|
14
|
+
}
|
15
|
+
|
16
|
+
preview_image = @template.image_tag(self.object.send(attachment).url, :id => "#{attachment}_crop_preview")
|
17
|
+
|
18
|
+
@template.content_tag(:div, preview_image, wrapper_options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def cropbox(attachment, opts={})
|
24
|
+
attachment = attachment.to_sym
|
25
|
+
|
26
|
+
if(self.object.send(attachment).class.ancestors.include? CarrierWave::Uploader::Base )
|
27
|
+
box = self.hidden_field(:"#{attachment}_crop_x", id: "#{self.object.class.name.downcase}_#{attachment}_crop_x")
|
28
|
+
[:crop_y, :crop_w, :crop_h].each do |attribute|
|
29
|
+
box << self.hidden_field(:"#{attachment}_#{attribute}", id: "#{self.object.class.name.downcase}_#{attachment}_#{attribute}")
|
30
|
+
end
|
31
|
+
|
32
|
+
crop_image = @template.image_tag(self.object.send(attachment).url, :id => "#{self.object.class.name.downcase}_#{attachment}_cropbox")
|
33
|
+
|
34
|
+
box << @template.content_tag(:div, crop_image)
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
if defined? ActionView::Helpers::FormBuilder
|
43
|
+
ActionView::Helpers::FormBuilder.class_eval do
|
44
|
+
include Carrierwave::Crop::Helpers
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Carrierwave
|
2
|
+
module Crop
|
3
|
+
module ModelAdditions
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
## Adding dynamic attribute accessors
|
8
|
+
def crop_uploaded(attachment)
|
9
|
+
|
10
|
+
[:crop_x, :crop_y, :crop_w, :crop_h].each do |a|
|
11
|
+
attr_accessor :"#{attachment}_#{a}"
|
12
|
+
end
|
13
|
+
after_update :"recreate_#{attachment}_versions"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module InstanceMethods
|
18
|
+
|
19
|
+
def cropping?(attachment)
|
20
|
+
!self.send(:"#{attachment}_crop_x").blank? &&
|
21
|
+
!self.send(:"#{attachment}_crop_y").blank? &&
|
22
|
+
!self.send(:"#{attachment}_crop_w").blank? &&
|
23
|
+
!self.send(:"#{attachment}_crop_h").blank?
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(method, *args)
|
27
|
+
if method.to_s =~ /recreate_(\S{1,})_versions/
|
28
|
+
crop_image(method.to_s.scan(/recreate_(\S{1,})_versions/).flatten.first.to_sym)
|
29
|
+
else
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def crop_image(attachment)
|
35
|
+
if cropping?(attachment)
|
36
|
+
attachment_instance = send(attachment)
|
37
|
+
attachment_instance.recreate_versions!
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module Uploader
|
45
|
+
|
46
|
+
def crop(attachment)
|
47
|
+
if model.cropping?(attachment)
|
48
|
+
resize_to_limit(600, 600)
|
49
|
+
manipulate! do |img|
|
50
|
+
x = model.send("#{attachment}_crop_x").to_i
|
51
|
+
y = model.send("#{attachment}_crop_y").to_i
|
52
|
+
w = model.send("#{attachment}_crop_w").to_i
|
53
|
+
h = model.send("#{attachment}_crop_h").to_i
|
54
|
+
img.crop!(x, y, w, h)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
if defined? CarrierWave::Uploader::Base
|
64
|
+
CarrierWave::Uploader::Base.class_eval do
|
65
|
+
include Carrierwave::Crop::Uploader
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class CropperGenerator < Rails::Generators::NamedBase
|
2
|
+
source_root File.expand_path("../templates", __FILE__)
|
3
|
+
|
4
|
+
desc "This generator creates a cropper file at app/assets/javascripts"
|
5
|
+
|
6
|
+
argument :attachment_name, :required => true, :type => :string, :desc => "The names of the attachment to crop.",
|
7
|
+
:banner => "attachment_name"
|
8
|
+
|
9
|
+
def create_cropper_file
|
10
|
+
template "carrierwave_cropper.js.coffee", File.join('app/assets/javascripts', class_path, "#{file_name.pluralize}.js.coffee")
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
jQuery ->
|
2
|
+
new CarrierwaveCropper()
|
3
|
+
|
4
|
+
class CarrierwaveCropper
|
5
|
+
constructor: ->
|
6
|
+
$('#<%= file_name %>_<%= attachment_name %>_cropbox').Jcrop
|
7
|
+
aspectRatio: 1
|
8
|
+
setSelect: [0, 0, 200, 200]
|
9
|
+
onSelect: @update
|
10
|
+
onChange: @update
|
11
|
+
|
12
|
+
update: (coords) =>
|
13
|
+
$('#<%= file_name %>_<%= attachment_name %>_crop_x').val(coords.x)
|
14
|
+
$('#<%= file_name %>_<%= attachment_name %>_crop_y').val(coords.y)
|
15
|
+
$('#<%= file_name %>_<%= attachment_name %>_crop_w').val(coords.w)
|
16
|
+
$('#<%= file_name %>_<%= attachment_name %>_crop_h').val(coords.h)
|
17
|
+
@updatePreview(coords)
|
18
|
+
|
19
|
+
updatePreview: (coords) =>
|
20
|
+
$('#avatar_crop_preview').css
|
21
|
+
width: Math.round(100/coords.w * $('#<%= file_name %>_<%= attachment_name %>_cropbox').width()) + 'px'
|
22
|
+
height: Math.round(100/coords.h * $('#<%= file_name %>_<%= attachment_name %>_cropbox').height()) + 'px'
|
23
|
+
marginLeft: '-' + Math.round(100/coords.w * coords.x) + 'px'
|
24
|
+
marginTop: '-' + Math.round(100/coords.h * coords.y) + 'px'
|
data/spec/crop_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
Binary file
|
@@ -0,0 +1,1694 @@
|
|
1
|
+
/**
|
2
|
+
* jquery.Jcrop.js v0.9.12
|
3
|
+
* jQuery Image Cropping Plugin - released under MIT License
|
4
|
+
* Author: Kelly Hallman <khallman@gmail.com>
|
5
|
+
* http://github.com/tapmodo/Jcrop
|
6
|
+
* Copyright (c) 2008-2013 Tapmodo Interactive LLC {{{
|
7
|
+
*
|
8
|
+
* Permission is hereby granted, free of charge, to any person
|
9
|
+
* obtaining a copy of this software and associated documentation
|
10
|
+
* files (the "Software"), to deal in the Software without
|
11
|
+
* restriction, including without limitation the rights to use,
|
12
|
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
13
|
+
* copies of the Software, and to permit persons to whom the
|
14
|
+
* Software is furnished to do so, subject to the following
|
15
|
+
* conditions:
|
16
|
+
*
|
17
|
+
* The above copyright notice and this permission notice shall be
|
18
|
+
* included in all copies or substantial portions of the Software.
|
19
|
+
*
|
20
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
21
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
22
|
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
23
|
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
24
|
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
25
|
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
26
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
27
|
+
* OTHER DEALINGS IN THE SOFTWARE.
|
28
|
+
*
|
29
|
+
* }}}
|
30
|
+
*/
|
31
|
+
|
32
|
+
(function ($) {
|
33
|
+
|
34
|
+
$.Jcrop = function (obj, opt) {
|
35
|
+
var options = $.extend({}, $.Jcrop.defaults),
|
36
|
+
docOffset,
|
37
|
+
_ua = navigator.userAgent.toLowerCase(),
|
38
|
+
is_msie = /msie/.test(_ua),
|
39
|
+
ie6mode = /msie [1-6]\./.test(_ua);
|
40
|
+
|
41
|
+
// Internal Methods {{{
|
42
|
+
function px(n) {
|
43
|
+
return Math.round(n) + 'px';
|
44
|
+
}
|
45
|
+
function cssClass(cl) {
|
46
|
+
return options.baseClass + '-' + cl;
|
47
|
+
}
|
48
|
+
function supportsColorFade() {
|
49
|
+
return $.fx.step.hasOwnProperty('backgroundColor');
|
50
|
+
}
|
51
|
+
function getPos(obj) //{{{
|
52
|
+
{
|
53
|
+
var pos = $(obj).offset();
|
54
|
+
return [pos.left, pos.top];
|
55
|
+
}
|
56
|
+
//}}}
|
57
|
+
function mouseAbs(e) //{{{
|
58
|
+
{
|
59
|
+
return [(e.pageX - docOffset[0]), (e.pageY - docOffset[1])];
|
60
|
+
}
|
61
|
+
//}}}
|
62
|
+
function setOptions(opt) //{{{
|
63
|
+
{
|
64
|
+
if (typeof(opt) !== 'object') opt = {};
|
65
|
+
options = $.extend(options, opt);
|
66
|
+
|
67
|
+
$.each(['onChange','onSelect','onRelease','onDblClick'],function(i,e) {
|
68
|
+
if (typeof(options[e]) !== 'function') options[e] = function () {};
|
69
|
+
});
|
70
|
+
}
|
71
|
+
//}}}
|
72
|
+
function startDragMode(mode, pos, touch) //{{{
|
73
|
+
{
|
74
|
+
docOffset = getPos($img);
|
75
|
+
Tracker.setCursor(mode === 'move' ? mode : mode + '-resize');
|
76
|
+
|
77
|
+
if (mode === 'move') {
|
78
|
+
return Tracker.activateHandlers(createMover(pos), doneSelect, touch);
|
79
|
+
}
|
80
|
+
|
81
|
+
var fc = Coords.getFixed();
|
82
|
+
var opp = oppLockCorner(mode);
|
83
|
+
var opc = Coords.getCorner(oppLockCorner(opp));
|
84
|
+
|
85
|
+
Coords.setPressed(Coords.getCorner(opp));
|
86
|
+
Coords.setCurrent(opc);
|
87
|
+
|
88
|
+
Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect, touch);
|
89
|
+
}
|
90
|
+
//}}}
|
91
|
+
function dragmodeHandler(mode, f) //{{{
|
92
|
+
{
|
93
|
+
return function (pos) {
|
94
|
+
if (!options.aspectRatio) {
|
95
|
+
switch (mode) {
|
96
|
+
case 'e':
|
97
|
+
pos[1] = f.y2;
|
98
|
+
break;
|
99
|
+
case 'w':
|
100
|
+
pos[1] = f.y2;
|
101
|
+
break;
|
102
|
+
case 'n':
|
103
|
+
pos[0] = f.x2;
|
104
|
+
break;
|
105
|
+
case 's':
|
106
|
+
pos[0] = f.x2;
|
107
|
+
break;
|
108
|
+
}
|
109
|
+
} else {
|
110
|
+
switch (mode) {
|
111
|
+
case 'e':
|
112
|
+
pos[1] = f.y + 1;
|
113
|
+
break;
|
114
|
+
case 'w':
|
115
|
+
pos[1] = f.y + 1;
|
116
|
+
break;
|
117
|
+
case 'n':
|
118
|
+
pos[0] = f.x + 1;
|
119
|
+
break;
|
120
|
+
case 's':
|
121
|
+
pos[0] = f.x + 1;
|
122
|
+
break;
|
123
|
+
}
|
124
|
+
}
|
125
|
+
Coords.setCurrent(pos);
|
126
|
+
Selection.update();
|
127
|
+
};
|
128
|
+
}
|
129
|
+
//}}}
|
130
|
+
function createMover(pos) //{{{
|
131
|
+
{
|
132
|
+
var lloc = pos;
|
133
|
+
KeyManager.watchKeys();
|
134
|
+
|
135
|
+
return function (pos) {
|
136
|
+
Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]);
|
137
|
+
lloc = pos;
|
138
|
+
|
139
|
+
Selection.update();
|
140
|
+
};
|
141
|
+
}
|
142
|
+
//}}}
|
143
|
+
function oppLockCorner(ord) //{{{
|
144
|
+
{
|
145
|
+
switch (ord) {
|
146
|
+
case 'n':
|
147
|
+
return 'sw';
|
148
|
+
case 's':
|
149
|
+
return 'nw';
|
150
|
+
case 'e':
|
151
|
+
return 'nw';
|
152
|
+
case 'w':
|
153
|
+
return 'ne';
|
154
|
+
case 'ne':
|
155
|
+
return 'sw';
|
156
|
+
case 'nw':
|
157
|
+
return 'se';
|
158
|
+
case 'se':
|
159
|
+
return 'nw';
|
160
|
+
case 'sw':
|
161
|
+
return 'ne';
|
162
|
+
}
|
163
|
+
}
|
164
|
+
//}}}
|
165
|
+
function createDragger(ord) //{{{
|
166
|
+
{
|
167
|
+
return function (e) {
|
168
|
+
if (options.disabled) {
|
169
|
+
return false;
|
170
|
+
}
|
171
|
+
if ((ord === 'move') && !options.allowMove) {
|
172
|
+
return false;
|
173
|
+
}
|
174
|
+
|
175
|
+
// Fix position of crop area when dragged the very first time.
|
176
|
+
// Necessary when crop image is in a hidden element when page is loaded.
|
177
|
+
docOffset = getPos($img);
|
178
|
+
|
179
|
+
btndown = true;
|
180
|
+
startDragMode(ord, mouseAbs(e));
|
181
|
+
e.stopPropagation();
|
182
|
+
e.preventDefault();
|
183
|
+
return false;
|
184
|
+
};
|
185
|
+
}
|
186
|
+
//}}}
|
187
|
+
function presize($obj, w, h) //{{{
|
188
|
+
{
|
189
|
+
var nw = $obj.width(),
|
190
|
+
nh = $obj.height();
|
191
|
+
if ((nw > w) && w > 0) {
|
192
|
+
nw = w;
|
193
|
+
nh = (w / $obj.width()) * $obj.height();
|
194
|
+
}
|
195
|
+
if ((nh > h) && h > 0) {
|
196
|
+
nh = h;
|
197
|
+
nw = (h / $obj.height()) * $obj.width();
|
198
|
+
}
|
199
|
+
xscale = $obj.width() / nw;
|
200
|
+
yscale = $obj.height() / nh;
|
201
|
+
$obj.width(nw).height(nh);
|
202
|
+
}
|
203
|
+
//}}}
|
204
|
+
function unscale(c) //{{{
|
205
|
+
{
|
206
|
+
return {
|
207
|
+
x: c.x * xscale,
|
208
|
+
y: c.y * yscale,
|
209
|
+
x2: c.x2 * xscale,
|
210
|
+
y2: c.y2 * yscale,
|
211
|
+
w: c.w * xscale,
|
212
|
+
h: c.h * yscale
|
213
|
+
};
|
214
|
+
}
|
215
|
+
//}}}
|
216
|
+
function doneSelect(pos) //{{{
|
217
|
+
{
|
218
|
+
var c = Coords.getFixed();
|
219
|
+
if ((c.w > options.minSelect[0]) && (c.h > options.minSelect[1])) {
|
220
|
+
Selection.enableHandles();
|
221
|
+
Selection.done();
|
222
|
+
} else {
|
223
|
+
Selection.release();
|
224
|
+
}
|
225
|
+
Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
|
226
|
+
}
|
227
|
+
//}}}
|
228
|
+
function newSelection(e) //{{{
|
229
|
+
{
|
230
|
+
if (options.disabled) {
|
231
|
+
return false;
|
232
|
+
}
|
233
|
+
if (!options.allowSelect) {
|
234
|
+
return false;
|
235
|
+
}
|
236
|
+
btndown = true;
|
237
|
+
docOffset = getPos($img);
|
238
|
+
Selection.disableHandles();
|
239
|
+
Tracker.setCursor('crosshair');
|
240
|
+
var pos = mouseAbs(e);
|
241
|
+
Coords.setPressed(pos);
|
242
|
+
Selection.update();
|
243
|
+
Tracker.activateHandlers(selectDrag, doneSelect, e.type.substring(0,5)==='touch');
|
244
|
+
KeyManager.watchKeys();
|
245
|
+
|
246
|
+
e.stopPropagation();
|
247
|
+
e.preventDefault();
|
248
|
+
return false;
|
249
|
+
}
|
250
|
+
//}}}
|
251
|
+
function selectDrag(pos) //{{{
|
252
|
+
{
|
253
|
+
Coords.setCurrent(pos);
|
254
|
+
Selection.update();
|
255
|
+
}
|
256
|
+
//}}}
|
257
|
+
function newTracker() //{{{
|
258
|
+
{
|
259
|
+
var trk = $('<div></div>').addClass(cssClass('tracker'));
|
260
|
+
if (is_msie) {
|
261
|
+
trk.css({
|
262
|
+
opacity: 0,
|
263
|
+
backgroundColor: 'white'
|
264
|
+
});
|
265
|
+
}
|
266
|
+
return trk;
|
267
|
+
}
|
268
|
+
//}}}
|
269
|
+
|
270
|
+
// }}}
|
271
|
+
// Initialization {{{
|
272
|
+
// Sanitize some options {{{
|
273
|
+
if (typeof(obj) !== 'object') {
|
274
|
+
obj = $(obj)[0];
|
275
|
+
}
|
276
|
+
if (typeof(opt) !== 'object') {
|
277
|
+
opt = {};
|
278
|
+
}
|
279
|
+
// }}}
|
280
|
+
setOptions(opt);
|
281
|
+
// Initialize some jQuery objects {{{
|
282
|
+
// The values are SET on the image(s) for the interface
|
283
|
+
// If the original image has any of these set, they will be reset
|
284
|
+
// However, if you destroy() the Jcrop instance the original image's
|
285
|
+
// character in the DOM will be as you left it.
|
286
|
+
var img_css = {
|
287
|
+
border: 'none',
|
288
|
+
visibility: 'visible',
|
289
|
+
margin: 0,
|
290
|
+
padding: 0,
|
291
|
+
position: 'absolute',
|
292
|
+
top: 0,
|
293
|
+
left: 0
|
294
|
+
};
|
295
|
+
|
296
|
+
var $origimg = $(obj),
|
297
|
+
img_mode = true;
|
298
|
+
|
299
|
+
if (obj.tagName == 'IMG') {
|
300
|
+
// Fix size of crop image.
|
301
|
+
// Necessary when crop image is within a hidden element when page is loaded.
|
302
|
+
if ($origimg[0].width != 0 && $origimg[0].height != 0) {
|
303
|
+
// Obtain dimensions from contained img element.
|
304
|
+
$origimg.width($origimg[0].width);
|
305
|
+
$origimg.height($origimg[0].height);
|
306
|
+
} else {
|
307
|
+
// Obtain dimensions from temporary image in case the original is not loaded yet (e.g. IE 7.0).
|
308
|
+
var tempImage = new Image();
|
309
|
+
tempImage.src = $origimg[0].src;
|
310
|
+
$origimg.width(tempImage.width);
|
311
|
+
$origimg.height(tempImage.height);
|
312
|
+
}
|
313
|
+
|
314
|
+
var $img = $origimg.clone().removeAttr('id').css(img_css).show();
|
315
|
+
|
316
|
+
$img.width($origimg.width());
|
317
|
+
$img.height($origimg.height());
|
318
|
+
$origimg.after($img).hide();
|
319
|
+
|
320
|
+
} else {
|
321
|
+
$img = $origimg.css(img_css).show();
|
322
|
+
img_mode = false;
|
323
|
+
if (options.shade === null) { options.shade = true; }
|
324
|
+
}
|
325
|
+
|
326
|
+
presize($img, options.boxWidth, options.boxHeight);
|
327
|
+
|
328
|
+
var boundx = $img.width(),
|
329
|
+
boundy = $img.height(),
|
330
|
+
|
331
|
+
|
332
|
+
$div = $('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({
|
333
|
+
position: 'relative',
|
334
|
+
backgroundColor: options.bgColor
|
335
|
+
}).insertAfter($origimg).append($img);
|
336
|
+
|
337
|
+
if (options.addClass) {
|
338
|
+
$div.addClass(options.addClass);
|
339
|
+
}
|
340
|
+
|
341
|
+
var $img2 = $('<div />'),
|
342
|
+
|
343
|
+
$img_holder = $('<div />')
|
344
|
+
.width('100%').height('100%').css({
|
345
|
+
zIndex: 310,
|
346
|
+
position: 'absolute',
|
347
|
+
overflow: 'hidden'
|
348
|
+
}),
|
349
|
+
|
350
|
+
$hdl_holder = $('<div />')
|
351
|
+
.width('100%').height('100%').css('zIndex', 320),
|
352
|
+
|
353
|
+
$sel = $('<div />')
|
354
|
+
.css({
|
355
|
+
position: 'absolute',
|
356
|
+
zIndex: 600
|
357
|
+
}).dblclick(function(){
|
358
|
+
var c = Coords.getFixed();
|
359
|
+
options.onDblClick.call(api,c);
|
360
|
+
}).insertBefore($img).append($img_holder, $hdl_holder);
|
361
|
+
|
362
|
+
if (img_mode) {
|
363
|
+
|
364
|
+
$img2 = $('<img />')
|
365
|
+
.attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy),
|
366
|
+
|
367
|
+
$img_holder.append($img2);
|
368
|
+
|
369
|
+
}
|
370
|
+
|
371
|
+
if (ie6mode) {
|
372
|
+
$sel.css({
|
373
|
+
overflowY: 'hidden'
|
374
|
+
});
|
375
|
+
}
|
376
|
+
|
377
|
+
var bound = options.boundary;
|
378
|
+
var $trk = newTracker().width(boundx + (bound * 2)).height(boundy + (bound * 2)).css({
|
379
|
+
position: 'absolute',
|
380
|
+
top: px(-bound),
|
381
|
+
left: px(-bound),
|
382
|
+
zIndex: 290
|
383
|
+
}).mousedown(newSelection);
|
384
|
+
|
385
|
+
/* }}} */
|
386
|
+
// Set more variables {{{
|
387
|
+
var bgcolor = options.bgColor,
|
388
|
+
bgopacity = options.bgOpacity,
|
389
|
+
xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true,
|
390
|
+
btndown, animating, shift_down;
|
391
|
+
|
392
|
+
docOffset = getPos($img);
|
393
|
+
// }}}
|
394
|
+
// }}}
|
395
|
+
// Internal Modules {{{
|
396
|
+
// Touch Module {{{
|
397
|
+
var Touch = (function () {
|
398
|
+
// Touch support detection function adapted (under MIT License)
|
399
|
+
// from code by Jeffrey Sambells - http://github.com/iamamused/
|
400
|
+
function hasTouchSupport() {
|
401
|
+
var support = {}, events = ['touchstart', 'touchmove', 'touchend'],
|
402
|
+
el = document.createElement('div'), i;
|
403
|
+
|
404
|
+
try {
|
405
|
+
for(i=0; i<events.length; i++) {
|
406
|
+
var eventName = events[i];
|
407
|
+
eventName = 'on' + eventName;
|
408
|
+
var isSupported = (eventName in el);
|
409
|
+
if (!isSupported) {
|
410
|
+
el.setAttribute(eventName, 'return;');
|
411
|
+
isSupported = typeof el[eventName] == 'function';
|
412
|
+
}
|
413
|
+
support[events[i]] = isSupported;
|
414
|
+
}
|
415
|
+
return support.touchstart && support.touchend && support.touchmove;
|
416
|
+
}
|
417
|
+
catch(err) {
|
418
|
+
return false;
|
419
|
+
}
|
420
|
+
}
|
421
|
+
|
422
|
+
function detectSupport() {
|
423
|
+
if ((options.touchSupport === true) || (options.touchSupport === false)) return options.touchSupport;
|
424
|
+
else return hasTouchSupport();
|
425
|
+
}
|
426
|
+
return {
|
427
|
+
createDragger: function (ord) {
|
428
|
+
return function (e) {
|
429
|
+
if (options.disabled) {
|
430
|
+
return false;
|
431
|
+
}
|
432
|
+
if ((ord === 'move') && !options.allowMove) {
|
433
|
+
return false;
|
434
|
+
}
|
435
|
+
docOffset = getPos($img);
|
436
|
+
btndown = true;
|
437
|
+
startDragMode(ord, mouseAbs(Touch.cfilter(e)), true);
|
438
|
+
e.stopPropagation();
|
439
|
+
e.preventDefault();
|
440
|
+
return false;
|
441
|
+
};
|
442
|
+
},
|
443
|
+
newSelection: function (e) {
|
444
|
+
return newSelection(Touch.cfilter(e));
|
445
|
+
},
|
446
|
+
cfilter: function (e){
|
447
|
+
e.pageX = e.originalEvent.changedTouches[0].pageX;
|
448
|
+
e.pageY = e.originalEvent.changedTouches[0].pageY;
|
449
|
+
return e;
|
450
|
+
},
|
451
|
+
isSupported: hasTouchSupport,
|
452
|
+
support: detectSupport()
|
453
|
+
};
|
454
|
+
}());
|
455
|
+
// }}}
|
456
|
+
// Coords Module {{{
|
457
|
+
var Coords = (function () {
|
458
|
+
var x1 = 0,
|
459
|
+
y1 = 0,
|
460
|
+
x2 = 0,
|
461
|
+
y2 = 0,
|
462
|
+
ox, oy;
|
463
|
+
|
464
|
+
function setPressed(pos) //{{{
|
465
|
+
{
|
466
|
+
pos = rebound(pos);
|
467
|
+
x2 = x1 = pos[0];
|
468
|
+
y2 = y1 = pos[1];
|
469
|
+
}
|
470
|
+
//}}}
|
471
|
+
function setCurrent(pos) //{{{
|
472
|
+
{
|
473
|
+
pos = rebound(pos);
|
474
|
+
ox = pos[0] - x2;
|
475
|
+
oy = pos[1] - y2;
|
476
|
+
x2 = pos[0];
|
477
|
+
y2 = pos[1];
|
478
|
+
}
|
479
|
+
//}}}
|
480
|
+
function getOffset() //{{{
|
481
|
+
{
|
482
|
+
return [ox, oy];
|
483
|
+
}
|
484
|
+
//}}}
|
485
|
+
function moveOffset(offset) //{{{
|
486
|
+
{
|
487
|
+
var ox = offset[0],
|
488
|
+
oy = offset[1];
|
489
|
+
|
490
|
+
if (0 > x1 + ox) {
|
491
|
+
ox -= ox + x1;
|
492
|
+
}
|
493
|
+
if (0 > y1 + oy) {
|
494
|
+
oy -= oy + y1;
|
495
|
+
}
|
496
|
+
|
497
|
+
if (boundy < y2 + oy) {
|
498
|
+
oy += boundy - (y2 + oy);
|
499
|
+
}
|
500
|
+
if (boundx < x2 + ox) {
|
501
|
+
ox += boundx - (x2 + ox);
|
502
|
+
}
|
503
|
+
|
504
|
+
x1 += ox;
|
505
|
+
x2 += ox;
|
506
|
+
y1 += oy;
|
507
|
+
y2 += oy;
|
508
|
+
}
|
509
|
+
//}}}
|
510
|
+
function getCorner(ord) //{{{
|
511
|
+
{
|
512
|
+
var c = getFixed();
|
513
|
+
switch (ord) {
|
514
|
+
case 'ne':
|
515
|
+
return [c.x2, c.y];
|
516
|
+
case 'nw':
|
517
|
+
return [c.x, c.y];
|
518
|
+
case 'se':
|
519
|
+
return [c.x2, c.y2];
|
520
|
+
case 'sw':
|
521
|
+
return [c.x, c.y2];
|
522
|
+
}
|
523
|
+
}
|
524
|
+
//}}}
|
525
|
+
function getFixed() //{{{
|
526
|
+
{
|
527
|
+
if (!options.aspectRatio) {
|
528
|
+
return getRect();
|
529
|
+
}
|
530
|
+
// This function could use some optimization I think...
|
531
|
+
var aspect = options.aspectRatio,
|
532
|
+
min_x = options.minSize[0] / xscale,
|
533
|
+
|
534
|
+
|
535
|
+
//min_y = options.minSize[1]/yscale,
|
536
|
+
max_x = options.maxSize[0] / xscale,
|
537
|
+
max_y = options.maxSize[1] / yscale,
|
538
|
+
rw = x2 - x1,
|
539
|
+
rh = y2 - y1,
|
540
|
+
rwa = Math.abs(rw),
|
541
|
+
rha = Math.abs(rh),
|
542
|
+
real_ratio = rwa / rha,
|
543
|
+
xx, yy, w, h;
|
544
|
+
|
545
|
+
if (max_x === 0) {
|
546
|
+
max_x = boundx * 10;
|
547
|
+
}
|
548
|
+
if (max_y === 0) {
|
549
|
+
max_y = boundy * 10;
|
550
|
+
}
|
551
|
+
if (real_ratio < aspect) {
|
552
|
+
yy = y2;
|
553
|
+
w = rha * aspect;
|
554
|
+
xx = rw < 0 ? x1 - w : w + x1;
|
555
|
+
|
556
|
+
if (xx < 0) {
|
557
|
+
xx = 0;
|
558
|
+
h = Math.abs((xx - x1) / aspect);
|
559
|
+
yy = rh < 0 ? y1 - h : h + y1;
|
560
|
+
} else if (xx > boundx) {
|
561
|
+
xx = boundx;
|
562
|
+
h = Math.abs((xx - x1) / aspect);
|
563
|
+
yy = rh < 0 ? y1 - h : h + y1;
|
564
|
+
}
|
565
|
+
} else {
|
566
|
+
xx = x2;
|
567
|
+
h = rwa / aspect;
|
568
|
+
yy = rh < 0 ? y1 - h : y1 + h;
|
569
|
+
if (yy < 0) {
|
570
|
+
yy = 0;
|
571
|
+
w = Math.abs((yy - y1) * aspect);
|
572
|
+
xx = rw < 0 ? x1 - w : w + x1;
|
573
|
+
} else if (yy > boundy) {
|
574
|
+
yy = boundy;
|
575
|
+
w = Math.abs(yy - y1) * aspect;
|
576
|
+
xx = rw < 0 ? x1 - w : w + x1;
|
577
|
+
}
|
578
|
+
}
|
579
|
+
|
580
|
+
// Magic %-)
|
581
|
+
if (xx > x1) { // right side
|
582
|
+
if (xx - x1 < min_x) {
|
583
|
+
xx = x1 + min_x;
|
584
|
+
} else if (xx - x1 > max_x) {
|
585
|
+
xx = x1 + max_x;
|
586
|
+
}
|
587
|
+
if (yy > y1) {
|
588
|
+
yy = y1 + (xx - x1) / aspect;
|
589
|
+
} else {
|
590
|
+
yy = y1 - (xx - x1) / aspect;
|
591
|
+
}
|
592
|
+
} else if (xx < x1) { // left side
|
593
|
+
if (x1 - xx < min_x) {
|
594
|
+
xx = x1 - min_x;
|
595
|
+
} else if (x1 - xx > max_x) {
|
596
|
+
xx = x1 - max_x;
|
597
|
+
}
|
598
|
+
if (yy > y1) {
|
599
|
+
yy = y1 + (x1 - xx) / aspect;
|
600
|
+
} else {
|
601
|
+
yy = y1 - (x1 - xx) / aspect;
|
602
|
+
}
|
603
|
+
}
|
604
|
+
|
605
|
+
if (xx < 0) {
|
606
|
+
x1 -= xx;
|
607
|
+
xx = 0;
|
608
|
+
} else if (xx > boundx) {
|
609
|
+
x1 -= xx - boundx;
|
610
|
+
xx = boundx;
|
611
|
+
}
|
612
|
+
|
613
|
+
if (yy < 0) {
|
614
|
+
y1 -= yy;
|
615
|
+
yy = 0;
|
616
|
+
} else if (yy > boundy) {
|
617
|
+
y1 -= yy - boundy;
|
618
|
+
yy = boundy;
|
619
|
+
}
|
620
|
+
|
621
|
+
return makeObj(flipCoords(x1, y1, xx, yy));
|
622
|
+
}
|
623
|
+
//}}}
|
624
|
+
function rebound(p) //{{{
|
625
|
+
{
|
626
|
+
if (p[0] < 0) p[0] = 0;
|
627
|
+
if (p[1] < 0) p[1] = 0;
|
628
|
+
|
629
|
+
if (p[0] > boundx) p[0] = boundx;
|
630
|
+
if (p[1] > boundy) p[1] = boundy;
|
631
|
+
|
632
|
+
return [Math.round(p[0]), Math.round(p[1])];
|
633
|
+
}
|
634
|
+
//}}}
|
635
|
+
function flipCoords(x1, y1, x2, y2) //{{{
|
636
|
+
{
|
637
|
+
var xa = x1,
|
638
|
+
xb = x2,
|
639
|
+
ya = y1,
|
640
|
+
yb = y2;
|
641
|
+
if (x2 < x1) {
|
642
|
+
xa = x2;
|
643
|
+
xb = x1;
|
644
|
+
}
|
645
|
+
if (y2 < y1) {
|
646
|
+
ya = y2;
|
647
|
+
yb = y1;
|
648
|
+
}
|
649
|
+
return [xa, ya, xb, yb];
|
650
|
+
}
|
651
|
+
//}}}
|
652
|
+
function getRect() //{{{
|
653
|
+
{
|
654
|
+
var xsize = x2 - x1,
|
655
|
+
ysize = y2 - y1,
|
656
|
+
delta;
|
657
|
+
|
658
|
+
if (xlimit && (Math.abs(xsize) > xlimit)) {
|
659
|
+
x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit);
|
660
|
+
}
|
661
|
+
if (ylimit && (Math.abs(ysize) > ylimit)) {
|
662
|
+
y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit);
|
663
|
+
}
|
664
|
+
|
665
|
+
if (ymin / yscale && (Math.abs(ysize) < ymin / yscale)) {
|
666
|
+
y2 = (ysize > 0) ? (y1 + ymin / yscale) : (y1 - ymin / yscale);
|
667
|
+
}
|
668
|
+
if (xmin / xscale && (Math.abs(xsize) < xmin / xscale)) {
|
669
|
+
x2 = (xsize > 0) ? (x1 + xmin / xscale) : (x1 - xmin / xscale);
|
670
|
+
}
|
671
|
+
|
672
|
+
if (x1 < 0) {
|
673
|
+
x2 -= x1;
|
674
|
+
x1 -= x1;
|
675
|
+
}
|
676
|
+
if (y1 < 0) {
|
677
|
+
y2 -= y1;
|
678
|
+
y1 -= y1;
|
679
|
+
}
|
680
|
+
if (x2 < 0) {
|
681
|
+
x1 -= x2;
|
682
|
+
x2 -= x2;
|
683
|
+
}
|
684
|
+
if (y2 < 0) {
|
685
|
+
y1 -= y2;
|
686
|
+
y2 -= y2;
|
687
|
+
}
|
688
|
+
if (x2 > boundx) {
|
689
|
+
delta = x2 - boundx;
|
690
|
+
x1 -= delta;
|
691
|
+
x2 -= delta;
|
692
|
+
}
|
693
|
+
if (y2 > boundy) {
|
694
|
+
delta = y2 - boundy;
|
695
|
+
y1 -= delta;
|
696
|
+
y2 -= delta;
|
697
|
+
}
|
698
|
+
if (x1 > boundx) {
|
699
|
+
delta = x1 - boundy;
|
700
|
+
y2 -= delta;
|
701
|
+
y1 -= delta;
|
702
|
+
}
|
703
|
+
if (y1 > boundy) {
|
704
|
+
delta = y1 - boundy;
|
705
|
+
y2 -= delta;
|
706
|
+
y1 -= delta;
|
707
|
+
}
|
708
|
+
|
709
|
+
return makeObj(flipCoords(x1, y1, x2, y2));
|
710
|
+
}
|
711
|
+
//}}}
|
712
|
+
function makeObj(a) //{{{
|
713
|
+
{
|
714
|
+
return {
|
715
|
+
x: a[0],
|
716
|
+
y: a[1],
|
717
|
+
x2: a[2],
|
718
|
+
y2: a[3],
|
719
|
+
w: a[2] - a[0],
|
720
|
+
h: a[3] - a[1]
|
721
|
+
};
|
722
|
+
}
|
723
|
+
//}}}
|
724
|
+
|
725
|
+
return {
|
726
|
+
flipCoords: flipCoords,
|
727
|
+
setPressed: setPressed,
|
728
|
+
setCurrent: setCurrent,
|
729
|
+
getOffset: getOffset,
|
730
|
+
moveOffset: moveOffset,
|
731
|
+
getCorner: getCorner,
|
732
|
+
getFixed: getFixed
|
733
|
+
};
|
734
|
+
}());
|
735
|
+
|
736
|
+
//}}}
|
737
|
+
// Shade Module {{{
|
738
|
+
var Shade = (function() {
|
739
|
+
var enabled = false,
|
740
|
+
holder = $('<div />').css({
|
741
|
+
position: 'absolute',
|
742
|
+
zIndex: 240,
|
743
|
+
opacity: 0
|
744
|
+
}),
|
745
|
+
shades = {
|
746
|
+
top: createShade(),
|
747
|
+
left: createShade().height(boundy),
|
748
|
+
right: createShade().height(boundy),
|
749
|
+
bottom: createShade()
|
750
|
+
};
|
751
|
+
|
752
|
+
function resizeShades(w,h) {
|
753
|
+
shades.left.css({ height: px(h) });
|
754
|
+
shades.right.css({ height: px(h) });
|
755
|
+
}
|
756
|
+
function updateAuto()
|
757
|
+
{
|
758
|
+
return updateShade(Coords.getFixed());
|
759
|
+
}
|
760
|
+
function updateShade(c)
|
761
|
+
{
|
762
|
+
shades.top.css({
|
763
|
+
left: px(c.x),
|
764
|
+
width: px(c.w),
|
765
|
+
height: px(c.y)
|
766
|
+
});
|
767
|
+
shades.bottom.css({
|
768
|
+
top: px(c.y2),
|
769
|
+
left: px(c.x),
|
770
|
+
width: px(c.w),
|
771
|
+
height: px(boundy-c.y2)
|
772
|
+
});
|
773
|
+
shades.right.css({
|
774
|
+
left: px(c.x2),
|
775
|
+
width: px(boundx-c.x2)
|
776
|
+
});
|
777
|
+
shades.left.css({
|
778
|
+
width: px(c.x)
|
779
|
+
});
|
780
|
+
}
|
781
|
+
function createShade() {
|
782
|
+
return $('<div />').css({
|
783
|
+
position: 'absolute',
|
784
|
+
backgroundColor: options.shadeColor||options.bgColor
|
785
|
+
}).appendTo(holder);
|
786
|
+
}
|
787
|
+
function enableShade() {
|
788
|
+
if (!enabled) {
|
789
|
+
enabled = true;
|
790
|
+
holder.insertBefore($img);
|
791
|
+
updateAuto();
|
792
|
+
Selection.setBgOpacity(1,0,1);
|
793
|
+
$img2.hide();
|
794
|
+
|
795
|
+
setBgColor(options.shadeColor||options.bgColor,1);
|
796
|
+
if (Selection.isAwake())
|
797
|
+
{
|
798
|
+
setOpacity(options.bgOpacity,1);
|
799
|
+
}
|
800
|
+
else setOpacity(1,1);
|
801
|
+
}
|
802
|
+
}
|
803
|
+
function setBgColor(color,now) {
|
804
|
+
colorChangeMacro(getShades(),color,now);
|
805
|
+
}
|
806
|
+
function disableShade() {
|
807
|
+
if (enabled) {
|
808
|
+
holder.remove();
|
809
|
+
$img2.show();
|
810
|
+
enabled = false;
|
811
|
+
if (Selection.isAwake()) {
|
812
|
+
Selection.setBgOpacity(options.bgOpacity,1,1);
|
813
|
+
} else {
|
814
|
+
Selection.setBgOpacity(1,1,1);
|
815
|
+
Selection.disableHandles();
|
816
|
+
}
|
817
|
+
colorChangeMacro($div,0,1);
|
818
|
+
}
|
819
|
+
}
|
820
|
+
function setOpacity(opacity,now) {
|
821
|
+
if (enabled) {
|
822
|
+
if (options.bgFade && !now) {
|
823
|
+
holder.animate({
|
824
|
+
opacity: 1-opacity
|
825
|
+
},{
|
826
|
+
queue: false,
|
827
|
+
duration: options.fadeTime
|
828
|
+
});
|
829
|
+
}
|
830
|
+
else holder.css({opacity:1-opacity});
|
831
|
+
}
|
832
|
+
}
|
833
|
+
function refreshAll() {
|
834
|
+
options.shade ? enableShade() : disableShade();
|
835
|
+
if (Selection.isAwake()) setOpacity(options.bgOpacity);
|
836
|
+
}
|
837
|
+
function getShades() {
|
838
|
+
return holder.children();
|
839
|
+
}
|
840
|
+
|
841
|
+
return {
|
842
|
+
update: updateAuto,
|
843
|
+
updateRaw: updateShade,
|
844
|
+
getShades: getShades,
|
845
|
+
setBgColor: setBgColor,
|
846
|
+
enable: enableShade,
|
847
|
+
disable: disableShade,
|
848
|
+
resize: resizeShades,
|
849
|
+
refresh: refreshAll,
|
850
|
+
opacity: setOpacity
|
851
|
+
};
|
852
|
+
}());
|
853
|
+
// }}}
|
854
|
+
// Selection Module {{{
|
855
|
+
var Selection = (function () {
|
856
|
+
var awake,
|
857
|
+
hdep = 370,
|
858
|
+
borders = {},
|
859
|
+
handle = {},
|
860
|
+
dragbar = {},
|
861
|
+
seehandles = false;
|
862
|
+
|
863
|
+
// Private Methods
|
864
|
+
function insertBorder(type) //{{{
|
865
|
+
{
|
866
|
+
var jq = $('<div />').css({
|
867
|
+
position: 'absolute',
|
868
|
+
opacity: options.borderOpacity
|
869
|
+
}).addClass(cssClass(type));
|
870
|
+
$img_holder.append(jq);
|
871
|
+
return jq;
|
872
|
+
}
|
873
|
+
//}}}
|
874
|
+
function dragDiv(ord, zi) //{{{
|
875
|
+
{
|
876
|
+
var jq = $('<div />').mousedown(createDragger(ord)).css({
|
877
|
+
cursor: ord + '-resize',
|
878
|
+
position: 'absolute',
|
879
|
+
zIndex: zi
|
880
|
+
}).addClass('ord-'+ord);
|
881
|
+
|
882
|
+
if (Touch.support) {
|
883
|
+
jq.bind('touchstart.jcrop', Touch.createDragger(ord));
|
884
|
+
}
|
885
|
+
|
886
|
+
$hdl_holder.append(jq);
|
887
|
+
return jq;
|
888
|
+
}
|
889
|
+
//}}}
|
890
|
+
function insertHandle(ord) //{{{
|
891
|
+
{
|
892
|
+
var hs = options.handleSize,
|
893
|
+
|
894
|
+
div = dragDiv(ord, hdep++).css({
|
895
|
+
opacity: options.handleOpacity
|
896
|
+
}).addClass(cssClass('handle'));
|
897
|
+
|
898
|
+
if (hs) { div.width(hs).height(hs); }
|
899
|
+
|
900
|
+
return div;
|
901
|
+
}
|
902
|
+
//}}}
|
903
|
+
function insertDragbar(ord) //{{{
|
904
|
+
{
|
905
|
+
return dragDiv(ord, hdep++).addClass('jcrop-dragbar');
|
906
|
+
}
|
907
|
+
//}}}
|
908
|
+
function createDragbars(li) //{{{
|
909
|
+
{
|
910
|
+
var i;
|
911
|
+
for (i = 0; i < li.length; i++) {
|
912
|
+
dragbar[li[i]] = insertDragbar(li[i]);
|
913
|
+
}
|
914
|
+
}
|
915
|
+
//}}}
|
916
|
+
function createBorders(li) //{{{
|
917
|
+
{
|
918
|
+
var cl,i;
|
919
|
+
for (i = 0; i < li.length; i++) {
|
920
|
+
switch(li[i]){
|
921
|
+
case'n': cl='hline'; break;
|
922
|
+
case's': cl='hline bottom'; break;
|
923
|
+
case'e': cl='vline right'; break;
|
924
|
+
case'w': cl='vline'; break;
|
925
|
+
}
|
926
|
+
borders[li[i]] = insertBorder(cl);
|
927
|
+
}
|
928
|
+
}
|
929
|
+
//}}}
|
930
|
+
function createHandles(li) //{{{
|
931
|
+
{
|
932
|
+
var i;
|
933
|
+
for (i = 0; i < li.length; i++) {
|
934
|
+
handle[li[i]] = insertHandle(li[i]);
|
935
|
+
}
|
936
|
+
}
|
937
|
+
//}}}
|
938
|
+
function moveto(x, y) //{{{
|
939
|
+
{
|
940
|
+
if (!options.shade) {
|
941
|
+
$img2.css({
|
942
|
+
top: px(-y),
|
943
|
+
left: px(-x)
|
944
|
+
});
|
945
|
+
}
|
946
|
+
$sel.css({
|
947
|
+
top: px(y),
|
948
|
+
left: px(x)
|
949
|
+
});
|
950
|
+
}
|
951
|
+
//}}}
|
952
|
+
function resize(w, h) //{{{
|
953
|
+
{
|
954
|
+
$sel.width(Math.round(w)).height(Math.round(h));
|
955
|
+
}
|
956
|
+
//}}}
|
957
|
+
function refresh() //{{{
|
958
|
+
{
|
959
|
+
var c = Coords.getFixed();
|
960
|
+
|
961
|
+
Coords.setPressed([c.x, c.y]);
|
962
|
+
Coords.setCurrent([c.x2, c.y2]);
|
963
|
+
|
964
|
+
updateVisible();
|
965
|
+
}
|
966
|
+
//}}}
|
967
|
+
|
968
|
+
// Internal Methods
|
969
|
+
function updateVisible(select) //{{{
|
970
|
+
{
|
971
|
+
if (awake) {
|
972
|
+
return update(select);
|
973
|
+
}
|
974
|
+
}
|
975
|
+
//}}}
|
976
|
+
function update(select) //{{{
|
977
|
+
{
|
978
|
+
var c = Coords.getFixed();
|
979
|
+
|
980
|
+
resize(c.w, c.h);
|
981
|
+
moveto(c.x, c.y);
|
982
|
+
if (options.shade) Shade.updateRaw(c);
|
983
|
+
|
984
|
+
awake || show();
|
985
|
+
|
986
|
+
if (select) {
|
987
|
+
options.onSelect.call(api, unscale(c));
|
988
|
+
} else {
|
989
|
+
options.onChange.call(api, unscale(c));
|
990
|
+
}
|
991
|
+
}
|
992
|
+
//}}}
|
993
|
+
function setBgOpacity(opacity,force,now) //{{{
|
994
|
+
{
|
995
|
+
if (!awake && !force) return;
|
996
|
+
if (options.bgFade && !now) {
|
997
|
+
$img.animate({
|
998
|
+
opacity: opacity
|
999
|
+
},{
|
1000
|
+
queue: false,
|
1001
|
+
duration: options.fadeTime
|
1002
|
+
});
|
1003
|
+
} else {
|
1004
|
+
$img.css('opacity', opacity);
|
1005
|
+
}
|
1006
|
+
}
|
1007
|
+
//}}}
|
1008
|
+
function show() //{{{
|
1009
|
+
{
|
1010
|
+
$sel.show();
|
1011
|
+
|
1012
|
+
if (options.shade) Shade.opacity(bgopacity);
|
1013
|
+
else setBgOpacity(bgopacity,true);
|
1014
|
+
|
1015
|
+
awake = true;
|
1016
|
+
}
|
1017
|
+
//}}}
|
1018
|
+
function release() //{{{
|
1019
|
+
{
|
1020
|
+
disableHandles();
|
1021
|
+
$sel.hide();
|
1022
|
+
|
1023
|
+
if (options.shade) Shade.opacity(1);
|
1024
|
+
else setBgOpacity(1);
|
1025
|
+
|
1026
|
+
awake = false;
|
1027
|
+
options.onRelease.call(api);
|
1028
|
+
}
|
1029
|
+
//}}}
|
1030
|
+
function showHandles() //{{{
|
1031
|
+
{
|
1032
|
+
if (seehandles) {
|
1033
|
+
$hdl_holder.show();
|
1034
|
+
}
|
1035
|
+
}
|
1036
|
+
//}}}
|
1037
|
+
function enableHandles() //{{{
|
1038
|
+
{
|
1039
|
+
seehandles = true;
|
1040
|
+
if (options.allowResize) {
|
1041
|
+
$hdl_holder.show();
|
1042
|
+
return true;
|
1043
|
+
}
|
1044
|
+
}
|
1045
|
+
//}}}
|
1046
|
+
function disableHandles() //{{{
|
1047
|
+
{
|
1048
|
+
seehandles = false;
|
1049
|
+
$hdl_holder.hide();
|
1050
|
+
}
|
1051
|
+
//}}}
|
1052
|
+
function animMode(v) //{{{
|
1053
|
+
{
|
1054
|
+
if (v) {
|
1055
|
+
animating = true;
|
1056
|
+
disableHandles();
|
1057
|
+
} else {
|
1058
|
+
animating = false;
|
1059
|
+
enableHandles();
|
1060
|
+
}
|
1061
|
+
}
|
1062
|
+
//}}}
|
1063
|
+
function done() //{{{
|
1064
|
+
{
|
1065
|
+
animMode(false);
|
1066
|
+
refresh();
|
1067
|
+
}
|
1068
|
+
//}}}
|
1069
|
+
// Insert draggable elements {{{
|
1070
|
+
// Insert border divs for outline
|
1071
|
+
|
1072
|
+
if (options.dragEdges && $.isArray(options.createDragbars))
|
1073
|
+
createDragbars(options.createDragbars);
|
1074
|
+
|
1075
|
+
if ($.isArray(options.createHandles))
|
1076
|
+
createHandles(options.createHandles);
|
1077
|
+
|
1078
|
+
if (options.drawBorders && $.isArray(options.createBorders))
|
1079
|
+
createBorders(options.createBorders);
|
1080
|
+
|
1081
|
+
//}}}
|
1082
|
+
|
1083
|
+
// This is a hack for iOS5 to support drag/move touch functionality
|
1084
|
+
$(document).bind('touchstart.jcrop-ios',function(e) {
|
1085
|
+
if ($(e.currentTarget).hasClass('jcrop-tracker')) e.stopPropagation();
|
1086
|
+
});
|
1087
|
+
|
1088
|
+
var $track = newTracker().mousedown(createDragger('move')).css({
|
1089
|
+
cursor: 'move',
|
1090
|
+
position: 'absolute',
|
1091
|
+
zIndex: 360
|
1092
|
+
});
|
1093
|
+
|
1094
|
+
if (Touch.support) {
|
1095
|
+
$track.bind('touchstart.jcrop', Touch.createDragger('move'));
|
1096
|
+
}
|
1097
|
+
|
1098
|
+
$img_holder.append($track);
|
1099
|
+
disableHandles();
|
1100
|
+
|
1101
|
+
return {
|
1102
|
+
updateVisible: updateVisible,
|
1103
|
+
update: update,
|
1104
|
+
release: release,
|
1105
|
+
refresh: refresh,
|
1106
|
+
isAwake: function () {
|
1107
|
+
return awake;
|
1108
|
+
},
|
1109
|
+
setCursor: function (cursor) {
|
1110
|
+
$track.css('cursor', cursor);
|
1111
|
+
},
|
1112
|
+
enableHandles: enableHandles,
|
1113
|
+
enableOnly: function () {
|
1114
|
+
seehandles = true;
|
1115
|
+
},
|
1116
|
+
showHandles: showHandles,
|
1117
|
+
disableHandles: disableHandles,
|
1118
|
+
animMode: animMode,
|
1119
|
+
setBgOpacity: setBgOpacity,
|
1120
|
+
done: done
|
1121
|
+
};
|
1122
|
+
}());
|
1123
|
+
|
1124
|
+
//}}}
|
1125
|
+
// Tracker Module {{{
|
1126
|
+
var Tracker = (function () {
|
1127
|
+
var onMove = function () {},
|
1128
|
+
onDone = function () {},
|
1129
|
+
trackDoc = options.trackDocument;
|
1130
|
+
|
1131
|
+
function toFront(touch) //{{{
|
1132
|
+
{
|
1133
|
+
$trk.css({
|
1134
|
+
zIndex: 450
|
1135
|
+
});
|
1136
|
+
|
1137
|
+
if (touch)
|
1138
|
+
$(document)
|
1139
|
+
.bind('touchmove.jcrop', trackTouchMove)
|
1140
|
+
.bind('touchend.jcrop', trackTouchEnd);
|
1141
|
+
|
1142
|
+
else if (trackDoc)
|
1143
|
+
$(document)
|
1144
|
+
.bind('mousemove.jcrop',trackMove)
|
1145
|
+
.bind('mouseup.jcrop',trackUp);
|
1146
|
+
}
|
1147
|
+
//}}}
|
1148
|
+
function toBack() //{{{
|
1149
|
+
{
|
1150
|
+
$trk.css({
|
1151
|
+
zIndex: 290
|
1152
|
+
});
|
1153
|
+
$(document).unbind('.jcrop');
|
1154
|
+
}
|
1155
|
+
//}}}
|
1156
|
+
function trackMove(e) //{{{
|
1157
|
+
{
|
1158
|
+
onMove(mouseAbs(e));
|
1159
|
+
return false;
|
1160
|
+
}
|
1161
|
+
//}}}
|
1162
|
+
function trackUp(e) //{{{
|
1163
|
+
{
|
1164
|
+
e.preventDefault();
|
1165
|
+
e.stopPropagation();
|
1166
|
+
|
1167
|
+
if (btndown) {
|
1168
|
+
btndown = false;
|
1169
|
+
|
1170
|
+
onDone(mouseAbs(e));
|
1171
|
+
|
1172
|
+
if (Selection.isAwake()) {
|
1173
|
+
options.onSelect.call(api, unscale(Coords.getFixed()));
|
1174
|
+
}
|
1175
|
+
|
1176
|
+
toBack();
|
1177
|
+
onMove = function () {};
|
1178
|
+
onDone = function () {};
|
1179
|
+
}
|
1180
|
+
|
1181
|
+
return false;
|
1182
|
+
}
|
1183
|
+
//}}}
|
1184
|
+
function activateHandlers(move, done, touch) //{{{
|
1185
|
+
{
|
1186
|
+
btndown = true;
|
1187
|
+
onMove = move;
|
1188
|
+
onDone = done;
|
1189
|
+
toFront(touch);
|
1190
|
+
return false;
|
1191
|
+
}
|
1192
|
+
//}}}
|
1193
|
+
function trackTouchMove(e) //{{{
|
1194
|
+
{
|
1195
|
+
onMove(mouseAbs(Touch.cfilter(e)));
|
1196
|
+
return false;
|
1197
|
+
}
|
1198
|
+
//}}}
|
1199
|
+
function trackTouchEnd(e) //{{{
|
1200
|
+
{
|
1201
|
+
return trackUp(Touch.cfilter(e));
|
1202
|
+
}
|
1203
|
+
//}}}
|
1204
|
+
function setCursor(t) //{{{
|
1205
|
+
{
|
1206
|
+
$trk.css('cursor', t);
|
1207
|
+
}
|
1208
|
+
//}}}
|
1209
|
+
|
1210
|
+
if (!trackDoc) {
|
1211
|
+
$trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);
|
1212
|
+
}
|
1213
|
+
|
1214
|
+
$img.before($trk);
|
1215
|
+
return {
|
1216
|
+
activateHandlers: activateHandlers,
|
1217
|
+
setCursor: setCursor
|
1218
|
+
};
|
1219
|
+
}());
|
1220
|
+
//}}}
|
1221
|
+
// KeyManager Module {{{
|
1222
|
+
var KeyManager = (function () {
|
1223
|
+
var $keymgr = $('<input type="radio" />').css({
|
1224
|
+
position: 'fixed',
|
1225
|
+
left: '-120px',
|
1226
|
+
width: '12px'
|
1227
|
+
}).addClass('jcrop-keymgr'),
|
1228
|
+
|
1229
|
+
$keywrap = $('<div />').css({
|
1230
|
+
position: 'absolute',
|
1231
|
+
overflow: 'hidden'
|
1232
|
+
}).append($keymgr);
|
1233
|
+
|
1234
|
+
function watchKeys() //{{{
|
1235
|
+
{
|
1236
|
+
if (options.keySupport) {
|
1237
|
+
$keymgr.show();
|
1238
|
+
$keymgr.focus();
|
1239
|
+
}
|
1240
|
+
}
|
1241
|
+
//}}}
|
1242
|
+
function onBlur(e) //{{{
|
1243
|
+
{
|
1244
|
+
$keymgr.hide();
|
1245
|
+
}
|
1246
|
+
//}}}
|
1247
|
+
function doNudge(e, x, y) //{{{
|
1248
|
+
{
|
1249
|
+
if (options.allowMove) {
|
1250
|
+
Coords.moveOffset([x, y]);
|
1251
|
+
Selection.updateVisible(true);
|
1252
|
+
}
|
1253
|
+
e.preventDefault();
|
1254
|
+
e.stopPropagation();
|
1255
|
+
}
|
1256
|
+
//}}}
|
1257
|
+
function parseKey(e) //{{{
|
1258
|
+
{
|
1259
|
+
if (e.ctrlKey || e.metaKey) {
|
1260
|
+
return true;
|
1261
|
+
}
|
1262
|
+
shift_down = e.shiftKey ? true : false;
|
1263
|
+
var nudge = shift_down ? 10 : 1;
|
1264
|
+
|
1265
|
+
switch (e.keyCode) {
|
1266
|
+
case 37:
|
1267
|
+
doNudge(e, -nudge, 0);
|
1268
|
+
break;
|
1269
|
+
case 39:
|
1270
|
+
doNudge(e, nudge, 0);
|
1271
|
+
break;
|
1272
|
+
case 38:
|
1273
|
+
doNudge(e, 0, -nudge);
|
1274
|
+
break;
|
1275
|
+
case 40:
|
1276
|
+
doNudge(e, 0, nudge);
|
1277
|
+
break;
|
1278
|
+
case 27:
|
1279
|
+
if (options.allowSelect) Selection.release();
|
1280
|
+
break;
|
1281
|
+
case 9:
|
1282
|
+
return true;
|
1283
|
+
}
|
1284
|
+
|
1285
|
+
return false;
|
1286
|
+
}
|
1287
|
+
//}}}
|
1288
|
+
|
1289
|
+
if (options.keySupport) {
|
1290
|
+
$keymgr.keydown(parseKey).blur(onBlur);
|
1291
|
+
if (ie6mode || !options.fixedSupport) {
|
1292
|
+
$keymgr.css({
|
1293
|
+
position: 'absolute',
|
1294
|
+
left: '-20px'
|
1295
|
+
});
|
1296
|
+
$keywrap.append($keymgr).insertBefore($img);
|
1297
|
+
} else {
|
1298
|
+
$keymgr.insertBefore($img);
|
1299
|
+
}
|
1300
|
+
}
|
1301
|
+
|
1302
|
+
|
1303
|
+
return {
|
1304
|
+
watchKeys: watchKeys
|
1305
|
+
};
|
1306
|
+
}());
|
1307
|
+
//}}}
|
1308
|
+
// }}}
|
1309
|
+
// API methods {{{
|
1310
|
+
function setClass(cname) //{{{
|
1311
|
+
{
|
1312
|
+
$div.removeClass().addClass(cssClass('holder')).addClass(cname);
|
1313
|
+
}
|
1314
|
+
//}}}
|
1315
|
+
function animateTo(a, callback) //{{{
|
1316
|
+
{
|
1317
|
+
var x1 = a[0] / xscale,
|
1318
|
+
y1 = a[1] / yscale,
|
1319
|
+
x2 = a[2] / xscale,
|
1320
|
+
y2 = a[3] / yscale;
|
1321
|
+
|
1322
|
+
if (animating) {
|
1323
|
+
return;
|
1324
|
+
}
|
1325
|
+
|
1326
|
+
var animto = Coords.flipCoords(x1, y1, x2, y2),
|
1327
|
+
c = Coords.getFixed(),
|
1328
|
+
initcr = [c.x, c.y, c.x2, c.y2],
|
1329
|
+
animat = initcr,
|
1330
|
+
interv = options.animationDelay,
|
1331
|
+
ix1 = animto[0] - initcr[0],
|
1332
|
+
iy1 = animto[1] - initcr[1],
|
1333
|
+
ix2 = animto[2] - initcr[2],
|
1334
|
+
iy2 = animto[3] - initcr[3],
|
1335
|
+
pcent = 0,
|
1336
|
+
velocity = options.swingSpeed;
|
1337
|
+
|
1338
|
+
x1 = animat[0];
|
1339
|
+
y1 = animat[1];
|
1340
|
+
x2 = animat[2];
|
1341
|
+
y2 = animat[3];
|
1342
|
+
|
1343
|
+
Selection.animMode(true);
|
1344
|
+
var anim_timer;
|
1345
|
+
|
1346
|
+
function queueAnimator() {
|
1347
|
+
window.setTimeout(animator, interv);
|
1348
|
+
}
|
1349
|
+
var animator = (function () {
|
1350
|
+
return function () {
|
1351
|
+
pcent += (100 - pcent) / velocity;
|
1352
|
+
|
1353
|
+
animat[0] = Math.round(x1 + ((pcent / 100) * ix1));
|
1354
|
+
animat[1] = Math.round(y1 + ((pcent / 100) * iy1));
|
1355
|
+
animat[2] = Math.round(x2 + ((pcent / 100) * ix2));
|
1356
|
+
animat[3] = Math.round(y2 + ((pcent / 100) * iy2));
|
1357
|
+
|
1358
|
+
if (pcent >= 99.8) {
|
1359
|
+
pcent = 100;
|
1360
|
+
}
|
1361
|
+
if (pcent < 100) {
|
1362
|
+
setSelectRaw(animat);
|
1363
|
+
queueAnimator();
|
1364
|
+
} else {
|
1365
|
+
Selection.done();
|
1366
|
+
Selection.animMode(false);
|
1367
|
+
if (typeof(callback) === 'function') {
|
1368
|
+
callback.call(api);
|
1369
|
+
}
|
1370
|
+
}
|
1371
|
+
};
|
1372
|
+
}());
|
1373
|
+
queueAnimator();
|
1374
|
+
}
|
1375
|
+
//}}}
|
1376
|
+
function setSelect(rect) //{{{
|
1377
|
+
{
|
1378
|
+
setSelectRaw([rect[0] / xscale, rect[1] / yscale, rect[2] / xscale, rect[3] / yscale]);
|
1379
|
+
options.onSelect.call(api, unscale(Coords.getFixed()));
|
1380
|
+
Selection.enableHandles();
|
1381
|
+
}
|
1382
|
+
//}}}
|
1383
|
+
function setSelectRaw(l) //{{{
|
1384
|
+
{
|
1385
|
+
Coords.setPressed([l[0], l[1]]);
|
1386
|
+
Coords.setCurrent([l[2], l[3]]);
|
1387
|
+
Selection.update();
|
1388
|
+
}
|
1389
|
+
//}}}
|
1390
|
+
function tellSelect() //{{{
|
1391
|
+
{
|
1392
|
+
return unscale(Coords.getFixed());
|
1393
|
+
}
|
1394
|
+
//}}}
|
1395
|
+
function tellScaled() //{{{
|
1396
|
+
{
|
1397
|
+
return Coords.getFixed();
|
1398
|
+
}
|
1399
|
+
//}}}
|
1400
|
+
function setOptionsNew(opt) //{{{
|
1401
|
+
{
|
1402
|
+
setOptions(opt);
|
1403
|
+
interfaceUpdate();
|
1404
|
+
}
|
1405
|
+
//}}}
|
1406
|
+
function disableCrop() //{{{
|
1407
|
+
{
|
1408
|
+
options.disabled = true;
|
1409
|
+
Selection.disableHandles();
|
1410
|
+
Selection.setCursor('default');
|
1411
|
+
Tracker.setCursor('default');
|
1412
|
+
}
|
1413
|
+
//}}}
|
1414
|
+
function enableCrop() //{{{
|
1415
|
+
{
|
1416
|
+
options.disabled = false;
|
1417
|
+
interfaceUpdate();
|
1418
|
+
}
|
1419
|
+
//}}}
|
1420
|
+
function cancelCrop() //{{{
|
1421
|
+
{
|
1422
|
+
Selection.done();
|
1423
|
+
Tracker.activateHandlers(null, null);
|
1424
|
+
}
|
1425
|
+
//}}}
|
1426
|
+
function destroy() //{{{
|
1427
|
+
{
|
1428
|
+
$div.remove();
|
1429
|
+
$origimg.show();
|
1430
|
+
$origimg.css('visibility','visible');
|
1431
|
+
$(obj).removeData('Jcrop');
|
1432
|
+
}
|
1433
|
+
//}}}
|
1434
|
+
function setImage(src, callback) //{{{
|
1435
|
+
{
|
1436
|
+
Selection.release();
|
1437
|
+
disableCrop();
|
1438
|
+
var img = new Image();
|
1439
|
+
img.onload = function () {
|
1440
|
+
var iw = img.width;
|
1441
|
+
var ih = img.height;
|
1442
|
+
var bw = options.boxWidth;
|
1443
|
+
var bh = options.boxHeight;
|
1444
|
+
$img.width(iw).height(ih);
|
1445
|
+
$img.attr('src', src);
|
1446
|
+
$img2.attr('src', src);
|
1447
|
+
presize($img, bw, bh);
|
1448
|
+
boundx = $img.width();
|
1449
|
+
boundy = $img.height();
|
1450
|
+
$img2.width(boundx).height(boundy);
|
1451
|
+
$trk.width(boundx + (bound * 2)).height(boundy + (bound * 2));
|
1452
|
+
$div.width(boundx).height(boundy);
|
1453
|
+
Shade.resize(boundx,boundy);
|
1454
|
+
enableCrop();
|
1455
|
+
|
1456
|
+
if (typeof(callback) === 'function') {
|
1457
|
+
callback.call(api);
|
1458
|
+
}
|
1459
|
+
};
|
1460
|
+
img.src = src;
|
1461
|
+
}
|
1462
|
+
//}}}
|
1463
|
+
function colorChangeMacro($obj,color,now) {
|
1464
|
+
var mycolor = color || options.bgColor;
|
1465
|
+
if (options.bgFade && supportsColorFade() && options.fadeTime && !now) {
|
1466
|
+
$obj.animate({
|
1467
|
+
backgroundColor: mycolor
|
1468
|
+
}, {
|
1469
|
+
queue: false,
|
1470
|
+
duration: options.fadeTime
|
1471
|
+
});
|
1472
|
+
} else {
|
1473
|
+
$obj.css('backgroundColor', mycolor);
|
1474
|
+
}
|
1475
|
+
}
|
1476
|
+
function interfaceUpdate(alt) //{{{
|
1477
|
+
// This method tweaks the interface based on options object.
|
1478
|
+
// Called when options are changed and at end of initialization.
|
1479
|
+
{
|
1480
|
+
if (options.allowResize) {
|
1481
|
+
if (alt) {
|
1482
|
+
Selection.enableOnly();
|
1483
|
+
} else {
|
1484
|
+
Selection.enableHandles();
|
1485
|
+
}
|
1486
|
+
} else {
|
1487
|
+
Selection.disableHandles();
|
1488
|
+
}
|
1489
|
+
|
1490
|
+
Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
|
1491
|
+
Selection.setCursor(options.allowMove ? 'move' : 'default');
|
1492
|
+
|
1493
|
+
if (options.hasOwnProperty('trueSize')) {
|
1494
|
+
xscale = options.trueSize[0] / boundx;
|
1495
|
+
yscale = options.trueSize[1] / boundy;
|
1496
|
+
}
|
1497
|
+
|
1498
|
+
if (options.hasOwnProperty('setSelect')) {
|
1499
|
+
setSelect(options.setSelect);
|
1500
|
+
Selection.done();
|
1501
|
+
delete(options.setSelect);
|
1502
|
+
}
|
1503
|
+
|
1504
|
+
Shade.refresh();
|
1505
|
+
|
1506
|
+
if (options.bgColor != bgcolor) {
|
1507
|
+
colorChangeMacro(
|
1508
|
+
options.shade? Shade.getShades(): $div,
|
1509
|
+
options.shade?
|
1510
|
+
(options.shadeColor || options.bgColor):
|
1511
|
+
options.bgColor
|
1512
|
+
);
|
1513
|
+
bgcolor = options.bgColor;
|
1514
|
+
}
|
1515
|
+
|
1516
|
+
if (bgopacity != options.bgOpacity) {
|
1517
|
+
bgopacity = options.bgOpacity;
|
1518
|
+
if (options.shade) Shade.refresh();
|
1519
|
+
else Selection.setBgOpacity(bgopacity);
|
1520
|
+
}
|
1521
|
+
|
1522
|
+
xlimit = options.maxSize[0] || 0;
|
1523
|
+
ylimit = options.maxSize[1] || 0;
|
1524
|
+
xmin = options.minSize[0] || 0;
|
1525
|
+
ymin = options.minSize[1] || 0;
|
1526
|
+
|
1527
|
+
if (options.hasOwnProperty('outerImage')) {
|
1528
|
+
$img.attr('src', options.outerImage);
|
1529
|
+
delete(options.outerImage);
|
1530
|
+
}
|
1531
|
+
|
1532
|
+
Selection.refresh();
|
1533
|
+
}
|
1534
|
+
//}}}
|
1535
|
+
//}}}
|
1536
|
+
|
1537
|
+
if (Touch.support) $trk.bind('touchstart.jcrop', Touch.newSelection);
|
1538
|
+
|
1539
|
+
$hdl_holder.hide();
|
1540
|
+
interfaceUpdate(true);
|
1541
|
+
|
1542
|
+
var api = {
|
1543
|
+
setImage: setImage,
|
1544
|
+
animateTo: animateTo,
|
1545
|
+
setSelect: setSelect,
|
1546
|
+
setOptions: setOptionsNew,
|
1547
|
+
tellSelect: tellSelect,
|
1548
|
+
tellScaled: tellScaled,
|
1549
|
+
setClass: setClass,
|
1550
|
+
|
1551
|
+
disable: disableCrop,
|
1552
|
+
enable: enableCrop,
|
1553
|
+
cancel: cancelCrop,
|
1554
|
+
release: Selection.release,
|
1555
|
+
destroy: destroy,
|
1556
|
+
|
1557
|
+
focus: KeyManager.watchKeys,
|
1558
|
+
|
1559
|
+
getBounds: function () {
|
1560
|
+
return [boundx * xscale, boundy * yscale];
|
1561
|
+
},
|
1562
|
+
getWidgetSize: function () {
|
1563
|
+
return [boundx, boundy];
|
1564
|
+
},
|
1565
|
+
getScaleFactor: function () {
|
1566
|
+
return [xscale, yscale];
|
1567
|
+
},
|
1568
|
+
getOptions: function() {
|
1569
|
+
// careful: internal values are returned
|
1570
|
+
return options;
|
1571
|
+
},
|
1572
|
+
|
1573
|
+
ui: {
|
1574
|
+
holder: $div,
|
1575
|
+
selection: $sel
|
1576
|
+
}
|
1577
|
+
};
|
1578
|
+
|
1579
|
+
if (is_msie) $div.bind('selectstart', function () { return false; });
|
1580
|
+
|
1581
|
+
$origimg.data('Jcrop', api);
|
1582
|
+
return api;
|
1583
|
+
};
|
1584
|
+
$.fn.Jcrop = function (options, callback) //{{{
|
1585
|
+
{
|
1586
|
+
var api;
|
1587
|
+
// Iterate over each object, attach Jcrop
|
1588
|
+
this.each(function () {
|
1589
|
+
// If we've already attached to this object
|
1590
|
+
if ($(this).data('Jcrop')) {
|
1591
|
+
// The API can be requested this way (undocumented)
|
1592
|
+
if (options === 'api') return $(this).data('Jcrop');
|
1593
|
+
// Otherwise, we just reset the options...
|
1594
|
+
else $(this).data('Jcrop').setOptions(options);
|
1595
|
+
}
|
1596
|
+
// If we haven't been attached, preload and attach
|
1597
|
+
else {
|
1598
|
+
if (this.tagName == 'IMG')
|
1599
|
+
$.Jcrop.Loader(this,function(){
|
1600
|
+
$(this).css({display:'block',visibility:'hidden'});
|
1601
|
+
api = $.Jcrop(this, options);
|
1602
|
+
if ($.isFunction(callback)) callback.call(api);
|
1603
|
+
});
|
1604
|
+
else {
|
1605
|
+
$(this).css({display:'block',visibility:'hidden'});
|
1606
|
+
api = $.Jcrop(this, options);
|
1607
|
+
if ($.isFunction(callback)) callback.call(api);
|
1608
|
+
}
|
1609
|
+
}
|
1610
|
+
});
|
1611
|
+
|
1612
|
+
// Return "this" so the object is chainable (jQuery-style)
|
1613
|
+
return this;
|
1614
|
+
};
|
1615
|
+
//}}}
|
1616
|
+
// $.Jcrop.Loader - basic image loader {{{
|
1617
|
+
|
1618
|
+
$.Jcrop.Loader = function(imgobj,success,error){
|
1619
|
+
var $img = $(imgobj), img = $img[0];
|
1620
|
+
|
1621
|
+
function completeCheck(){
|
1622
|
+
if (img.complete) {
|
1623
|
+
$img.unbind('.jcloader');
|
1624
|
+
if ($.isFunction(success)) success.call(img);
|
1625
|
+
}
|
1626
|
+
else window.setTimeout(completeCheck,50);
|
1627
|
+
}
|
1628
|
+
|
1629
|
+
$img
|
1630
|
+
.bind('load.jcloader',completeCheck)
|
1631
|
+
.bind('error.jcloader',function(e){
|
1632
|
+
$img.unbind('.jcloader');
|
1633
|
+
if ($.isFunction(error)) error.call(img);
|
1634
|
+
});
|
1635
|
+
|
1636
|
+
if (img.complete && $.isFunction(success)){
|
1637
|
+
$img.unbind('.jcloader');
|
1638
|
+
success.call(img);
|
1639
|
+
}
|
1640
|
+
};
|
1641
|
+
|
1642
|
+
//}}}
|
1643
|
+
// Global Defaults {{{
|
1644
|
+
$.Jcrop.defaults = {
|
1645
|
+
|
1646
|
+
// Basic Settings
|
1647
|
+
allowSelect: true,
|
1648
|
+
allowMove: true,
|
1649
|
+
allowResize: true,
|
1650
|
+
|
1651
|
+
trackDocument: true,
|
1652
|
+
|
1653
|
+
// Styling Options
|
1654
|
+
baseClass: 'jcrop',
|
1655
|
+
addClass: null,
|
1656
|
+
bgColor: 'black',
|
1657
|
+
bgOpacity: 0.6,
|
1658
|
+
bgFade: false,
|
1659
|
+
borderOpacity: 0.4,
|
1660
|
+
handleOpacity: 0.5,
|
1661
|
+
handleSize: null,
|
1662
|
+
|
1663
|
+
aspectRatio: 0,
|
1664
|
+
keySupport: true,
|
1665
|
+
createHandles: ['n','s','e','w','nw','ne','se','sw'],
|
1666
|
+
createDragbars: ['n','s','e','w'],
|
1667
|
+
createBorders: ['n','s','e','w'],
|
1668
|
+
drawBorders: true,
|
1669
|
+
dragEdges: true,
|
1670
|
+
fixedSupport: true,
|
1671
|
+
touchSupport: null,
|
1672
|
+
|
1673
|
+
shade: null,
|
1674
|
+
|
1675
|
+
boxWidth: 0,
|
1676
|
+
boxHeight: 0,
|
1677
|
+
boundary: 2,
|
1678
|
+
fadeTime: 400,
|
1679
|
+
animationDelay: 20,
|
1680
|
+
swingSpeed: 3,
|
1681
|
+
|
1682
|
+
minSelect: [0, 0],
|
1683
|
+
maxSize: [0, 0],
|
1684
|
+
minSize: [0, 0],
|
1685
|
+
|
1686
|
+
// Callbacks / Event Handlers
|
1687
|
+
onChange: function () {},
|
1688
|
+
onSelect: function () {},
|
1689
|
+
onDblClick: function () {},
|
1690
|
+
onRelease: function () {}
|
1691
|
+
};
|
1692
|
+
|
1693
|
+
// }}}
|
1694
|
+
}(jQuery));
|