pageflow-linkmap-page 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.jshintignore +1 -0
- data/.jshintrc +23 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +18 -0
- data/README.md +62 -0
- data/Rakefile +11 -0
- data/app/assets/images/pageflow/linkmap_page/text_only_area_type_pictogram.png +0 -0
- data/app/assets/images/pageflow/linkmap_page/themes/default/pictograms/sprite.png +0 -0
- data/app/assets/images/pageflow/linkmap_page/themes/default/pictograms/wide.png +0 -0
- data/app/assets/images/pageflow/linkmap_page_pictogram.png +0 -0
- data/app/assets/images/pageflow/linkmap_page_pictogram_small.png +0 -0
- data/app/assets/javascript/pageflow/linkmap_page.js +9 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor.js +25 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/collections/areas_collection.js +57 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/collections/page_links_collection.js +29 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/config.js +51 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/controllers/side_bar_controller.js +15 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/models/area.js +79 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/models/area_file_selection_handler.js +12 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/models/audio_file_area_type.js +17 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/models/external_link_area_type.js +19 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/models/new_area_file_selection_handler.js +11 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/models/page_configuration_mixin.js +33 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/models/page_link_area_type.js +29 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/models/text_only_area_type.js +15 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/routers/side_bar_router.js +5 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/templates/edit_area.jst.ejs +3 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/templates/embedded/area_item.jst.ejs +11 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/views/areas_list_view.js +44 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/views/configuration_editor_view.js +90 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/views/edit_area_view.js +103 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/views/editable_areas_mode_view.js +10 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/views/embedded/area_item_embedded_view.js +190 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/views/embedded/areas_embedded_view.js +26 -0
- data/app/assets/javascript/pageflow/linkmap_page/editor/views/embedded/panorama_embedded_view.js +14 -0
- data/app/assets/javascript/pageflow/linkmap_page/features.js +9 -0
- data/app/assets/javascript/pageflow/linkmap_page/page_type.js +302 -0
- data/app/assets/javascript/pageflow/linkmap_page/vendor/gyro.js +3 -0
- data/app/assets/javascript/pageflow/linkmap_page/widgets/hover_video.js +77 -0
- data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap.js +112 -0
- data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap_audio_player_controls.js +132 -0
- data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap_audio_players_controller.js +48 -0
- data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap_lookaround.js +154 -0
- data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap_lookaround_strategies/target_speed.js +99 -0
- data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap_panorama.js +421 -0
- data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap_scroll_indicators.js +17 -0
- data/app/assets/stylesheets/pageflow/linkmap_page.css.scss +266 -0
- data/app/assets/stylesheets/pageflow/linkmap_page/animations/rotate.css.scss +8 -0
- data/app/assets/stylesheets/pageflow/linkmap_page/audio_player_controls.scss +134 -0
- data/app/assets/stylesheets/pageflow/linkmap_page/editor.css.scss +122 -0
- data/app/assets/stylesheets/pageflow/linkmap_page/editor/areas_list.scss +15 -0
- data/app/assets/stylesheets/pageflow/linkmap_page/editor/file_areas.css.scss +70 -0
- data/app/assets/stylesheets/pageflow/linkmap_page/editor/resizable.css.scss +80 -0
- data/app/assets/stylesheets/pageflow/linkmap_page/themes/default.css.scss +341 -0
- data/app/assets/stylesheets/pageflow/linkmap_page/themes/default/scroll_indicators.scss +82 -0
- data/app/controllers/pageflow/external_links/sites_controller.rb +40 -0
- data/app/helpers/pageflow/linkmap_page/areas_helper.rb +93 -0
- data/app/models/pageflow/linkmap_page/site.rb +11 -0
- data/app/views/pageflow/linkmap_page/areas/_div.html.erb +33 -0
- data/app/views/pageflow/linkmap_page/page.html +51 -0
- data/config/locales/de.yml +119 -0
- data/config/locales/en.yml +119 -0
- data/config/locales/new/inverted.de.yml +10 -0
- data/config/locales/new/inverted.en.yml +10 -0
- data/config/locales/new/text_only_area_type.de.yml +11 -0
- data/config/locales/new/text_only_area_type.en.yml +11 -0
- data/config/routes.rb +5 -0
- data/config/spring.rb +1 -0
- data/exec/rspec +15 -0
- data/exec/spring +18 -0
- data/lib/pageflow-linkmap-page.rb +13 -0
- data/lib/pageflow/linkmap_page/engine.rb +17 -0
- data/lib/pageflow/linkmap_page/page_type.rb +19 -0
- data/lib/pageflow/linkmap_page/plugin.rb +9 -0
- data/lib/pageflow/linkmap_page/version.rb +5 -0
- data/pageflow-linkmap-page.gemspec +37 -0
- data/spec/helpers/pageflow/linkmap_page/areas_helper_spec.rb +68 -0
- data/spec/spec_helper.rb +15 -0
- metadata +265 -0
@@ -0,0 +1,132 @@
|
|
1
|
+
(function($) {
|
2
|
+
$.widget('pageflow.linkmapAudioPlayerControls', {
|
3
|
+
_create: function() {
|
4
|
+
var widget = this;
|
5
|
+
var that = this;
|
6
|
+
|
7
|
+
this.wrapper = $('<div />')
|
8
|
+
.addClass('linkmap_audio_player_controls')
|
9
|
+
.appendTo(this.element.find('.linkmap_marker'));
|
10
|
+
|
11
|
+
this.playButton = $('<div />')
|
12
|
+
.addClass('play')
|
13
|
+
.appendTo(this.wrapper)
|
14
|
+
;
|
15
|
+
|
16
|
+
this.pauseButton = $('<div />')
|
17
|
+
.addClass('pause')
|
18
|
+
.appendTo(this.wrapper)
|
19
|
+
;
|
20
|
+
|
21
|
+
this.progressElement = $('<div />')
|
22
|
+
.addClass('progress')
|
23
|
+
.appendTo(this.wrapper)
|
24
|
+
;
|
25
|
+
|
26
|
+
this.progressElement.html('<div class="audio_inline_progress"><div class="progress_inner"><div class="left_circle"><div class="circle_inner"><div class="circle_innerst"></div></div></div><div class="right_circle"><div class="circle_inner"><div class="circle_innerst"></div></div></div><div class="audio_inline_loading_spinner"><div class="circle_inner"><div class="circle_innerst"></div></div></div></div></div>');
|
27
|
+
|
28
|
+
this.currentTimeElement = $('<div />')
|
29
|
+
.addClass('current_time')
|
30
|
+
.appendTo(this.wrapper)
|
31
|
+
;
|
32
|
+
|
33
|
+
this.durationElement = $('<div />')
|
34
|
+
.addClass('duration')
|
35
|
+
.appendTo(this.wrapper)
|
36
|
+
;
|
37
|
+
|
38
|
+
this.playButton.on('click', function(e) {
|
39
|
+
widget.element.addClass('loading');
|
40
|
+
widget._trigger('play', null, {
|
41
|
+
audioFileId: widget.element.data('audioFile')
|
42
|
+
});
|
43
|
+
e.preventDefault();
|
44
|
+
e.stopPropagation();
|
45
|
+
});
|
46
|
+
|
47
|
+
this.pauseButton.on('click', function(e) {
|
48
|
+
widget._trigger('pause', null, {
|
49
|
+
audioFileId: widget.element.data('audioFile')
|
50
|
+
});
|
51
|
+
|
52
|
+
e.preventDefault();
|
53
|
+
e.stopPropagation();
|
54
|
+
});
|
55
|
+
|
56
|
+
this.element.on('click', function() {
|
57
|
+
if (!widget.element.hasClass('dynamic_marker')) {
|
58
|
+
widget._trigger('play', null, {
|
59
|
+
audioFileId: widget.element.data('audioFile')
|
60
|
+
});
|
61
|
+
}
|
62
|
+
});
|
63
|
+
|
64
|
+
this.progressElement.on('click', function(e) {
|
65
|
+
|
66
|
+
var elementCenter = {
|
67
|
+
x: $(this).offset().left + $(this).width() / 2,
|
68
|
+
y: $(this).offset().top + $(this).height() / 2,
|
69
|
+
};
|
70
|
+
|
71
|
+
var angleDeg = Math.atan2(e.pageY - elementCenter.y, e.pageX - elementCenter.x) * 180 / Math.PI;
|
72
|
+
var circlePercentage = (angleDeg + 90) / 360;
|
73
|
+
|
74
|
+
circlePercentage = circlePercentage < 0 ? 1 + circlePercentage : circlePercentage;
|
75
|
+
|
76
|
+
widget._trigger('seek', null, {
|
77
|
+
positionInPercent: circlePercentage,
|
78
|
+
audioFileId: widget.element.data('audioFile')
|
79
|
+
});
|
80
|
+
|
81
|
+
e.stopPropagation();
|
82
|
+
});
|
83
|
+
},
|
84
|
+
|
85
|
+
drawCircle: function(percentage) {
|
86
|
+
var rightCircle = this.element.find('.right_circle .circle_inner');
|
87
|
+
var leftCircle = this.element.find('.left_circle .circle_inner');
|
88
|
+
var rightCircleInner = this.element.find('.right_circle .circle_innerst');
|
89
|
+
var leftCircleInner = this.element.find('.left_circle .circle_innerst');
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
var rotationRight = Math.min(percentage/100 * 360, 180);
|
94
|
+
var rotationLeft = Math.max(percentage/100 * 360 - 180, 0);
|
95
|
+
var rotation;
|
96
|
+
|
97
|
+
rotation = rotationRight;
|
98
|
+
rightCircle.attr("style", "-webkit-transform: rotate(" + rotation + "deg); -moz-transform: rotate(" + rotation + "deg); -ms-transform: rotate(" + rotation + "deg); -o-transform: rotate(" + rotation + "deg); transform: rotate(" + rotation + "deg)");
|
99
|
+
rightCircleInner.attr("style", "-webkit-transform: rotate(" + -rotation + "deg); -moz-transform: rotate(" + -rotation + "deg); -ms-transform: rotate(" + -rotation + "deg); -o-transform: rotate(" + -rotation + "deg); transform: rotate(" + -rotation + "deg)");
|
100
|
+
|
101
|
+
rotation = rotationLeft;
|
102
|
+
leftCircle.attr("style", "-webkit-transform: rotate(" + rotation + "deg); -moz-transform: rotate(" + rotation + "deg); -ms-transform: rotate(" + rotation + "deg); -o-transform: rotate(" + rotation + "deg); transform: rotate(" + rotation + "deg)");
|
103
|
+
leftCircleInner.attr("style", "-webkit-transform: rotate(" + -rotation + "deg); -moz-transform: rotate(" + -rotation + "deg); -ms-transform: rotate(" + -rotation + "deg); -o-transform: rotate(" + -rotation + "deg); transform: rotate(" + -rotation + "deg)");
|
104
|
+
},
|
105
|
+
|
106
|
+
playing: function() {
|
107
|
+
this.element.addClass('loading');
|
108
|
+
},
|
109
|
+
|
110
|
+
notPlaying: function() {
|
111
|
+
this.element.removeClass('playing loading');
|
112
|
+
},
|
113
|
+
|
114
|
+
cancelLoading: function() {
|
115
|
+
this.element.removeClass('loading');
|
116
|
+
},
|
117
|
+
|
118
|
+
updateProgress: function(player) {
|
119
|
+
this.element.removeClass('loading');
|
120
|
+
this.element.addClass('playing');
|
121
|
+
|
122
|
+
this.currentTimeElement.text(player.formatTime(player.position()));
|
123
|
+
this.durationElement.text(player.formatTime(player.duration()));
|
124
|
+
|
125
|
+
var percent = player.duration() > 0 ? player.position() / player.duration() * 100 : 0;
|
126
|
+
this.drawCircle(percent);
|
127
|
+
},
|
128
|
+
|
129
|
+
refresh: function() {
|
130
|
+
}
|
131
|
+
});
|
132
|
+
}(jQuery));
|
@@ -0,0 +1,48 @@
|
|
1
|
+
(function($) {
|
2
|
+
$.widget('pageflow.linkmapAudioPlayersController', {
|
3
|
+
_create: function() {
|
4
|
+
var player = this.options.player;
|
5
|
+
var element = this.element;
|
6
|
+
|
7
|
+
this.delegatePlayerEvent('play', 'playing');
|
8
|
+
this.delegatePlayerEvent('pause ended', 'notPlaying');
|
9
|
+
this.delegatePlayerEvent('timeupdate', 'updateProgress');
|
10
|
+
|
11
|
+
player.on('play', function(options) {
|
12
|
+
var playerElements = element.find('[data-target-type="audio_file"]');
|
13
|
+
|
14
|
+
playerElements.each(function() {
|
15
|
+
var playerElement = $(this);
|
16
|
+
|
17
|
+
if (playerElement.data('audioFile') !== options.audioFileId) {
|
18
|
+
playerElement.linkmapAudioPlayerControls('cancelLoading');
|
19
|
+
}
|
20
|
+
});
|
21
|
+
});
|
22
|
+
|
23
|
+
this.element.on('linkmapaudioplayercontrolsplay', function(event, options) {
|
24
|
+
player.play(options.audioFileId);
|
25
|
+
});
|
26
|
+
|
27
|
+
this.element.on('linkmapaudioplayercontrolspause', function(event, options) {
|
28
|
+
player.pause();
|
29
|
+
});
|
30
|
+
|
31
|
+
this.element.on('linkmapaudioplayercontrolsseek', function(event, options) {
|
32
|
+
player.seek(player.duration() * options.positionInPercent);
|
33
|
+
});
|
34
|
+
},
|
35
|
+
|
36
|
+
delegatePlayerEvent: function (event, method) {
|
37
|
+
var element = this.element;
|
38
|
+
var player = this.options.player;
|
39
|
+
|
40
|
+
player.on(event, function(options) {
|
41
|
+
var selector = '[data-audio-file="' + options.audioFileId + '"]';
|
42
|
+
var playerElement = element.find(selector);
|
43
|
+
|
44
|
+
playerElement.linkmapAudioPlayerControls(method, player);
|
45
|
+
});
|
46
|
+
}
|
47
|
+
});
|
48
|
+
}(jQuery));
|
@@ -0,0 +1,154 @@
|
|
1
|
+
(function($) {
|
2
|
+
$.widget('pageflow.linkmapLookaround', {
|
3
|
+
speedUp : 10,
|
4
|
+
drag : false,
|
5
|
+
|
6
|
+
_create: function() {
|
7
|
+
this.disabled = false;
|
8
|
+
this.marginScrolling = !this.options.marginScrollingDisabled;
|
9
|
+
|
10
|
+
var scroller = this.scroller = this.options.scroller;
|
11
|
+
var that = this;
|
12
|
+
|
13
|
+
this.scrollStrategyX = new pageflow.linkmapPage.TargetSpeedStrategy({
|
14
|
+
scrollerPosition: function() {
|
15
|
+
return scroller.positionX();
|
16
|
+
},
|
17
|
+
|
18
|
+
scrollerMax: function() {
|
19
|
+
return scroller.maxX();
|
20
|
+
}
|
21
|
+
}, 'x');
|
22
|
+
|
23
|
+
this.scrollStrategyY = new pageflow.linkmapPage.TargetSpeedStrategy({
|
24
|
+
scrollerPosition: function() {
|
25
|
+
return scroller.positionY();
|
26
|
+
},
|
27
|
+
|
28
|
+
scrollerMax: function() {
|
29
|
+
return scroller.maxY();
|
30
|
+
}
|
31
|
+
}, 'y');
|
32
|
+
|
33
|
+
this.element.on('mousedown touchstart', function (event) {
|
34
|
+
that.drag = true;
|
35
|
+
|
36
|
+
$(window).one('mouseup touchend', function() {
|
37
|
+
that.drag = false;
|
38
|
+
that.initialBeta = null;
|
39
|
+
that.initialGamma = null;
|
40
|
+
});
|
41
|
+
});
|
42
|
+
|
43
|
+
this.element.on('mousedown', function (event) {
|
44
|
+
// prevent dragging
|
45
|
+
event.originalEvent.preventDefault();
|
46
|
+
});
|
47
|
+
|
48
|
+
this.element.on('mouseenter', function() {
|
49
|
+
that.scrollStrategyX.reset();
|
50
|
+
that.scrollStrategyY.reset();
|
51
|
+
});
|
52
|
+
|
53
|
+
this.element.on('mouseleave', function() {
|
54
|
+
that.scrollStrategyX.reset();
|
55
|
+
that.scrollStrategyY.reset();
|
56
|
+
});
|
57
|
+
|
58
|
+
$(window).on('orientationchange', function( event ) {
|
59
|
+
that.drag = false;
|
60
|
+
that.initialBeta = null;
|
61
|
+
that.initialGamma = null;
|
62
|
+
});
|
63
|
+
|
64
|
+
this.element.on('mousemove', function(e) {
|
65
|
+
var containerWidth = that.element.width();
|
66
|
+
var containerHeight = that.element.height();
|
67
|
+
|
68
|
+
that.scrollStrategyX.updateMouse(e.pageX / containerWidth);
|
69
|
+
that.scrollStrategyY.updateMouse(e.pageY / containerHeight);
|
70
|
+
});
|
71
|
+
},
|
72
|
+
|
73
|
+
enable: function() {
|
74
|
+
this.disabled = false;
|
75
|
+
},
|
76
|
+
|
77
|
+
disable: function() {
|
78
|
+
this.disabled = true;
|
79
|
+
},
|
80
|
+
|
81
|
+
activate: function() {
|
82
|
+
this.startInterval();
|
83
|
+
|
84
|
+
if (pageflow.browser.has('mobile platform')) {
|
85
|
+
this.startGyro();
|
86
|
+
}
|
87
|
+
},
|
88
|
+
|
89
|
+
deactivate: function() {
|
90
|
+
this.stopInterval();
|
91
|
+
|
92
|
+
if (pageflow.browser.has('mobile platform')) {
|
93
|
+
this.stopGyro();
|
94
|
+
}
|
95
|
+
},
|
96
|
+
|
97
|
+
startInterval: function() {
|
98
|
+
if (!this.interval) {
|
99
|
+
this.interval = setInterval(_.bind(this.onTick, this), 25);
|
100
|
+
}
|
101
|
+
},
|
102
|
+
|
103
|
+
stopInterval: function() {
|
104
|
+
if (this.interval) {
|
105
|
+
clearInterval(this.interval);
|
106
|
+
this.interval = null;
|
107
|
+
}
|
108
|
+
},
|
109
|
+
|
110
|
+
onTick: function() {
|
111
|
+
if (!this.drag && this.marginScrolling && !this.disabled) {
|
112
|
+
this.scroller.scrollBy(this.scrollStrategyX.getNextScrollDelta(),
|
113
|
+
this.scrollStrategyY.getNextScrollDelta());
|
114
|
+
}
|
115
|
+
},
|
116
|
+
|
117
|
+
update: function(marginScrollingDisabled) {
|
118
|
+
this.marginScrolling = !marginScrollingDisabled;
|
119
|
+
},
|
120
|
+
|
121
|
+
startGyro: function() {
|
122
|
+
var that = this;
|
123
|
+
var limit = 8;
|
124
|
+
|
125
|
+
gyro.startTracking(function(o) {
|
126
|
+
if (!that.initialBeta) {
|
127
|
+
that.initialBeta = o.beta;
|
128
|
+
}
|
129
|
+
|
130
|
+
if (!that.initialGamma) {
|
131
|
+
that.initialGamma = o.gamma;
|
132
|
+
}
|
133
|
+
|
134
|
+
if (!this.drag) {
|
135
|
+
var deltaGamma = o.gamma - that.initialGamma;
|
136
|
+
var deltaBeta = o.beta - that.initialBeta;
|
137
|
+
|
138
|
+
if ($(window).height() >= $(window).width()) {
|
139
|
+
that.scrollStrategyX.updateGyro(deltaGamma);
|
140
|
+
that.scrollStrategyY.updateGyro(-deltaBeta);
|
141
|
+
}
|
142
|
+
else {
|
143
|
+
that.scrollStrategyX.updateGyro(-deltaBeta);
|
144
|
+
that.scrollStrategyY.updateGyro(deltaGamma);
|
145
|
+
}
|
146
|
+
}
|
147
|
+
});
|
148
|
+
},
|
149
|
+
|
150
|
+
stopGyro: function() {
|
151
|
+
gyro.stopTracking();
|
152
|
+
}
|
153
|
+
});
|
154
|
+
}(jQuery));
|
@@ -0,0 +1,99 @@
|
|
1
|
+
pageflow.linkmapPage.TargetSpeedStrategy = function(options, name) {
|
2
|
+
var speedUp = 10;
|
3
|
+
|
4
|
+
var targetSpeed = 0;
|
5
|
+
var speed = 0;
|
6
|
+
var realSpeed = 0;
|
7
|
+
|
8
|
+
var stopFactor = 1;
|
9
|
+
var isStopping = false;
|
10
|
+
var wasStopping = false;
|
11
|
+
|
12
|
+
var activeMargin = 0.4;
|
13
|
+
|
14
|
+
var scrollerPosition = options.scrollerPosition;
|
15
|
+
var scrollerMax = options.scrollerMax;
|
16
|
+
|
17
|
+
this.reset = function() {
|
18
|
+
targetSpeed = 0;
|
19
|
+
};
|
20
|
+
|
21
|
+
this.updateGyro = function(delta) {
|
22
|
+
this.updateTargetSpeed(Math.abs(delta) < 8 ? 0 : delta / 90);
|
23
|
+
};
|
24
|
+
|
25
|
+
this.updateMouse = function(fraction) {
|
26
|
+
var delta = fraction * 2 - 1;
|
27
|
+
var onOuterAreas = Math.abs(delta) > 1 - activeMargin;
|
28
|
+
|
29
|
+
this.updateTargetSpeed(onOuterAreas ?
|
30
|
+
(delta - ((1 - activeMargin) * sign(delta))) / activeMargin :
|
31
|
+
0);
|
32
|
+
};
|
33
|
+
|
34
|
+
this.updateTargetSpeed = function(value) {
|
35
|
+
targetSpeed = value;
|
36
|
+
};
|
37
|
+
|
38
|
+
this.getNextScrollDelta = function() {
|
39
|
+
convergeSpeed();
|
40
|
+
updateStopFactor();
|
41
|
+
updateSpeedIfStoppingAborted();
|
42
|
+
|
43
|
+
realSpeed = speed * stopFactor;
|
44
|
+
|
45
|
+
return -realSpeed * speedUp;
|
46
|
+
};
|
47
|
+
|
48
|
+
var i = 0;
|
49
|
+
|
50
|
+
function convergeSpeed() {
|
51
|
+
if (Math.abs(speed - targetSpeed) > 0.01) {
|
52
|
+
var d = Math.abs(targetSpeed) > Math.abs(speed) ? 0.02 : 0.04;
|
53
|
+
speed = limit(speed + d * sign(targetSpeed - speed), targetSpeed);
|
54
|
+
}
|
55
|
+
else {
|
56
|
+
speed = targetSpeed;
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
function limit(speed, targetSpeed) {
|
61
|
+
if (speed > targetSpeed) {
|
62
|
+
return Math.max(speed, targetSpeed);
|
63
|
+
}
|
64
|
+
else {
|
65
|
+
return Math.min(speed, targetSpeed);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
function updateStopFactor() {
|
70
|
+
isStopping = false;
|
71
|
+
stopFactor = 1;
|
72
|
+
|
73
|
+
if (scrollerPosition() < scrollerMax() * 0.8 && targetSpeed >= 0) {
|
74
|
+
stopFactor = (scrollerMax() - scrollerPosition()) / (scrollerMax() * 0.2);
|
75
|
+
isStopping = true;
|
76
|
+
}
|
77
|
+
|
78
|
+
if (scrollerPosition() > scrollerMax() * 0.2 && targetSpeed <= 0) {
|
79
|
+
stopFactor = scrollerPosition() / (scrollerMax() * 0.2);
|
80
|
+
isStopping = true;
|
81
|
+
}
|
82
|
+
|
83
|
+
if (stopFactor > 1) {
|
84
|
+
stopFactor = stopFactor;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
function updateSpeedIfStoppingAborted() {
|
89
|
+
if (wasStopping && !isStopping) {
|
90
|
+
speed = realSpeed;
|
91
|
+
}
|
92
|
+
|
93
|
+
wasStopping = isStopping;
|
94
|
+
}
|
95
|
+
|
96
|
+
function sign(value) {
|
97
|
+
return value > 0 ? 1 : -1;
|
98
|
+
}
|
99
|
+
};
|
@@ -0,0 +1,421 @@
|
|
1
|
+
(function($) {
|
2
|
+
$.widget('pageflow.linkmapPanorama', {
|
3
|
+
scrollHoverMargin : 0.2,
|
4
|
+
environmentMargin : 0.2,
|
5
|
+
minScaling: true,
|
6
|
+
minScalingSize: 80,
|
7
|
+
lastMouseMoveEvent: null,
|
8
|
+
|
9
|
+
_create: function() {
|
10
|
+
var that = this,
|
11
|
+
pageElement = this.options.page;
|
12
|
+
|
13
|
+
this.addEnvironment = this.options.addEnvironment;
|
14
|
+
this.panorama = this.options.panorama();
|
15
|
+
this.limitScrolling = this.options.limitScrolling;
|
16
|
+
this.scroller = this.options.scroller;
|
17
|
+
|
18
|
+
this.activeAreas = pageElement.find(this.options.activeAreasSelector);
|
19
|
+
this.panoramaWrapper = pageElement.find('.panorama_wrapper');
|
20
|
+
this.innerScrollerElement = pageElement.find('.linkmap');
|
21
|
+
this.overlayBox = pageElement.find('.description_overlay');
|
22
|
+
this.overlayInnerBox = pageElement.find('.description_overlay_wrapper');
|
23
|
+
this.overlayTitle = pageElement.find('.description_overlay .link_title');
|
24
|
+
this.overlayDescription = pageElement.find('.description_overlay .link_description');
|
25
|
+
|
26
|
+
this.startScrollPosition = _.clone(this.options.startScrollPosition);
|
27
|
+
|
28
|
+
this.currentScrollPosition = null;
|
29
|
+
|
30
|
+
this.refresh();
|
31
|
+
|
32
|
+
this.scroller.onScrollEnd(function() {
|
33
|
+
that.updateScrollPosition();
|
34
|
+
});
|
35
|
+
|
36
|
+
$(window).on('resize', function () {
|
37
|
+
that.centerToPoint(null, 0);
|
38
|
+
});
|
39
|
+
|
40
|
+
this.element.on('mousemove', function(e) {
|
41
|
+
that.lastMouseMoveEvent = e;
|
42
|
+
that.calcAreaOpacity(that.activeAreas, e.pageX, e.pageY);
|
43
|
+
});
|
44
|
+
|
45
|
+
pageElement.on('mouseenter', '.hover_area', function() {
|
46
|
+
positionOverlay($(this));
|
47
|
+
});
|
48
|
+
|
49
|
+
pageElement.on('click', function() {
|
50
|
+
that.overlayBox.removeClass('active');
|
51
|
+
that.activeAreas.removeClass('hover');
|
52
|
+
});
|
53
|
+
|
54
|
+
$('body').on('mouseleave', '.hover_area', function() {
|
55
|
+
that.overlayBox.removeClass('active');
|
56
|
+
});
|
57
|
+
|
58
|
+
pageElement.on('dragstart resizestart', '.hover_area', function() {
|
59
|
+
that.overlayBox.removeClass('active');
|
60
|
+
});
|
61
|
+
|
62
|
+
that.activeAreas.each(function() {
|
63
|
+
$(this).on('click touchstart', function(e) {
|
64
|
+
if (pageflow.browser.has('mobile platform')) {
|
65
|
+
if($(this).hasClass('hover')) {
|
66
|
+
that.activeAreas.removeClass('active');
|
67
|
+
$(this).addClass('active');
|
68
|
+
return;
|
69
|
+
}
|
70
|
+
that.activeAreas.removeClass('hover');
|
71
|
+
$(this).addClass('hover');
|
72
|
+
positionOverlay($(this));
|
73
|
+
return false;
|
74
|
+
}
|
75
|
+
else {
|
76
|
+
that.activeAreas.removeClass('active');
|
77
|
+
$(this).addClass('active');
|
78
|
+
}
|
79
|
+
})
|
80
|
+
});
|
81
|
+
|
82
|
+
var positionOverlay = function(area) {
|
83
|
+
if (area.is('.editing')) {
|
84
|
+
return;
|
85
|
+
}
|
86
|
+
|
87
|
+
var linkTitle = area.find('.link_title').html();
|
88
|
+
var linkDescription = area.find('.link_description').html();
|
89
|
+
|
90
|
+
if (linkTitle || linkDescription) {
|
91
|
+
that.overlayTitle.html(linkTitle);
|
92
|
+
that.overlayDescription.html(linkDescription);
|
93
|
+
|
94
|
+
that.overlayBox.addClass('active');
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
if(that.panorama.width() - (area.position().left + area.outerWidth()) < that.overlayBox.outerWidth()) {
|
99
|
+
var overlayAlignmentDirection = "left";
|
100
|
+
that.overlayBox.addClass('left_aligned');
|
101
|
+
}
|
102
|
+
else {
|
103
|
+
var spaceLeftOfArea = area.offset().left;
|
104
|
+
var spaceRightOfArea = $(window).width() - area.offset().left - area.outerWidth();
|
105
|
+
|
106
|
+
if(spaceLeftOfArea < spaceRightOfArea || spaceLeftOfArea < that.overlayBox.outerWidth()) {
|
107
|
+
var overlayAlignmentDirection = "right";
|
108
|
+
that.overlayBox.removeClass('left_aligned');
|
109
|
+
}
|
110
|
+
else {
|
111
|
+
var overlayAlignmentDirection = "left";
|
112
|
+
that.overlayBox.addClass('left_aligned');
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
if(overlayAlignmentDirection == "right") {
|
117
|
+
that.overlayBox.removeClass('left_aligned');
|
118
|
+
that.overlayBox.css({
|
119
|
+
'left': area.position().left + area.width(),
|
120
|
+
'top': area.position().top,
|
121
|
+
'margin-top': area.height() / 2
|
122
|
+
});
|
123
|
+
}
|
124
|
+
if(overlayAlignmentDirection == "left") {
|
125
|
+
that.overlayBox.addClass('left_aligned');
|
126
|
+
that.overlayBox.css({
|
127
|
+
'left': area.position().left - that.overlayBox.outerWidth(),
|
128
|
+
'top': area.position().top,
|
129
|
+
'margin-top': area.height() / 2
|
130
|
+
});
|
131
|
+
}
|
132
|
+
|
133
|
+
var spaceToBottom = that.panorama.height() - area.position().top;
|
134
|
+
var spaceToViewportBottom = $(window).height() - area.offset().top - area.height() / 2;
|
135
|
+
var spaceToViewportTop = $(window).height() - 50;
|
136
|
+
var minMargin = 40;
|
137
|
+
|
138
|
+
if(that.overlayBox.outerHeight() > spaceToBottom) {
|
139
|
+
that.overlayInnerBox.css('top', (spaceToBottom - that.overlayInnerBox.outerHeight() - minMargin - area.height() / 2) + 'px');
|
140
|
+
}
|
141
|
+
else {
|
142
|
+
that.overlayInnerBox.css('top', '0px');
|
143
|
+
}
|
144
|
+
var additionalMargin = 10;
|
145
|
+
|
146
|
+
if(spaceToViewportBottom < that.overlayBox.outerHeight() && that.overlayBox.outerHeight() + additionalMargin < spaceToViewportTop) {
|
147
|
+
additionalMargin = spaceToViewportBottom - that.overlayBox.outerHeight() - additionalMargin;
|
148
|
+
that.overlayInnerBox.css('top', additionalMargin + 'px');
|
149
|
+
}
|
150
|
+
else {
|
151
|
+
that.overlayInnerBox.css('top', '0px');
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
this.refresh();
|
157
|
+
},
|
158
|
+
|
159
|
+
calcAreaOpacity: function(activeAreas, mX, mY) {
|
160
|
+
if (pageflow.browser.has('mobile platform')) {
|
161
|
+
return;
|
162
|
+
}
|
163
|
+
|
164
|
+
var pageElement = this.options.page;
|
165
|
+
var distanceLimit = pageElement.width() > pageElement.height() ? pageElement.height() : pageElement.width();
|
166
|
+
var minOpacity = 0.4;
|
167
|
+
activeAreas.each(function() {
|
168
|
+
var distance = calculateDistance($(this), mX, mY);
|
169
|
+
|
170
|
+
if(distance <= distanceLimit) {
|
171
|
+
var opacity = 1 + minOpacity - Math.sqrt(distance / distanceLimit);
|
172
|
+
$(this).find('.linkmap_marker.no_transition').css('opacity', opacity);
|
173
|
+
}
|
174
|
+
else {
|
175
|
+
$(this).find('.linkmap_marker.no_transition').css('opacity', minOpacity);
|
176
|
+
}
|
177
|
+
|
178
|
+
|
179
|
+
});
|
180
|
+
|
181
|
+
function calculateDistance(elem, mouseX, mouseY) {
|
182
|
+
return Math.floor(Math.sqrt(Math.pow(mouseX - (elem.offset().left+(elem.width()/2)), 2) + Math.pow(mouseY - (elem.offset().top+(elem.height()/2)), 2)));
|
183
|
+
}
|
184
|
+
},
|
185
|
+
|
186
|
+
highlightAreas: function() {
|
187
|
+
var element = this.element;
|
188
|
+
element.find('.linkmap_marker').addClass('teasing');
|
189
|
+
|
190
|
+
setTimeout(function() {
|
191
|
+
element.find('.linkmap_marker').removeClass('teasing');
|
192
|
+
}, 1000);
|
193
|
+
|
194
|
+
setTimeout(function() {
|
195
|
+
element.find('.linkmap_marker').addClass('no_transition');
|
196
|
+
}, 2000);
|
197
|
+
},
|
198
|
+
|
199
|
+
resetAreaHighlighting: function() {
|
200
|
+
var element = this.element;
|
201
|
+
|
202
|
+
element.find('.linkmap_marker').removeClass('no_transition teasing');
|
203
|
+
element.find('.linkmap_marker').css('opacity', pageflow.browser.has('mobile platform') ? '0.8' : '0.4');
|
204
|
+
},
|
205
|
+
|
206
|
+
getScrollArea: function(activeAreas) {
|
207
|
+
var panorama = this.panorama;
|
208
|
+
var pageElement = this.options.page;
|
209
|
+
var startScrollPosition = this.startScrollPosition;
|
210
|
+
var scrollArea;
|
211
|
+
|
212
|
+
if (activeAreas.length && this.limitScrolling) {
|
213
|
+
scrollArea = {
|
214
|
+
top: this.startScrollPosition.y * panorama.height(),
|
215
|
+
left: this.startScrollPosition.x * panorama.width(),
|
216
|
+
bottom: this.startScrollPosition.y * panorama.height(),
|
217
|
+
right: this.startScrollPosition.x * panorama.width(),
|
218
|
+
};
|
219
|
+
|
220
|
+
activeAreas.each(function() {
|
221
|
+
var el = $(this);
|
222
|
+
|
223
|
+
scrollArea.top = scrollArea.top > el.position().top ? el.position().top : scrollArea.top;
|
224
|
+
scrollArea.left = scrollArea.left > el.position().left ? el.position().left : scrollArea.left;
|
225
|
+
scrollArea.bottom = scrollArea.bottom < el.position().top + el.height() ? el.position().top + el.height() : scrollArea.bottom;
|
226
|
+
scrollArea.right = scrollArea.right < el.position().left + el.width() ? el.position().left + el.width() : scrollArea.right;
|
227
|
+
});
|
228
|
+
|
229
|
+
scrollArea.top = Math.max(0, scrollArea.top - pageElement.height() * this.scrollHoverMargin);
|
230
|
+
scrollArea.left = Math.max(0, scrollArea.left - pageElement.width() * this.scrollHoverMargin);
|
231
|
+
scrollArea.bottom = Math.min(panorama.height(), scrollArea.bottom + pageElement.height() * this.scrollHoverMargin);
|
232
|
+
scrollArea.right = Math.min(panorama.width(), scrollArea.right + pageElement.width() * this.scrollHoverMargin);
|
233
|
+
}
|
234
|
+
else {
|
235
|
+
scrollArea = {
|
236
|
+
top: panorama.position().top,
|
237
|
+
left: panorama.position().left,
|
238
|
+
bottom: (panorama.position().top + panorama.height()),
|
239
|
+
right: (panorama.position().left + panorama.width()),
|
240
|
+
};
|
241
|
+
}
|
242
|
+
|
243
|
+
return scrollArea;
|
244
|
+
|
245
|
+
},
|
246
|
+
|
247
|
+
getMinScale: function(activeAreas) {
|
248
|
+
var smallestScale;
|
249
|
+
var that = this;
|
250
|
+
var minimumSize = this.minScalingSize;
|
251
|
+
var smallestSize = Math.min(this.panorama.attr('data-width'), this.panorama.attr('data-height'));
|
252
|
+
|
253
|
+
if(this.minScaling) {
|
254
|
+
|
255
|
+
for (var i = 0; i < activeAreas.length; i++) {
|
256
|
+
var el = $(activeAreas[i]);
|
257
|
+
|
258
|
+
if(el.attr('data-height') / 100 * that.panorama.attr('data-height') < smallestSize) {
|
259
|
+
smallestSize = el.attr('data-height') / 100 * that.panorama.attr('data-height');
|
260
|
+
}
|
261
|
+
if(el.attr('data-width') / 100 * that.panorama.attr('data-width') < smallestSize) {
|
262
|
+
smallestSize = el.attr('data-width') / 100 * that.panorama.attr('data-width');
|
263
|
+
}
|
264
|
+
smallestScale = minimumSize / smallestSize;
|
265
|
+
}
|
266
|
+
} else {
|
267
|
+
smallestScale = 0;
|
268
|
+
}
|
269
|
+
|
270
|
+
return smallestScale;
|
271
|
+
},
|
272
|
+
|
273
|
+
update: function(addEnvironment, limitScrolling, startScrollPosition, minScaling) {
|
274
|
+
this.addEnvironment = addEnvironment;
|
275
|
+
this.limitScrolling = limitScrolling;
|
276
|
+
this.startScrollPosition = _.clone(startScrollPosition);
|
277
|
+
this.minScaling = minScaling;
|
278
|
+
|
279
|
+
this.refresh();
|
280
|
+
},
|
281
|
+
|
282
|
+
refresh: function() {
|
283
|
+
this.keepingScrollPosition(function() {
|
284
|
+
var pageElement = this.options.page;
|
285
|
+
|
286
|
+
this.panorama = this.options.panorama();
|
287
|
+
|
288
|
+
this.panoramaSize = this.getPanoramaSize(pageElement);
|
289
|
+
this.panorama.width(this.panoramaSize.width);
|
290
|
+
this.panorama.height(this.panoramaSize.height);
|
291
|
+
|
292
|
+
this.activeAreas = pageElement.find(this.options.activeAreasSelector);
|
293
|
+
this.scrollArea = this.getScrollArea(this.activeAreas);
|
294
|
+
|
295
|
+
this.innerScrollerElement.addClass('measuring');
|
296
|
+
|
297
|
+
this.innerScrollerElement.width(this.scrollArea.right - this.scrollArea.left);
|
298
|
+
this.innerScrollerElement.height(this.scrollArea.bottom - this.scrollArea.top);
|
299
|
+
|
300
|
+
var maxTranslateX = this.panoramaSize.width - pageElement.width();
|
301
|
+
var maxTranslateY = this.panoramaSize.height - pageElement.height();
|
302
|
+
|
303
|
+
this.panoramaWrapper.css({
|
304
|
+
left: -Math.min(maxTranslateX, this.scrollArea.left) +'px',
|
305
|
+
top: -Math.min(maxTranslateY, this.scrollArea.top) + 'px'
|
306
|
+
});
|
307
|
+
|
308
|
+
this.innerScrollerElement.removeClass('measuring');
|
309
|
+
this.scroller.refresh();
|
310
|
+
|
311
|
+
var leftToCenterInnerScroller = (pageElement.width() - (this.scrollArea.right - this.scrollArea.left)) / 2;
|
312
|
+
var topToCenterInnerScroller = (pageElement.height() - (this.scrollArea.bottom - this.scrollArea.top)) / 2;
|
313
|
+
|
314
|
+
this.innerScrollerElement.css('left', (this.scroller.maxX() == 0 && this.panoramaSize.width > this.scrollArea.right - this.scrollArea.left ? Math.min(leftToCenterInnerScroller, this.scrollArea.left) : 0) + "px");
|
315
|
+
this.innerScrollerElement.css('top', (this.scroller.maxY() == 0 && this.panoramaSize.height > pageElement.height() ? Math.min(topToCenterInnerScroller, this.scrollArea.top) : 0) + "px");
|
316
|
+
});
|
317
|
+
},
|
318
|
+
|
319
|
+
getPanoramaSize: function(pageElement) {
|
320
|
+
var result = {};
|
321
|
+
var windowRatio = pageElement.width() / pageElement.height();
|
322
|
+
var environmentMargin = this.addEnvironment ? (1 + this.environmentMargin) : 1;
|
323
|
+
var smallestScale = this.getMinScale(this.activeAreas);
|
324
|
+
var imageRatio;
|
325
|
+
|
326
|
+
if (this.panorama.attr('data-height') > 0) {
|
327
|
+
imageRatio = this.panorama.attr('data-width') / this.panorama.attr('data-height');
|
328
|
+
}
|
329
|
+
else {
|
330
|
+
imageRatio = 1;
|
331
|
+
}
|
332
|
+
|
333
|
+
if(imageRatio > windowRatio) {
|
334
|
+
result.height = pageElement.height() * environmentMargin;
|
335
|
+
result.width = result.height * imageRatio;
|
336
|
+
}
|
337
|
+
else {
|
338
|
+
result.width = pageElement.width() * environmentMargin;
|
339
|
+
result.height = result.width / imageRatio;
|
340
|
+
}
|
341
|
+
|
342
|
+
if (result.width < this.panorama.attr('data-width') * smallestScale) {
|
343
|
+
result.width = this.panorama.attr('data-width') * smallestScale;
|
344
|
+
result.height = this.panorama.attr('data-height') * smallestScale;
|
345
|
+
}
|
346
|
+
|
347
|
+
return result;
|
348
|
+
},
|
349
|
+
|
350
|
+
resetScrollPosition: function() {
|
351
|
+
this.centerToPoint(this.panoramaToScroller(this.startScrollPosition), 0);
|
352
|
+
},
|
353
|
+
|
354
|
+
centerToPoint: function(point, time) {
|
355
|
+
point = point || this.currentScrollPosition;
|
356
|
+
|
357
|
+
var absoluteX = this.scroller.maxX() * point.x;
|
358
|
+
var absoluteY = this.scroller.maxY() * point.y;
|
359
|
+
|
360
|
+
this.scroller.scrollTo(absoluteX, absoluteY, time);
|
361
|
+
|
362
|
+
this.currentScrollPosition = this.currentScrollPosition || point;
|
363
|
+
},
|
364
|
+
|
365
|
+
keepingScrollPosition: function(fn) {
|
366
|
+
var panoramaPosition;
|
367
|
+
|
368
|
+
if (this.currentScrollPosition) {
|
369
|
+
panoramaPosition = this.scrollerToPanorama(this.currentScrollPosition);
|
370
|
+
}
|
371
|
+
else {
|
372
|
+
panoramaPosition = this.startScrollPosition;
|
373
|
+
}
|
374
|
+
|
375
|
+
fn.call(this);
|
376
|
+
|
377
|
+
this.centerToPoint(this.panoramaToScroller(panoramaPosition));
|
378
|
+
},
|
379
|
+
|
380
|
+
scrollerToPanorama: function(point) {
|
381
|
+
var scrollAreaWidth = (this.scrollArea.right - this.scrollArea.left);
|
382
|
+
var scrollAreaHeight = (this.scrollArea.bottom - this.scrollArea.top);
|
383
|
+
|
384
|
+
return {
|
385
|
+
x: this.panoramaSize.width === 0 ?
|
386
|
+
0 :
|
387
|
+
(this.scrollArea.left + point.x * scrollAreaWidth) / this.panoramaSize.width,
|
388
|
+
y: this.panoramaSize.height === 0?
|
389
|
+
0 :
|
390
|
+
(this.scrollArea.top + point.y * scrollAreaHeight) / this.panoramaSize.height
|
391
|
+
};
|
392
|
+
},
|
393
|
+
|
394
|
+
panoramaToScroller: function(point) {
|
395
|
+
var scrollAreaWidth = (this.scrollArea.right - this.scrollArea.left);
|
396
|
+
var scrollAreaHeight = (this.scrollArea.bottom - this.scrollArea.top);
|
397
|
+
|
398
|
+
return {
|
399
|
+
x: scrollAreaWidth === 0 ?
|
400
|
+
0 :
|
401
|
+
(point.x * this.panoramaSize.width - this.scrollArea.left) / scrollAreaWidth ,
|
402
|
+
y: scrollAreaHeight === 0 ?
|
403
|
+
0 :
|
404
|
+
(point.y * this.panoramaSize.height - this.scrollArea.top) / scrollAreaHeight
|
405
|
+
};
|
406
|
+
},
|
407
|
+
|
408
|
+
updateScrollPosition: function() {
|
409
|
+
var that = this;
|
410
|
+
|
411
|
+
setTimeout(function() {
|
412
|
+
that.currentScrollPosition.x = that.scroller.maxX() !== 0 ? that.scroller.positionX() / that.scroller.maxX() : 0;
|
413
|
+
that.currentScrollPosition.y = that.scroller.maxY() !== 0 ? that.scroller.positionY() / that.scroller.maxY() : 0;
|
414
|
+
}, 10);
|
415
|
+
|
416
|
+
if (this.lastMouseMoveEvent) {
|
417
|
+
this.calcAreaOpacity(this.activeAreas, this.lastMouseMoveEvent.pageX, this.lastMouseMoveEvent.pageY);
|
418
|
+
}
|
419
|
+
}
|
420
|
+
});
|
421
|
+
}(jQuery));
|