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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6acbfc5688ec8e6b14430cc033efc22aecd3367c
4
- data.tar.gz: a5e9b23bf22b43fd8ef7c1df5c6d07edad1336a0
3
+ metadata.gz: caa429ebe88b99d0a303010a2794cae3935e8d30
4
+ data.tar.gz: 6d2440c4d8a4b1793f3ccc6ae2fde6065460f09a
5
5
  SHA512:
6
- metadata.gz: df5dd1c8a930be07ac3078171fdb989b149f5fd9d7c7971cd1c2db4460eaccbb21d477fa4594c4efdcc231f721ce9e1c3169bbbf33e4358a8a1ae0effa5adaf8
7
- data.tar.gz: 47b31d1c1d37dba45c2eee482da8fce399a9b3018b77e43bd27e8b43c0e21b5309465a97f34c8acbded1d4a147021d131f2bbdc5fa3c7e5d166919310158b216
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
- #= require_directory ./events
15
- #= require_directory ./map_objects
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 _image_bg = null;
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
- //var selfX = _map.calcCoord(scale, _map.X1, _bbox.xmin);
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
- // сначала попросим карту очистить слой с img_bg картинками
130
- _map.clear_all_map_object_image_bg();
105
+ // пока не загрузили картинку этажа - не будем удалять отображённые картинки этажей, отметим их "для удаления"
106
+ _map.mark_all_map_object_images_for_clean();
131
107
 
132
108
  // просим карту нарисовать картинку с данными характеристиками
133
- _image_bg = _map.draw_map_object_image_bg(the_floor["img_bg"]["url"], {
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
- //setTimeout(function () {
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
- //}, 400);
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 (_image_bg != null) _image_bg.remove();
229
+ if (_$image_bg != null) _$image_bg.remove();
256
230
  if (_image_overlay != null) {
257
231
  _image_overlay.remove();
258
232
  }
259
- _image_bg = null;
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
- clog("<mousedown> mode = " + self.mode);
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
- //.attr('style','background-image:url("'+img_src+'")')
850
- .appendTo(self.map_layers); // .hide()
859
+ .appendTo(self.map_layers);
851
860
 
852
- // сохраним начальные параметры в data
853
- var left = params["x"];
854
- var top = params["y"];
855
- var width = params["width"];
856
- var height = params["height"];
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
- return $div_map_object_image_bg;
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').parent().remove();
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
@@ -1,3 +1,3 @@
1
1
  module C80MapFloors
2
- VERSION = "0.1.0.2"
2
+ VERSION = '0.1.0.3'
3
3
  end
data/lib/integer.rb ADDED
@@ -0,0 +1,6 @@
1
+ class Integer
2
+ N_BYTES = [42].pack('i').size
3
+ N_BITS = N_BYTES * 16
4
+ MAX = 2 ** (N_BITS - 2) - 1
5
+ MIN = -MAX - 1
6
+ end
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.2
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-10-26 00:00:00.000000000 Z
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