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 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