/
utils.js
153 lines (142 loc) · 5.92 KB
/
utils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Make inheritance bearable: clone one level of properties
MM.extend = function(child, parent) {
for (var property in parent.prototype) {
if (typeof child.prototype[property] == "undefined") {
child.prototype[property] = parent.prototype[property];
}
}
return child;
};
MM.getFrame = function () {
// native animation frames
// http://webstuff.nfshost.com/anim-timing/Overview.html
// http://dev.chromium.org/developers/design-documents/requestanimationframe-implementation
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// can't apply these directly to MM because Chrome needs window
// to own webkitRequestAnimationFrame (for example)
// perhaps we should namespace an alias onto window instead?
// e.g. window.mmRequestAnimationFrame?
return function(callback) {
(window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
window.setTimeout(function () {
callback(+new Date());
}, 10);
})(callback);
};
}();
// Inspired by LeafletJS
MM.transformProperty = (function(props) {
if (!this.document) return; // node.js safety
var style = document.documentElement.style;
for (var i = 0; i < props.length; i++) {
if (props[i] in style) {
return props[i];
}
}
return false;
})(['transformProperty', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
MM.matrixString = function(point) {
// Make the result of point.scale * point.width a whole number.
if (point.scale * point.width % 1) {
point.scale += (1 - point.scale * point.width % 1) / point.width;
}
if (MM._browser.webkit3d) {
return 'matrix3d(' +
[(point.scale || '1'), '0,0,0,0',
(point.scale || '1'), '0,0',
'0,0,1,0',
(point.x + (((point.width * point.scale) - point.width) / 2)).toFixed(4),
(point.y + (((point.height * point.scale) - point.height) / 2)).toFixed(4),
0,1].join(',') + ')';
} else {
var unit = (MM.transformProperty == 'MozTransform') ? 'px' : '';
return 'matrix(' +
[(point.scale || '1'), 0, 0,
(point.scale || '1'),
(point.x + (((point.width * point.scale) - point.width) / 2)) + unit,
(point.y + (((point.height * point.scale) - point.height) / 2)) + unit
].join(',') + ')';
}
};
MM._browser = (function(window) {
return {
webkit: ('WebKitCSSMatrix' in window),
webkit3d: ('WebKitCSSMatrix' in window) && ('m11' in new WebKitCSSMatrix())
};
})(this); // use this for node.js global
MM.moveElement = function(el, point) {
if (MM.transformProperty) {
// Optimize for identity transforms, where you don't actually
// need to change this element's string. Browsers can optimize for
// the .style.left case but not for this CSS case.
var ms = MM.matrixString(point);
if (el[MM.transformProperty] !== ms) {
el.style[MM.transformProperty] =
el[MM.transformProperty] = ms;
}
} else {
el.style.left = point.x + 'px';
el.style.top = point.y + 'px';
el.style.width = Math.ceil(point.width * point.scale) + 'px';
el.style.height = Math.ceil(point.height * point.scale) + 'px';
}
};
// Events
// Cancel an event: prevent it from bubbling
MM.cancelEvent = function(e) {
// there's more than one way to skin this cat
e.cancelBubble = true;
e.cancel = true;
e.returnValue = false;
if (e.stopPropagation) { e.stopPropagation(); }
if (e.preventDefault) { e.preventDefault(); }
return false;
};
// From underscore.js
MM.bind = function(func, obj) {
var slice = Array.prototype.slice;
var nativeBind = Function.prototype.bind;
if (func.bind === nativeBind && nativeBind) {
return nativeBind.apply(func, slice.call(arguments, 1));
}
var args = slice.call(arguments, 2);
return function() {
return func.apply(obj, args.concat(slice.call(arguments)));
};
};
// see http://ejohn.org/apps/jselect/event.html for the originals
MM.addEvent = function(obj, type, fn) {
if (obj.addEventListener) {
obj.addEventListener(type, fn, false);
if (type == 'mousewheel') {
obj.addEventListener('DOMMouseScroll', fn, false);
}
} else if (obj.attachEvent) {
obj['e'+type+fn] = fn;
obj[type+fn] = function(){ obj['e'+type+fn](window.event); };
obj.attachEvent('on'+type, obj[type+fn]);
}
};
MM.removeEvent = function( obj, type, fn ) {
if (obj.removeEventListener) {
obj.removeEventListener(type, fn, false);
if (type == 'mousewheel') {
obj.removeEventListener('DOMMouseScroll', fn, false);
}
} else if (obj.detachEvent) {
obj.detachEvent('on'+type, obj[type+fn]);
obj[type+fn] = null;
}
};
// Cross-browser function to get current element style property
MM.getStyle = function(el,styleProp) {
if (el.currentStyle)
return el.currentStyle[styleProp];
else if (window.getComputedStyle)
return document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
};