c80_map_floors 0.1.0.2 → 0.1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/admin/c80_map_floors/floors.rb +1 -1
- data/app/admin/c80_map_floors/map_buildings.rb +2 -2
- data/app/assets/javascripts/c80_map_floors.js.coffee +5 -2
- data/app/assets/javascripts/lib/spin.js +377 -0
- data/app/assets/javascripts/map_objects/building.js +13 -39
- data/app/assets/javascripts/src/image_loader.js +116 -0
- data/app/assets/javascripts/src/main.js +36 -25
- data/app/assets/stylesheets/view/elems/map_objects/map_object_image_bg.scss +13 -0
- data/app/assets/stylesheets/view/image_loader_preloader.scss +48 -0
- data/app/models/c80_map_floors/base_map_object.rb +2 -1
- data/app/models/c80_map_floors/map_building.rb +46 -0
- data/lib/c80_map_floors/version.rb +1 -1
- data/lib/integer.rb +6 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: caa429ebe88b99d0a303010a2794cae3935e8d30
|
4
|
+
data.tar.gz: 6d2440c4d8a4b1793f3ccc6ae2fde6065460f09a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59d17da106e56573b4e644b6ac22a65d5cff1376f0d83ef5cbe56342a610c1f07b56544da1911d2ef81f05674fb0947a1a45108213dd26b62903980c7c7003a1
|
7
|
+
data.tar.gz: fa3b4d8e7c6d3cf39e2da4c3c786eefbb4a892dff3235cf7c9eec9827f3c22f7d483c3380a196eceff1bfae19cecf7ce03c8fa948b90ee3e48e3d1e2afee928e
|
@@ -43,7 +43,7 @@ ActiveAdmin.register C80MapFloors::Floor, as: 'Floor' do
|
|
43
43
|
f.input :title
|
44
44
|
f.input :tag
|
45
45
|
f.input :ord
|
46
|
-
f.input :coords
|
46
|
+
f.input :coords, :input_html => {:style => 'height:80px'}
|
47
47
|
f.input :img_bg, :hint => "#{image_tag(f.object.img_bg.thumb.url)}".html_safe
|
48
48
|
# f.input :img_overlay, :hint => "#{image_tag(f.object.img_overlay.thumb.url)}".html_safe
|
49
49
|
f.input :map_building,
|
@@ -38,8 +38,8 @@ ActiveAdmin.register C80MapFloors::MapBuilding, as: 'MapBuilding' do
|
|
38
38
|
f.inputs 'Свойства' do
|
39
39
|
f.input :tag
|
40
40
|
f.input :title
|
41
|
-
f.input :coords
|
42
|
-
f.input :coords_img
|
41
|
+
f.input :coords, :input_html => {:style => 'height:50px'}
|
42
|
+
f.input :coords_img, :input_html => {:style => 'height:50px'}
|
43
43
|
# f.input :img, :hint => "#{image_tag(f.object.img.thumb.url) if f.object.img.present?}".html_safe
|
44
44
|
end
|
45
45
|
|
@@ -6,13 +6,15 @@
|
|
6
6
|
#= require bootstrap/dropdown
|
7
7
|
#= require bootstrap-select
|
8
8
|
|
9
|
+
#= require_tree ./lib
|
10
|
+
|
9
11
|
#= require ./svg_elements/helper.js
|
10
12
|
#= require ./svg_elements/polygon.js
|
11
13
|
#= require ./svg_elements/area_label.js
|
12
14
|
#= require ./svg_elements/building_label.js
|
13
15
|
|
14
|
-
#=
|
15
|
-
#=
|
16
|
+
#= require_tree ./events
|
17
|
+
#= require_tree ./map_objects
|
16
18
|
#= require_tree ./view
|
17
19
|
#= require_tree ./buttons
|
18
20
|
#= require_tree ./ui
|
@@ -21,4 +23,5 @@
|
|
21
23
|
#= require ./src/utils/opacity_buttons_utils.js
|
22
24
|
#= require ./src/utils/map_utils.js
|
23
25
|
#= require ./src/state_controller.js
|
26
|
+
#= require ./src/image_loader.js
|
24
27
|
#= require ./src/main.js
|
@@ -0,0 +1,377 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) 2011-2014 Felix Gnass
|
3
|
+
* Licensed under the MIT license
|
4
|
+
* http://spin.js.org/
|
5
|
+
*
|
6
|
+
* Example:
|
7
|
+
var opts = {
|
8
|
+
lines: 12 // The number of lines to draw
|
9
|
+
, length: 7 // The length of each line
|
10
|
+
, width: 5 // The line thickness
|
11
|
+
, radius: 10 // The radius of the inner circle
|
12
|
+
, scale: 1.0 // Scales overall size of the spinner
|
13
|
+
, corners: 1 // Roundness (0..1)
|
14
|
+
, color: '#000' // #rgb or #rrggbb
|
15
|
+
, opacity: 1/4 // Opacity of the lines
|
16
|
+
, rotate: 0 // Rotation offset
|
17
|
+
, direction: 1 // 1: clockwise, -1: counterclockwise
|
18
|
+
, speed: 1 // Rounds per second
|
19
|
+
, trail: 100 // Afterglow percentage
|
20
|
+
, fps: 20 // Frames per second when using setTimeout()
|
21
|
+
, zIndex: 2e9 // Use a high z-index by default
|
22
|
+
, className: 'spinner' // CSS class to assign to the element
|
23
|
+
, top: '50%' // center vertically
|
24
|
+
, left: '50%' // center horizontally
|
25
|
+
, shadow: false // Whether to render a shadow
|
26
|
+
, hwaccel: false // Whether to use hardware acceleration (might be buggy)
|
27
|
+
, position: 'absolute' // Element positioning
|
28
|
+
}
|
29
|
+
var target = document.getElementById('foo')
|
30
|
+
var spinner = new Spinner(opts).spin(target)
|
31
|
+
*/
|
32
|
+
;(function (root, factory) {
|
33
|
+
|
34
|
+
/* CommonJS */
|
35
|
+
if (typeof module == 'object' && module.exports) module.exports = factory()
|
36
|
+
|
37
|
+
/* AMD module */
|
38
|
+
else if (typeof define == 'function' && define.amd) define(factory)
|
39
|
+
|
40
|
+
/* Browser global */
|
41
|
+
else root.Spinner = factory()
|
42
|
+
}(this, function () {
|
43
|
+
"use strict"
|
44
|
+
|
45
|
+
var prefixes = ['webkit', 'Moz', 'ms', 'O'] /* Vendor prefixes */
|
46
|
+
, animations = {} /* Animation rules keyed by their name */
|
47
|
+
, useCssAnimations /* Whether to use CSS animations or setTimeout */
|
48
|
+
, sheet /* A stylesheet to hold the @keyframe or VML rules. */
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Utility function to create elements. If no tag name is given,
|
52
|
+
* a DIV is created. Optionally properties can be passed.
|
53
|
+
*/
|
54
|
+
function createEl (tag, prop) {
|
55
|
+
var el = document.createElement(tag || 'div')
|
56
|
+
, n
|
57
|
+
|
58
|
+
for (n in prop) el[n] = prop[n]
|
59
|
+
return el
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Appends children and returns the parent.
|
64
|
+
*/
|
65
|
+
function ins (parent /* child1, child2, ...*/) {
|
66
|
+
for (var i = 1, n = arguments.length; i < n; i++) {
|
67
|
+
parent.appendChild(arguments[i])
|
68
|
+
}
|
69
|
+
|
70
|
+
return parent
|
71
|
+
}
|
72
|
+
|
73
|
+
/**
|
74
|
+
* Creates an opacity keyframe animation rule and returns its name.
|
75
|
+
* Since most mobile Webkits have timing issues with animation-delay,
|
76
|
+
* we create separate rules for each line/segment.
|
77
|
+
*/
|
78
|
+
function addAnimation (alpha, trail, i, lines) {
|
79
|
+
var name = ['opacity', trail, ~~(alpha * 100), i, lines].join('-')
|
80
|
+
, start = 0.01 + i/lines * 100
|
81
|
+
, z = Math.max(1 - (1-alpha) / trail * (100-start), alpha)
|
82
|
+
, prefix = useCssAnimations.substring(0, useCssAnimations.indexOf('Animation')).toLowerCase()
|
83
|
+
, pre = prefix && '-' + prefix + '-' || ''
|
84
|
+
|
85
|
+
if (!animations[name]) {
|
86
|
+
sheet.insertRule(
|
87
|
+
'@' + pre + 'keyframes ' + name + '{' +
|
88
|
+
'0%{opacity:' + z + '}' +
|
89
|
+
start + '%{opacity:' + alpha + '}' +
|
90
|
+
(start+0.01) + '%{opacity:1}' +
|
91
|
+
(start+trail) % 100 + '%{opacity:' + alpha + '}' +
|
92
|
+
'100%{opacity:' + z + '}' +
|
93
|
+
'}', sheet.cssRules.length)
|
94
|
+
|
95
|
+
animations[name] = 1
|
96
|
+
}
|
97
|
+
|
98
|
+
return name
|
99
|
+
}
|
100
|
+
|
101
|
+
/**
|
102
|
+
* Tries various vendor prefixes and returns the first supported property.
|
103
|
+
*/
|
104
|
+
function vendor (el, prop) {
|
105
|
+
var s = el.style
|
106
|
+
, pp
|
107
|
+
, i
|
108
|
+
|
109
|
+
prop = prop.charAt(0).toUpperCase() + prop.slice(1)
|
110
|
+
if (s[prop] !== undefined) return prop
|
111
|
+
for (i = 0; i < prefixes.length; i++) {
|
112
|
+
pp = prefixes[i]+prop
|
113
|
+
if (s[pp] !== undefined) return pp
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
/**
|
118
|
+
* Sets multiple style properties at once.
|
119
|
+
*/
|
120
|
+
function css (el, prop) {
|
121
|
+
for (var n in prop) {
|
122
|
+
el.style[vendor(el, n) || n] = prop[n]
|
123
|
+
}
|
124
|
+
|
125
|
+
return el
|
126
|
+
}
|
127
|
+
|
128
|
+
/**
|
129
|
+
* Fills in default values.
|
130
|
+
*/
|
131
|
+
function merge (obj) {
|
132
|
+
for (var i = 1; i < arguments.length; i++) {
|
133
|
+
var def = arguments[i]
|
134
|
+
for (var n in def) {
|
135
|
+
if (obj[n] === undefined) obj[n] = def[n]
|
136
|
+
}
|
137
|
+
}
|
138
|
+
return obj
|
139
|
+
}
|
140
|
+
|
141
|
+
/**
|
142
|
+
* Returns the line color from the given string or array.
|
143
|
+
*/
|
144
|
+
function getColor (color, idx) {
|
145
|
+
return typeof color == 'string' ? color : color[idx % color.length]
|
146
|
+
}
|
147
|
+
|
148
|
+
// Built-in defaults
|
149
|
+
|
150
|
+
var defaults = {
|
151
|
+
lines: 12 // The number of lines to draw
|
152
|
+
, length: 7 // The length of each line
|
153
|
+
, width: 5 // The line thickness
|
154
|
+
, radius: 10 // The radius of the inner circle
|
155
|
+
, scale: 1.0 // Scales overall size of the spinner
|
156
|
+
, corners: 1 // Roundness (0..1)
|
157
|
+
, color: '#000' // #rgb or #rrggbb
|
158
|
+
, opacity: 1/4 // Opacity of the lines
|
159
|
+
, rotate: 0 // Rotation offset
|
160
|
+
, direction: 1 // 1: clockwise, -1: counterclockwise
|
161
|
+
, speed: 1 // Rounds per second
|
162
|
+
, trail: 100 // Afterglow percentage
|
163
|
+
, fps: 20 // Frames per second when using setTimeout()
|
164
|
+
, zIndex: 2e9 // Use a high z-index by default
|
165
|
+
, className: 'spinner' // CSS class to assign to the element
|
166
|
+
, top: '50%' // center vertically
|
167
|
+
, left: '50%' // center horizontally
|
168
|
+
, shadow: false // Whether to render a shadow
|
169
|
+
, hwaccel: false // Whether to use hardware acceleration (might be buggy)
|
170
|
+
, position: 'absolute' // Element positioning
|
171
|
+
}
|
172
|
+
|
173
|
+
/** The constructor */
|
174
|
+
function Spinner (o) {
|
175
|
+
this.opts = merge(o || {}, Spinner.defaults, defaults)
|
176
|
+
}
|
177
|
+
|
178
|
+
// Global defaults that override the built-ins:
|
179
|
+
Spinner.defaults = {}
|
180
|
+
|
181
|
+
merge(Spinner.prototype, {
|
182
|
+
/**
|
183
|
+
* Adds the spinner to the given target element. If this instance is already
|
184
|
+
* spinning, it is automatically removed from its previous target b calling
|
185
|
+
* stop() internally.
|
186
|
+
*/
|
187
|
+
spin: function (target) {
|
188
|
+
this.stop()
|
189
|
+
|
190
|
+
var self = this
|
191
|
+
, o = self.opts
|
192
|
+
, el = self.el = createEl(null, {className: o.className})
|
193
|
+
|
194
|
+
css(el, {
|
195
|
+
position: o.position
|
196
|
+
, width: 0
|
197
|
+
, zIndex: o.zIndex
|
198
|
+
, left: o.left
|
199
|
+
, top: o.top
|
200
|
+
})
|
201
|
+
|
202
|
+
if (target) {
|
203
|
+
target.insertBefore(el, target.firstChild || null)
|
204
|
+
}
|
205
|
+
|
206
|
+
el.setAttribute('role', 'progressbar')
|
207
|
+
self.lines(el, self.opts)
|
208
|
+
|
209
|
+
if (!useCssAnimations) {
|
210
|
+
// No CSS animation support, use setTimeout() instead
|
211
|
+
var i = 0
|
212
|
+
, start = (o.lines - 1) * (1 - o.direction) / 2
|
213
|
+
, alpha
|
214
|
+
, fps = o.fps
|
215
|
+
, f = fps / o.speed
|
216
|
+
, ostep = (1 - o.opacity) / (f * o.trail / 100)
|
217
|
+
, astep = f / o.lines
|
218
|
+
|
219
|
+
;(function anim () {
|
220
|
+
i++
|
221
|
+
for (var j = 0; j < o.lines; j++) {
|
222
|
+
alpha = Math.max(1 - (i + (o.lines - j) * astep) % f * ostep, o.opacity)
|
223
|
+
|
224
|
+
self.opacity(el, j * o.direction + start, alpha, o)
|
225
|
+
}
|
226
|
+
self.timeout = self.el && setTimeout(anim, ~~(1000 / fps))
|
227
|
+
})()
|
228
|
+
}
|
229
|
+
return self
|
230
|
+
}
|
231
|
+
|
232
|
+
/**
|
233
|
+
* Stops and removes the Spinner.
|
234
|
+
*/
|
235
|
+
, stop: function () {
|
236
|
+
var el = this.el
|
237
|
+
if (el) {
|
238
|
+
clearTimeout(this.timeout)
|
239
|
+
if (el.parentNode) el.parentNode.removeChild(el)
|
240
|
+
this.el = undefined
|
241
|
+
}
|
242
|
+
return this
|
243
|
+
}
|
244
|
+
|
245
|
+
/**
|
246
|
+
* Internal method that draws the individual lines. Will be overwritten
|
247
|
+
* in VML fallback mode below.
|
248
|
+
*/
|
249
|
+
, lines: function (el, o) {
|
250
|
+
var i = 0
|
251
|
+
, start = (o.lines - 1) * (1 - o.direction) / 2
|
252
|
+
, seg
|
253
|
+
|
254
|
+
function fill (color, shadow) {
|
255
|
+
return css(createEl(), {
|
256
|
+
position: 'absolute'
|
257
|
+
, width: o.scale * (o.length + o.width) + 'px'
|
258
|
+
, height: o.scale * o.width + 'px'
|
259
|
+
, background: color
|
260
|
+
, boxShadow: shadow
|
261
|
+
, transformOrigin: 'left'
|
262
|
+
, transform: 'rotate(' + ~~(360/o.lines*i + o.rotate) + 'deg) translate(' + o.scale*o.radius + 'px' + ',0)'
|
263
|
+
, borderRadius: (o.corners * o.scale * o.width >> 1) + 'px'
|
264
|
+
})
|
265
|
+
}
|
266
|
+
|
267
|
+
for (; i < o.lines; i++) {
|
268
|
+
seg = css(createEl(), {
|
269
|
+
position: 'absolute'
|
270
|
+
, top: 1 + ~(o.scale * o.width / 2) + 'px'
|
271
|
+
, transform: o.hwaccel ? 'translate3d(0,0,0)' : ''
|
272
|
+
, opacity: o.opacity
|
273
|
+
, animation: useCssAnimations && addAnimation(o.opacity, o.trail, start + i * o.direction, o.lines) + ' ' + 1 / o.speed + 's linear infinite'
|
274
|
+
})
|
275
|
+
|
276
|
+
if (o.shadow) ins(seg, css(fill('#000', '0 0 4px #000'), {top: '2px'}))
|
277
|
+
ins(el, ins(seg, fill(getColor(o.color, i), '0 0 1px rgba(0,0,0,.1)')))
|
278
|
+
}
|
279
|
+
return el
|
280
|
+
}
|
281
|
+
|
282
|
+
/**
|
283
|
+
* Internal method that adjusts the opacity of a single line.
|
284
|
+
* Will be overwritten in VML fallback mode below.
|
285
|
+
*/
|
286
|
+
, opacity: function (el, i, val) {
|
287
|
+
if (i < el.childNodes.length) el.childNodes[i].style.opacity = val
|
288
|
+
}
|
289
|
+
|
290
|
+
})
|
291
|
+
|
292
|
+
|
293
|
+
function initVML () {
|
294
|
+
|
295
|
+
/* Utility function to create a VML tag */
|
296
|
+
function vml (tag, attr) {
|
297
|
+
return createEl('<' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr)
|
298
|
+
}
|
299
|
+
|
300
|
+
// No CSS transforms but VML support, add a CSS rule for VML elements:
|
301
|
+
sheet.addRule('.spin-vml', 'behavior:url(#default#VML)')
|
302
|
+
|
303
|
+
Spinner.prototype.lines = function (el, o) {
|
304
|
+
var r = o.scale * (o.length + o.width)
|
305
|
+
, s = o.scale * 2 * r
|
306
|
+
|
307
|
+
function grp () {
|
308
|
+
return css(
|
309
|
+
vml('group', {
|
310
|
+
coordsize: s + ' ' + s
|
311
|
+
, coordorigin: -r + ' ' + -r
|
312
|
+
})
|
313
|
+
, { width: s, height: s }
|
314
|
+
)
|
315
|
+
}
|
316
|
+
|
317
|
+
var margin = -(o.width + o.length) * o.scale * 2 + 'px'
|
318
|
+
, g = css(grp(), {position: 'absolute', top: margin, left: margin})
|
319
|
+
, i
|
320
|
+
|
321
|
+
function seg (i, dx, filter) {
|
322
|
+
ins(
|
323
|
+
g
|
324
|
+
, ins(
|
325
|
+
css(grp(), {rotation: 360 / o.lines * i + 'deg', left: ~~dx})
|
326
|
+
, ins(
|
327
|
+
css(
|
328
|
+
vml('roundrect', {arcsize: o.corners})
|
329
|
+
, { width: r
|
330
|
+
, height: o.scale * o.width
|
331
|
+
, left: o.scale * o.radius
|
332
|
+
, top: -o.scale * o.width >> 1
|
333
|
+
, filter: filter
|
334
|
+
}
|
335
|
+
)
|
336
|
+
, vml('fill', {color: getColor(o.color, i), opacity: o.opacity})
|
337
|
+
, vml('stroke', {opacity: 0}) // transparent stroke to fix color bleeding upon opacity change
|
338
|
+
)
|
339
|
+
)
|
340
|
+
)
|
341
|
+
}
|
342
|
+
|
343
|
+
if (o.shadow)
|
344
|
+
for (i = 1; i <= o.lines; i++) {
|
345
|
+
seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)')
|
346
|
+
}
|
347
|
+
|
348
|
+
for (i = 1; i <= o.lines; i++) seg(i)
|
349
|
+
return ins(el, g)
|
350
|
+
}
|
351
|
+
|
352
|
+
Spinner.prototype.opacity = function (el, i, val, o) {
|
353
|
+
var c = el.firstChild
|
354
|
+
o = o.shadow && o.lines || 0
|
355
|
+
if (c && i + o < c.childNodes.length) {
|
356
|
+
c = c.childNodes[i + o]; c = c && c.firstChild; c = c && c.firstChild
|
357
|
+
if (c) c.opacity = val
|
358
|
+
}
|
359
|
+
}
|
360
|
+
}
|
361
|
+
|
362
|
+
if (typeof document !== 'undefined') {
|
363
|
+
sheet = (function () {
|
364
|
+
var el = createEl('style', {type : 'text/css'})
|
365
|
+
ins(document.getElementsByTagName('head')[0], el)
|
366
|
+
return el.sheet || el.styleSheet
|
367
|
+
}())
|
368
|
+
|
369
|
+
var probe = css(createEl('group'), {behavior: 'url(#default#VML)'})
|
370
|
+
|
371
|
+
if (!vendor(probe, 'transform') && probe.adj) initVML()
|
372
|
+
else useCssAnimations = vendor(probe, 'animation')
|
373
|
+
}
|
374
|
+
|
375
|
+
return Spinner
|
376
|
+
|
377
|
+
}));
|
@@ -21,7 +21,7 @@ function Building() {
|
|
21
21
|
var _cx = null;
|
22
22
|
var _cy = null;
|
23
23
|
|
24
|
-
var
|
24
|
+
var _$image_bg = null;
|
25
25
|
var _image_overlay = null;
|
26
26
|
|
27
27
|
var _zoomToMe = function () {
|
@@ -33,31 +33,7 @@ function Building() {
|
|
33
33
|
//console.log("<Building.enter> scaleX = " + scaleX + ", scaleY = " + scaleY);
|
34
34
|
|
35
35
|
var scale = (scaleX < scaleY) ? scaleX : scaleY;
|
36
|
-
|
37
|
-
//var selfY = _map.calcCoord(scale, _map.Y1, _bbox.ymin);
|
38
|
-
|
39
|
-
//_map.scale = scale;
|
40
|
-
//_map.x = selfX;
|
41
|
-
//_map.y = selfY;
|
42
|
-
|
43
|
-
/* по-отдельности */
|
44
|
-
|
45
|
-
//var scaleX = _map.calcScale(_bbox.xmin, _bbox.xmax, _map.X1, _map.X2);
|
46
|
-
//console.log("<Building.enter> scaleX = " + scaleX);
|
47
|
-
//var selfX = _map.calcCoord(scaleX, _map.X1, _bbox.xmin);
|
48
|
-
//_map.scale = scaleX;
|
49
|
-
//_map.x = selfX;
|
50
|
-
|
51
|
-
//var scaleY = _map.calcScale(_bbox.ymin, _bbox.ymax, _map.Y1, _map.Y2);
|
52
|
-
//console.log("<Building.enter> scaleY = " + scaleY);
|
53
|
-
//var selfY = _map.calcCoord(scaleY, _map.Y1, _bbox.ymin);
|
54
|
-
//_map.scale = scaleY;
|
55
|
-
//_map.y = selfY;
|
56
|
-
|
57
|
-
// совмещаем точку на экране, в которую надо центрировать дома, с центром дома с учётом рассчитанного масштаба
|
58
|
-
// или, другими словами, перегоняем логические координаты в систему координат экрана
|
59
|
-
//_map.x = _map.normalizeX(_map.CX - scale * _cx - _map.container.offset().left);
|
60
|
-
//_map.y = _map.normalizeY(_map.CY - scale * _cy - _map.container.offset().top);
|
36
|
+
scale = _map.normalizeScale(scale);
|
61
37
|
|
62
38
|
var x = _map.normalizeX({
|
63
39
|
x: _map.CX - scale * _cx - _map.container.offset().left,
|
@@ -126,13 +102,11 @@ function Building() {
|
|
126
102
|
yy2 = parseInt(tmp2[1]);
|
127
103
|
}
|
128
104
|
|
129
|
-
//
|
130
|
-
_map.
|
105
|
+
// пока не загрузили картинку этажа - не будем удалять отображённые картинки этажей, отметим их "для удаления"
|
106
|
+
_map.mark_all_map_object_images_for_clean();
|
131
107
|
|
132
108
|
// просим карту нарисовать картинку с данными характеристиками
|
133
|
-
|
134
|
-
//x: _bbox.xmin,
|
135
|
-
//y: _bbox.ymin,
|
109
|
+
_$image_bg = _map.draw_map_object_image_bg(the_floor["img_bg"]["url"], {
|
136
110
|
x: xx + xx2,
|
137
111
|
y: yy + yy2,
|
138
112
|
width: the_floor["img_bg_width"],
|
@@ -214,7 +188,7 @@ function Building() {
|
|
214
188
|
|
215
189
|
_zoomToMe();
|
216
190
|
|
217
|
-
|
191
|
+
setTimeout(function () {
|
218
192
|
|
219
193
|
// попросим изменить состояние окружающей среды
|
220
194
|
_map.setMode('view_building');
|
@@ -222,16 +196,16 @@ function Building() {
|
|
222
196
|
// запустим внутренний механизм парсинга этажей и их отрисовки
|
223
197
|
_proccess_floors_data();
|
224
198
|
|
225
|
-
|
199
|
+
_map.building_info_klass.setSelectedFloor(0);
|
226
200
|
|
201
|
+
}, 400);
|
202
|
+
|
203
|
+
// при входе в здание удаляем все кликабельные полигоны зданий
|
227
204
|
_map.svgRemoveAllNodes();
|
228
205
|
|
229
206
|
//console.log("<Building.enter> id: " + _this.id);
|
230
207
|
_map.mark_virgin = false;
|
231
208
|
|
232
|
-
//
|
233
|
-
_map.building_info_klass.setSelectedFloor(0);
|
234
|
-
|
235
209
|
};
|
236
210
|
|
237
211
|
/**
|
@@ -249,14 +223,14 @@ function Building() {
|
|
249
223
|
}
|
250
224
|
|
251
225
|
|
252
|
-
}
|
226
|
+
};
|
253
227
|
|
254
228
|
_this.exit = function () {
|
255
|
-
if (
|
229
|
+
if (_$image_bg != null) _$image_bg.remove();
|
256
230
|
if (_image_overlay != null) {
|
257
231
|
_image_overlay.remove();
|
258
232
|
}
|
259
|
-
|
233
|
+
_$image_bg = null;
|
260
234
|
_image_overlay = null;
|
261
235
|
//_zoomToMe();
|
262
236
|
};
|
@@ -0,0 +1,116 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
function ImageLoader() {
|
4
|
+
|
5
|
+
var _this = this;
|
6
|
+
|
7
|
+
//--[ private ]----------------------------------------------------------------------------------------------------------------------
|
8
|
+
|
9
|
+
/** Показать прелоадер в диве $target.
|
10
|
+
*
|
11
|
+
* @param $target
|
12
|
+
* @param params {x,y,width,height} - габариты и местонах. прелоадера
|
13
|
+
* @private
|
14
|
+
*/
|
15
|
+
_this._preloader_show = function ($target, params) {
|
16
|
+
|
17
|
+
var left = params["x"];
|
18
|
+
var top = params["y"];
|
19
|
+
var width = params["width"];
|
20
|
+
var height = params["height"];
|
21
|
+
|
22
|
+
var $a = $('<div class="anim"></div>');
|
23
|
+
|
24
|
+
var $d = $('<div></div>')
|
25
|
+
.css('top', top)
|
26
|
+
.css('left', left)
|
27
|
+
.css('width', width)
|
28
|
+
.css('height', height)
|
29
|
+
.append('<span class="helper"></span>')
|
30
|
+
.append($a)
|
31
|
+
.addClass('image_loader_preloader')
|
32
|
+
.appendTo($target);
|
33
|
+
|
34
|
+
var spinner = new Spinner().spin();
|
35
|
+
$a[0].appendChild(spinner.el);
|
36
|
+
|
37
|
+
$d.addClass('shown');
|
38
|
+
|
39
|
+
};
|
40
|
+
|
41
|
+
_this._preloader_hide = function ($target) {
|
42
|
+
var $ilp = $target.find('.image_loader_preloader');
|
43
|
+
$ilp.removeClass('shown');
|
44
|
+
setTimeout(function () {
|
45
|
+
$ilp.remove();
|
46
|
+
}, 400);
|
47
|
+
};
|
48
|
+
|
49
|
+
//--[ public ]----------------------------------------------------------------------------------------------------------------------
|
50
|
+
|
51
|
+
/** Загрузить картинку и отобразить её в options["$target"].
|
52
|
+
* Процесс оснастить прелоадером.
|
53
|
+
* Показать картинку плавно.
|
54
|
+
*
|
55
|
+
* @param img_src урл картинки
|
56
|
+
* @param options { $target, params }, где:
|
57
|
+
* - $target: див, к которому надо прикрепить картинку
|
58
|
+
* - params: {x,y,width,height} - габариты и местонах. картинки
|
59
|
+
*/
|
60
|
+
_this.load = function (img_src, options) {
|
61
|
+
|
62
|
+
console.log('<ImageLoader.load> ' + img_src);
|
63
|
+
|
64
|
+
// покажем прелоадер
|
65
|
+
_this._preloader_show(options["$target"], options["params"]);
|
66
|
+
|
67
|
+
// создадим картинку
|
68
|
+
var img = new Image();
|
69
|
+
var $img = $(img);
|
70
|
+
|
71
|
+
// настроим картинку
|
72
|
+
$img.data('top', options['params']['y'])
|
73
|
+
.data('left', options['params']['x'])
|
74
|
+
.data('width', options['params']['width'])
|
75
|
+
.data('height', options['params']['height'])
|
76
|
+
.addClass('map_object_image_bg'); /* этот класс используем при [zoomove]*/
|
77
|
+
|
78
|
+
img.onload = function () {
|
79
|
+
|
80
|
+
// NOTE:: разделим вставку в DOM и отображение: в mozilla картинка отображается постепенно прорисовываясь сверху вниз, некрасиво
|
81
|
+
|
82
|
+
$img.appendTo(options["$target"]);
|
83
|
+
|
84
|
+
setTimeout(function () {
|
85
|
+
|
86
|
+
// спрячем прелоадер
|
87
|
+
_this._preloader_hide(options["$target"]);
|
88
|
+
|
89
|
+
// сделаем картинку видимой
|
90
|
+
$img.addClass('shown');
|
91
|
+
|
92
|
+
// вызовем колбэк
|
93
|
+
if (options['on_load'] != undefined) {
|
94
|
+
options['on_load']( $img );
|
95
|
+
}
|
96
|
+
|
97
|
+
}, 300);
|
98
|
+
|
99
|
+
};
|
100
|
+
|
101
|
+
// отобразим картинку
|
102
|
+
img.src = img_src;
|
103
|
+
|
104
|
+
return $img;
|
105
|
+
|
106
|
+
};
|
107
|
+
|
108
|
+
//--[ run ]----------------------------------------------------------------------------------------------------------------------
|
109
|
+
|
110
|
+
var _fInit = function () {
|
111
|
+
|
112
|
+
};
|
113
|
+
|
114
|
+
_fInit();
|
115
|
+
|
116
|
+
}
|
@@ -89,7 +89,7 @@ var clog = function () {
|
|
89
89
|
self.drawn_buildings = []; // если имеются нарисованные но несохранённые Здания - они хранятся тут
|
90
90
|
self.save_preloader_klass = null;
|
91
91
|
self.last_clicked_g = null; // начали просматривать area\building (запустили сессию), и здесь храним ссылку на последний кликнутый полигон из svg_overlay в течение сессии
|
92
|
-
self.dnd_enable = null; // если да, то можно карту dnd мышкой
|
92
|
+
//self.o.dnd_enable = null; // если да, то можно карту dnd мышкой
|
93
93
|
self.building_info_klass = null; // класс, занимающися отображением данных об этаже\здании\площади
|
94
94
|
|
95
95
|
// во время анимации каждый шаг рассчитывается мгновенный scale
|
@@ -106,7 +106,13 @@ var clog = function () {
|
|
106
106
|
// чтобы вернуть карту в исходное состояние после нажатия кнопки "назад на карту"
|
107
107
|
self.initial_map_position = null;
|
108
108
|
|
109
|
+
// грузит и отображает картинки заранее известного размера (WxH px), показывает прелоадер
|
110
|
+
self._imageLoader = null;
|
111
|
+
|
109
112
|
self.init = function (el, params) {
|
113
|
+
|
114
|
+
console.log('<Map.init>');
|
115
|
+
|
110
116
|
// extend options
|
111
117
|
self.o = $.extend(self.o, params);
|
112
118
|
|
@@ -219,6 +225,8 @@ var clog = function () {
|
|
219
225
|
sc.init(self);
|
220
226
|
self.setMode = sc.setMode;
|
221
227
|
|
228
|
+
self._imageLoader = new ImageLoader();
|
229
|
+
|
222
230
|
// Admin buttons
|
223
231
|
$.ajax({
|
224
232
|
url: '/ajax/map_edit_buttons',
|
@@ -442,7 +450,7 @@ var clog = function () {
|
|
442
450
|
// Drag & drop
|
443
451
|
function onDragNdrop(event) {
|
444
452
|
//clog("<mousedown> edit_type = " + self.edit_type);
|
445
|
-
|
453
|
+
console.log("<mousedown> mode = " + self.mode + " dnd_enable = " + self.o.dnd_enable);
|
446
454
|
//clog(event);
|
447
455
|
|
448
456
|
// если в данный момент не редактируем фигуру (т.е. не двигаем вершину фигуры)
|
@@ -462,7 +470,7 @@ var clog = function () {
|
|
462
470
|
self.map.on('mousemove', function (event) {
|
463
471
|
self.dragging = true;
|
464
472
|
|
465
|
-
if (self.dnd_enable) {
|
473
|
+
if (self.o.dnd_enable) { // NOTE:: добавить возможность делать dnd находясь в режиме рисования (админа?)
|
466
474
|
var x = event.pageX - map.data('mouseX') + self.x;
|
467
475
|
var y = event.pageY - map.data('mouseY') + self.y;
|
468
476
|
|
@@ -835,44 +843,45 @@ var clog = function () {
|
|
835
843
|
* <div class='map_object_image_bg'> // style='background-image:url(#{img_src});'
|
836
844
|
* <img src=#{img_src} />
|
837
845
|
* </div>
|
838
|
-
* и помещает его map_layers
|
846
|
+
* и помещает его в map_layers
|
839
847
|
*
|
840
848
|
* left и top - координаты bound box верхнего левого угла здания
|
841
849
|
*
|
850
|
+
* В новой версии используем предварительную загрузку картинки,
|
851
|
+
* и показ прелоадера во время загрузки. Когда картинка загрузится,
|
852
|
+
* она будет отображена на экране.
|
842
853
|
*/
|
843
854
|
self.draw_map_object_image_bg = function (img_src, params) {
|
844
|
-
//console.log('<draw_map_object_image_bg>');
|
845
855
|
|
846
856
|
// породим DOM
|
847
857
|
var $div_map_object_image_bg = $('<div></div>')
|
848
858
|
.addClass('mlayer')
|
849
|
-
|
850
|
-
.appendTo(self.map_layers); // .hide()
|
859
|
+
.appendTo(self.map_layers);
|
851
860
|
|
852
|
-
//
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
var $img = $('<img>')
|
859
|
-
.data('top', top)
|
860
|
-
.data('left', left)
|
861
|
-
.data('width', width)
|
862
|
-
.data('height', height)
|
863
|
-
.attr('src', img_src)
|
864
|
-
.addClass('map_object_image_bg') /* этот класс используем при [zoomove]*/
|
865
|
-
.appendTo($div_map_object_image_bg);
|
861
|
+
// загрузим в него картинку
|
862
|
+
return self._imageLoader.load(img_src, {
|
863
|
+
$target: $div_map_object_image_bg,
|
864
|
+
params: params,
|
865
|
+
on_load: self._draw_map_object_image_bg_onload
|
866
|
+
});
|
866
867
|
|
867
|
-
|
868
|
-
self.__compose_css_style_for_map_object_image($img);
|
868
|
+
};
|
869
869
|
|
870
|
-
|
870
|
+
self._draw_map_object_image_bg_onload = function ($image) {
|
871
|
+
self.clear_all_map_object_image_bg();
|
872
|
+
self.__compose_css_style_for_map_object_image($image); // рассчитаем позиционирующий стиль и применим его к созданной оверлейной картинке
|
873
|
+
};
|
871
874
|
|
875
|
+
self.mark_all_map_object_images_for_clean = function () {
|
876
|
+
$('.map_object_image_bg').addClass('for_clean');
|
872
877
|
};
|
873
878
|
|
874
879
|
self.clear_all_map_object_image_bg = function () {
|
875
|
-
$('.map_object_image_bg')
|
880
|
+
var $cc = $('.map_object_image_bg.for_clean');
|
881
|
+
$cc.removeClass('shown');
|
882
|
+
setTimeout(function () {
|
883
|
+
$cc.parent().remove();
|
884
|
+
},400);
|
876
885
|
};
|
877
886
|
|
878
887
|
/**
|
@@ -897,6 +906,8 @@ var clog = function () {
|
|
897
906
|
var width = $i.data("width")*self.scale_during_animation;
|
898
907
|
var height = $i.data("height")*self.scale_during_animation;
|
899
908
|
|
909
|
+
console.log('<__compose_css_style_for_map_object_image>');
|
910
|
+
|
900
911
|
// впишем в DOM стили
|
901
912
|
var style = 'top:';
|
902
913
|
style += top + 'px;';
|
@@ -7,4 +7,17 @@ img.map_object_image_bg {
|
|
7
7
|
-ms-user-select: none;
|
8
8
|
user-select: none;
|
9
9
|
width: auto;
|
10
|
+
|
11
|
+
opacity: 0;
|
12
|
+
|
13
|
+
transition: opacity 0.4s ease-in-out;
|
14
|
+
-webkit-transition: opacity 0.4s ease-in-out;
|
15
|
+
-moz-transition: opacity 0.4s ease-in-out;
|
16
|
+
-ms-transition: opacity 0.4s ease-in-out;
|
17
|
+
-o-transition: opacity 0.4s ease-in-out;
|
18
|
+
|
19
|
+
&.shown {
|
20
|
+
opacity: 1;
|
21
|
+
}
|
22
|
+
|
10
23
|
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
div.image_loader_preloader {
|
2
|
+
position: absolute;
|
3
|
+
|
4
|
+
-webkit-touch-callout: none;
|
5
|
+
-webkit-user-select: none;
|
6
|
+
-khtml-user-select: none;
|
7
|
+
-moz-user-select: none;
|
8
|
+
-ms-user-select: none;
|
9
|
+
user-select: none;
|
10
|
+
width: auto;
|
11
|
+
|
12
|
+
/*background-color: rgba(0, 0, 0, .01);*/
|
13
|
+
/*display: none;*/
|
14
|
+
opacity: 0;
|
15
|
+
|
16
|
+
transition: all 0.4s ease-in-out;
|
17
|
+
-webkit-transition: all 0.4s ease-in-out;
|
18
|
+
-moz-transition: all 0.4s ease-in-out;
|
19
|
+
-ms-transition: all 0.4s ease-in-out;
|
20
|
+
-o-transition: all 0.4s ease-in-out;
|
21
|
+
|
22
|
+
text-align: center; /*!*/
|
23
|
+
white-space: nowrap; /*!*/
|
24
|
+
|
25
|
+
span.helper {
|
26
|
+
display: inline-block; /*!*/
|
27
|
+
vertical-align: middle; /*!*/
|
28
|
+
height: 100%; /*!*/
|
29
|
+
}
|
30
|
+
|
31
|
+
.anim {
|
32
|
+
position: relative;
|
33
|
+
width: 20px;
|
34
|
+
height: 20px;
|
35
|
+
vertical-align: middle; /*!*/
|
36
|
+
display: inline-block;
|
37
|
+
|
38
|
+
/*background-color: rgba(0, 0, 0, .1);*/
|
39
|
+
|
40
|
+
}
|
41
|
+
|
42
|
+
|
43
|
+
&.shown {
|
44
|
+
/*background-color: rgba(0, 0, 0, .4);*/
|
45
|
+
opacity: 1;
|
46
|
+
}
|
47
|
+
|
48
|
+
}
|
@@ -16,7 +16,8 @@ module C80MapFloors
|
|
16
16
|
# has_many :map_buildings, :as => :building_representator, :class_name => 'C80MapFloors::MapBuilding', :dependent => :destroy
|
17
17
|
after_save :update_json
|
18
18
|
# after_destroy :update_json
|
19
|
-
validates :coords, uniqueness: true
|
19
|
+
# validates :coords, uniqueness: true
|
20
|
+
validates_uniqueness_of :coords, :allow_nil => true, :allow_blank => true
|
20
21
|
|
21
22
|
def update_json
|
22
23
|
MapJson.update_json
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'c80_map_floors/base_map_object'
|
2
|
+
require 'integer'
|
2
3
|
|
3
4
|
module C80MapFloors
|
4
5
|
class MapBuilding < ActiveRecord::Base
|
@@ -7,6 +8,9 @@ module C80MapFloors
|
|
7
8
|
belongs_to :building_representator, :polymorphic => true
|
8
9
|
# validates :coords, uniqueness: true
|
9
10
|
# after_save :update_json
|
11
|
+
|
12
|
+
after_create :calc_coords_img
|
13
|
+
|
10
14
|
acts_as_base_map_object
|
11
15
|
|
12
16
|
mount_uploader :img, C80MapFloors::BuildingImageUploader
|
@@ -35,6 +39,48 @@ module C80MapFloors
|
|
35
39
|
}.merge(options || {} ))
|
36
40
|
end
|
37
41
|
|
42
|
+
def calc_coords_img
|
43
|
+
|
44
|
+
cs = self.coords.split(',') # 511,71,511,71,497,88,497,110,865,196,865,172,876,155
|
45
|
+
|
46
|
+
#-> Рассчитаем весь bounding box, но вернём только верхний левый угол
|
47
|
+
|
48
|
+
xmin = Integer::MAX.to_f
|
49
|
+
ymin = Integer::MAX.to_f
|
50
|
+
xmax = Integer::MIN.to_f
|
51
|
+
ymax = Integer::MIN.to_f
|
52
|
+
|
53
|
+
(0..cs.count-1).step(2) do |i|
|
54
|
+
|
55
|
+
ix = cs[i].to_f
|
56
|
+
iy = cs[i+1].to_f
|
57
|
+
|
58
|
+
# Rails.logger.debug "[TRACE] <map_building.calc> #{ix}, #{iy}"
|
59
|
+
|
60
|
+
xmin = ix < xmin ? ix : xmin
|
61
|
+
ymin = iy < ymin ? iy : ymin
|
62
|
+
|
63
|
+
xmax = ix > xmax ? ix : xmax
|
64
|
+
ymax = iy > ymax ? iy : ymax
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
# bbox = {
|
69
|
+
# xmin: xmin,
|
70
|
+
# ymin: ymin,
|
71
|
+
# xmax: xmax,
|
72
|
+
# ymax: ymax
|
73
|
+
# }
|
74
|
+
|
75
|
+
str = [
|
76
|
+
'%.01f' % xmin,
|
77
|
+
'%.01f' % ymin
|
78
|
+
].join(',')
|
79
|
+
|
80
|
+
self.update_column(:coords_img, str)
|
81
|
+
|
82
|
+
end
|
83
|
+
|
38
84
|
# private
|
39
85
|
|
40
86
|
# def update_json
|
data/lib/integer.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: c80_map_floors
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.
|
4
|
+
version: 0.1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- C80609A
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -124,10 +124,12 @@ files:
|
|
124
124
|
- app/assets/javascripts/buttons/zoom_buttons.js
|
125
125
|
- app/assets/javascripts/c80_map_floors.js.coffee
|
126
126
|
- app/assets/javascripts/events/app_event.js
|
127
|
+
- app/assets/javascripts/lib/spin.js
|
127
128
|
- app/assets/javascripts/map_objects/area.js
|
128
129
|
- app/assets/javascripts/map_objects/building.js
|
129
130
|
- app/assets/javascripts/map_objects/dot.js
|
130
131
|
- app/assets/javascripts/map_objects/floor.js
|
132
|
+
- app/assets/javascripts/src/image_loader.js
|
131
133
|
- app/assets/javascripts/src/main.js
|
132
134
|
- app/assets/javascripts/src/state_controller.js
|
133
135
|
- app/assets/javascripts/src/utils/map_utils.js
|
@@ -147,6 +149,7 @@ files:
|
|
147
149
|
- app/assets/stylesheets/view/elems/building_info.scss
|
148
150
|
- app/assets/stylesheets/view/elems/free_areas_label.scss
|
149
151
|
- app/assets/stylesheets/view/elems/map_objects/map_object_image_bg.scss
|
152
|
+
- app/assets/stylesheets/view/image_loader_preloader.scss
|
150
153
|
- app/assets/stylesheets/view/modal_window.scss
|
151
154
|
- app/assets/stylesheets/view/save_preloader.scss
|
152
155
|
- app/controllers/c80_map_floors/ajax_controller.rb
|
@@ -194,6 +197,7 @@ files:
|
|
194
197
|
- lib/c80_map_floors.rb
|
195
198
|
- lib/c80_map_floors/engine.rb
|
196
199
|
- lib/c80_map_floors/version.rb
|
200
|
+
- lib/integer.rb
|
197
201
|
homepage: http://www.vorsa-park.ru
|
198
202
|
licenses:
|
199
203
|
- MIT
|