c80_map_floors 0.1.0.2 → 0.1.0.3
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 +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
|