FineBI按屏幕自适应插件。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

661 lines
28 KiB

!(function () {
var scale = 1, transformY = 0, selected = true, globalScaleRatio = parseFloat(BI.Cache.getItem('scaleRatio')) || null;
var html = document.getElementsByTagName('html')[0];
var wrapper = document.getElementById("wrapper");
var scrollContainer = document.createElement("div");
var fixedWrapper = document.createElement("div");
var fixedContainer = document.createElement('div'); // tooltip等fixed元素
scrollContainer.style.width = "100%";
scrollContainer.style.height = "100%";
fixedContainer.style.position = "absolute";
fixedContainer.style.top = "0";
fixedContainer.style.left = "0";
fixedContainer.style.width = "100%";
fixedContainer.style.height = "100%";
document.body.appendChild(scrollContainer);
scrollContainer.appendChild(fixedWrapper);
fixedWrapper.appendChild(wrapper);
wrapper.appendChild(fixedContainer);
var jQuery = $ || window.jQuery;
var injectOffset = jQuery.fn.offset;
var injectEventFix = jQuery.event.fix;
var injectMouseInBounds = jQuery.fn.__isMouseInBounds__;
var injectToolTipShow = null;
var injectBubblesShow = null;
var adjustHeight = BI.Combo.prototype.adjustHeight;
var originalRender = BI.Widget._renderEngine;
var injectSearchSearchStop = BI.Searcher.prototype._stopSearch;
var injectTooltipsShow = BI.TooltipsController.prototype.show;
var injectSwitcherPopup = BI.Switcher.prototype.populate;
var injectSwitcherAdjustView = BI.Switcher.prototype.adjustView;
var injectCreate = BI.createWidget;
var callback = function () {};
BI.Searcher.prototype._search = function (result, searchResult, keyword) {
var self = this, o = this.options, keyword = o.allowSearchBlank ? this.editor.getValue() : this._getLastSearchKeyword();
if (keyword === "" || this._stop) {
return;
}
if (o.isAutoSearch) {
var items = (o.adapter && ((o.adapter.getItems && o.adapter.getItems()) || o.adapter.attr("items"))) || [];
var finding = BI.Func.getSearchResult(items, keyword);
var match = finding.match, find = finding.find;
this.popupView.populate(find, match, keyword);
o.isAutoSync && o.adapter && o.adapter.getValue && this.popupView.setValue(o.adapter.getValue());
self.fireEvent(BI.Searcher.EVENT_SEARCHING);
callback && callback.call(self, true);
return;
}
this.popupView.loading && this.popupView.loading();
o.onSearch({
times: 1,
keyword: keyword,
selectedValues: o.adapter && o.adapter.getValue()
}, function (searchResult, matchResult) {
if (!self._stop) {
var args = [].slice.call(arguments);
if (args.length > 0) {
args.push(keyword);
}
BI.Maskers.show(self.getName());
self.popupView.populate.apply(self.popupView, args);
o.isAutoSync && o.adapter && o.adapter.getValue && self.popupView.setValue(o.adapter.getValue());
self.popupView.loaded && self.popupView.loaded();
self.fireEvent(BI.Searcher.EVENT_SEARCHING);
callback && callback.call(self);
}
});
};
// 修正事件偏移
function correctEvent(e) {
if (e && !e.corrected) {
e.pageX = e.pageX / scale;
e.pageY = (e.pageY - transformY) / scale;
e.clientX = e.clientX / scale;
e.clientY = (e.clientY - transformY) / scale;
e.corrected = true;
}
return e;
}
function checkInPopupView(el) {
var t = el.parentElement;
var flag = false;
do {
if (t.className && t.className.indexOf("bi-popup-view") !== -1) {
flag = true;
break;
}
t = t.parentElement
} while (t);
return flag;
}
// 进行缩放
function transformScale(ratio) {
var bounds = getScaleBounds(ratio);
scale = bounds.scale;
wrapper.style.width = bounds.width + "px";
wrapper.style.height = bounds.height + "px";
wrapper.style.transform = "scale(" + bounds.scale+ ")";
wrapper.style.transformOrigin = "top left";
wrapper.style["-ms-transform"] = "scale(" + bounds.scale+ ")";
wrapper.style["-ms-transform-origin"] = "top left";
wrapper.style.overflow = "hidden";
html.style.backgroundColor = "#ffffff";
scrollContainer.style.overflowX = globalScaleRatio === null ? "hidden" : "auto";
scrollContainer.style.overflowY = "auto";
fixedWrapper.style.overflow = "hidden";
fixedWrapper.style.width = bounds.width * scale + "px";
fixedWrapper.style.height = bounds.height * scale + "px";
window.scale = Math.max(window.devicePixelRatio * scale, 1);
}
// 取消缩放
function removeScale() {
wrapper.style.width = "100%";
wrapper.style.height = "100%";
wrapper.style.transform = "";
wrapper.style.transformOrigin = "";
wrapper.style["-ms-transform"] = "";
wrapper.style["-ms-transform-origin"] = "";
wrapper.style.overflow = "hidden";
wrapper.style.top = "";
html.style.backgroundColor = "#ffffff";
scrollContainer.style.overflow = "hidden";
fixedWrapper.style.overflow = "hidden";
fixedWrapper.style.width = "100%";
fixedWrapper.style.height = "100%";
scale = 1;
window.scale = window.devicePixelRatio;
}
// 获取缩放倍数,原模板宽高
function getScaleBounds(ratio) {
var widgets = BI.designConfigure.widgets,
layoutRatio = BI.designConfigure.layoutRatio,
freeLayoutRatio = BI.designConfigure.freeLayoutRatio,
freeWidgets = BI.designConfigure.freeWidgetIds;
if (Object.keys(widgets).length === 0) {
return {
scale: 1,
width: html.clientWidth,
height: html.clientHeight
}
}
var left = null, right = null, top = null, bottom = null,
freeLeft = null, freeRight = null, freeTop = null, freeBottom = null;
BI.each(widgets, function (wId, widget) {
var bounds = widget.bounds || {};
if (BI.contains(freeWidgets, wId)) {
freeLeft = BI.isNull(freeLeft) ? bounds.left : Math.min(freeLeft, bounds.left);
freeRight = Math.max(freeRight, bounds.left + bounds.width);
freeTop = BI.isNull(freeTop) ? bounds.top : Math.min(freeTop, bounds.top);
freeBottom = Math.max(freeBottom, bounds.top + bounds.height);
} else {
left = BI.isNull(left) ? bounds.left : Math.min(left, bounds.left);
right = Math.max(right, bounds.left + bounds.width);
top = BI.isNull(top) ? bounds.top : Math.min(top, bounds.top);
bottom = Math.max(bottom, bounds.top + bounds.height);
}
});
var templateWidth = (Math.round((right / (layoutRatio.x || 1)) || (freeRight / (freeLayoutRatio.x || 1)))) + 60;
var templateHeight = (Math.round((bottom / (layoutRatio.y || 1)) || (freeBottom / (freeLayoutRatio.y || 1)))) + 30;
var scaleRatio = parseFloat((html.clientWidth / templateWidth).toFixed(1));
var resultWidth = 0;
var resultHeight = 0;
var bHeight = 0;
if (ratio) {
scaleRatio = ratio;
bHeight = html.clientHeight / scaleRatio;
resultWidth = templateWidth;
resultHeight = Math.max(bHeight, templateHeight);
} else {
bHeight = html.clientHeight / scaleRatio;
resultWidth = html.clientWidth / scaleRatio;
resultHeight = Math.max(bHeight, scaleRatio === 1 ? html.clientHeight : templateHeight);
}
return {
scale: scaleRatio,
width: resultWidth,
height: resultHeight
};
}
// 准备环境,主要是纠正事件偏移
function prepareEnv() {
// IE的fixed元素不受transform:scale影响
injectToolTipShow = injectToolTipShow || BI.Tooltips.show;
injectBubblesShow = injectBubblesShow || BI.Bubbles.show;
jQuery.fn.__isMouseInBounds__ = function (e) {
var offset2Body = this.get(0).getBoundingClientRect ? this.get(0).getBoundingClientRect() : this.offset();
var width = offset2Body.width || this.outerWidth();
var height = offset2Body.height || this.outerHeight();
var pageX = e.clientX * scale,
pageY = e.clientY * scale + transformY;
return !(pageX < Math.floor(offset2Body.left) || pageX > offset2Body.left + width
|| pageY < Math.floor(offset2Body.top) || pageY > offset2Body.top + height);
};
jQuery.fn.offset = function( options ) {
function getWindow( elem ) {
return jQuery.isWindow( elem ) ?
elem :
elem.nodeType === 9 ?
elem.defaultView || elem.parentWindow :
false;
}
if ( arguments.length ) {
return options === undefined ?
this :
this.each(function( i ) {
jQuery.offset.setOffset( this, options, i );
});
}
var docElem, win,
box = { top: 0, left: 0 },
elem = this[ 0 ],
doc = elem && elem.ownerDocument;
if ( !doc ) {
return;
}
docElem = doc.documentElement;
// Make sure it's not a disconnected DOM node
if ( !jQuery.contains( docElem, elem ) ) {
return box;
}
var el = elem,
offsetLeft = 0,
offsetTop = 0;
do{
offsetLeft += ( BI.isIE() ? window.getComputedStyle(el).position === "fixed" ? el.offsetLeft / scale : el.offsetLeft : el.offsetLeft );
offsetTop += ( BI.isIE() ? window.getComputedStyle(el).position === "fixed" ? el.offsetTop / scale : el.offsetTop : el.offsetTop );
el = el.offsetParent;
} while( el );
var elm = elem;
if (!checkInPopupView(elm)) {
do{
if (elm === document.body) {
break;
}
offsetLeft -= elm.scrollLeft || 0;
offsetTop -= elm.scrollTop || 0;
elm = elm.offsetParent;
} while( elm );
}
win = getWindow( doc );
return {
top: offsetTop + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
left: offsetLeft + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
};
};
jQuery.event.fix = function ( e ) {
return correctEvent(injectEventFix.call(this, e));
};
// Popovers
BI.Popovers = new BI.PopoverController({render: fixedContainer});
if (BI.isIE()) {
BI.Combo.prototype.adjustHeight = function (e) {
adjustHeight.call(this, e);
var transformX = scrollContainer.scrollLeft;
var transformY = scrollContainer.scrollTop;
if (this.popupView) {
if (!checkInPopupView(this.popupView.element[0])) {
this.popupView.element[0].style.left = parseInt(this.popupView.element[0].style.left) * scale - transformX + "px";
this.popupView.element[0].style.top = parseInt(this.popupView.element[0].style.top) * scale - transformY + "px";
} else {
var cBounds = BI.extend({}, this.popupView.element[0].getBoundingClientRect());
var pBounds = BI.extend({}, this.popupView.element[0].parentElement.getBoundingClientRect());
var hasScale = this.popupView.element[0].style.transform && this.popupView.element[0].style.transform.includes("scale");
var minWidth = parseInt(this.popupView.element[0].style.minWidth);
var minHeight = parseInt(this.popupView.element[0].style.minHeight);
cBounds.width = Math.max(cBounds.width, minWidth * scale);
cBounds.height = Math.max(cBounds.height, minHeight * scale);
if ((cBounds.left * scale + cBounds.width * (hasScale ? 1 : scale)) - transformX > body.clientWidth) {
this.popupView.element[0].style.top = parseInt(pBounds.bottom) + "px";
this.popupView.element[0].style.left = parseInt(this.popupView.element[0].style.left) * scale - transformX + "px";
} else if (this.options.direction === "right") {
this.popupView.element[0].style.top = parseInt(pBounds.top) + "px";
this.popupView.element[0].style.left = parseInt(pBounds.right) + "px";
} else if (parseInt(cBounds.top) >= parseInt(pBounds.top) && parseInt(cBounds.left) >= parseInt(pBounds.left)) {
this.popupView.element[0].style.top = parseInt(pBounds.bottom) + "px";
this.popupView.element[0].style.left = parseInt(pBounds.left) + "px";
}else if (parseInt(cBounds.top) >= parseInt(pBounds.top) && parseInt(cBounds.left) < parseInt(pBounds.left)) {
this.popupView.element[0].style.top = parseInt(pBounds.bottom) + "px";
this.popupView.element[0].style.left = parseInt(Math.min(pBounds.left, body.clientWidth - cBounds.width)) - transformX + "px";
} else {
this.popupView.element[0].style.top = parseInt(pBounds.bottom) + "px";
this.popupView.element[0].style.left = parseInt(cBounds.left) * scale + "px";
}
}
this.popupView.element[0].style.transform = "scale(" + scale+ ")";
this.popupView.element[0].style.transformOrigin = "top left";
}
};
BI.Bubbles.show = function (name, text, context, opt) {
injectBubblesShow.call(this, name, text, context, opt);
var tooltip = this.get(name);
var transformX = scrollContainer.scrollLeft / scale, transformY = scrollContainer.scrollTop / scale;
tooltip.element[0].style.left = parseInt(tooltip.element[0].style.left) * scale - transformX + "px";
tooltip.element[0].style.top = parseInt(tooltip.element[0].style.top) * scale - transformY + "px";
tooltip.element[0].style.transform = "scale(" + scale+ ")";
tooltip.element[0].style.transformOrigin = "top left";
}
var tempAdd = BI.Popovers.add;
BI.Popovers.add = function (name, popover, options, context) {
tempAdd.call(this, name, popover, options, context);
if (this.floatContainer[name].options.cls && this.floatContainer[name].options.cls.includes("bi-popup-view")) {
this.floatContainer[name].element[0].style.setProperty("position", "absolute", "important");
}
}
// Searcher
callback = function (flag) {
var self = this;
BI.defer(function () {
if (self.popupView && self.popupView.element[0].parentElement) {
var skip = BI.isNotEmptyString(self.popupView.element[0].parentElement.style.transformOrigin) && flag;
if (!skip) {
self.popupView.element[0].parentElement.style.left = parseInt(self.popupView.element[0].parentElement.style.left) * scale + "px";
self.popupView.element[0].parentElement.style.top = parseInt(self.popupView.element[0].parentElement.style.top) * scale + "px";
self.popupView.element[0].parentElement.style.transform = "scale(" + scale + ")";
self.popupView.element[0].parentElement.style.transformOrigin = "left top";
}
}
})
}
BI.Searcher.prototype._stopSearch = function () {
injectSearchSearchStop.apply(this, arguments);
if (this.popupView && this.popupView.element[0].parentElement) {
this.popupView.element[0].parentElement.style.transform = "";
this.popupView.element[0].parentElement.style.transformOrigin = "";
}
}
// switcher
BI.Switcher.prototype.populate = function (items) {
injectSwitcherPopup.apply(this, arguments);
var self = this;
BI.defer(function () {
if (self.popupView) {
self.popupView.element[0].parentElement.style.left = parseInt(self.popupView.element[0].parentElement.style.left) * scale + "px";
self.popupView.element[0].parentElement.style.top = parseInt(self.popupView.element[0].parentElement.style.top) * scale + "px";
self.popupView.element[0].parentElement.style.transform = "scale(" + scale + ")";
self.popupView.element[0].parentElement.style.transformOrigin = "left top";
}
})
}
BI.Switcher.prototype.adjustView = function () {
injectSwitcherAdjustView.apply(this, arguments);
if (this.popupView) {
this.popupView.element[0].parentElement.style.left = parseInt(this.popupView.element[0].parentElement.style.left) * scale + "px";
this.popupView.element[0].parentElement.style.top = parseInt(this.popupView.element[0].parentElement.style.top) * scale + "px";
this.popupView.element[0].parentElement.style.transform = "scale(" + scale + ")";
this.popupView.element[0].parentElement.style.transformOrigin = "left top";
}
}
}
BI.createWidget = function () {
if (arguments[0] && arguments[0].element === "body") {
arguments[0].element = fixedContainer;
}
return injectCreate.apply(this, arguments);
};
BI.Widget.registerRenderEngine({
createElement: function (widget) {
if (widget === "body") {
return BI.$(wrapper);
}
return originalRender.createElement(widget);
},
createFragment: function () {
return originalRender.createFragment();
}
});
BI.TooltipsController.prototype.show = function (e, name, text, level, context, opt) {
opt || (opt = {});
var self = this;
BI.each(this.showingTips, function (i, tip) {
self.hide(i);
});
this.showingTips = {};
if (!this.has(name)) {
this.create(name, text, level, opt.container || "body");
}
if (!opt.belowMouse) {
var offset = context.element.offset();
var bounds = context.element.bounds();
if (bounds.height === 0 || bounds.width === 0) {
return;
}
var top = offset.top + bounds.height + 5;
}
var tooltip = this.get(name);
tooltip.setText(text);
tooltip.element.css({
left: "0px",
top: "0px"
});
tooltip.visible();
tooltip.element.height(tooltip.element[0].scrollHeight);
this.showingTips[name] = true;
// scale影响要计算在内
// var scale = context.element.offset().left / context.element.get(0).getBoundingClientRect().left;
// var x = (e.pageX || e.clientX) * scale + 15, y = (e.pageY || e.clientY) * scale + 15;
var x = (e.pageX || e.clientX) + 15, y = (e.pageY || e.clientY) + 15;
var originY = 0;
if (BI.isIE()) {
x = x * scale;
y = y * scale;
} else {
x = x + scrollContainer.scrollLeft / scale;
}
if (x + tooltip.element.outerWidth() > BI.Widget._renderEngine.createElement("body").outerWidth()) {
x -= tooltip.element.outerWidth() + 15;
}
var bodyHeight = BI.Widget._renderEngine.createElement("body").outerHeight();
if (y + tooltip.element.outerHeight() > bodyHeight || top + tooltip.element.outerHeight() > bodyHeight) {
y -= tooltip.element.outerHeight() + 15;
originY = y;
!opt.belowMouse && (y = Math.min(y, offset.top - tooltip.element.outerHeight() - 5));
} else {
originY = y;
!opt.belowMouse && (y = Math.max(y, top));
}
tooltip.element.css({
left: x < 0 ? 0 : x + "px",
top: y < 0 ? 0 : y + "px"
});
tooltip.element.hover(function () {
self.remove(name);
context.element.trigger("mouseleave.title" + context.getName());
});
if (BI.isIE()) {
tooltip.element[0].style.transform = "scale(" + scale+ ")";
tooltip.element[0].style.transformOrigin = "top left";
}
return this;
}
window.addEventListener('resize', updateScale);
window.matchMedia && window.matchMedia('screen and (min-resolution: 2dppx)').
addListener(selectHandler);
}
function restoreEnv() {
jQuery.fn.__isMouseInBounds__ = injectMouseInBounds;
jQuery.fn.offset = injectOffset;
jQuery.event.fix = injectEventFix;
if (BI.isIE()) {
BI.Combo.prototype.adjustHeight = adjustHeight;
BI.Tooltips.show = injectToolTipShow;
BI.Bubbles.show = injectBubblesShow;
}
BI.createWidget = injectCreate;
// Popovers
BI.Popovers = new BI.PopoverController();
BI.Widget.registerRenderEngine(originalRender);
callback = function () {}
BI.Switcher.prototype.populate = injectSwitcherPopup;
BI.Switcher.prototype.adjustView = injectSwitcherAdjustView;
BI.TooltipsController.prototype.show = injectTooltipsShow;
document.body.onmousedown = null;
window.removeEventListener('resize', updateScale);
window.matchMedia && window.matchMedia('screen and (min-resolution: 2dppx)').
removeListener(selectHandler);
}
var selectHandler = BI.debounce(function () {
selected && prepareEnv();
selected ? transformScale(globalScaleRatio) : removeScale();
!selected && restoreEnv();
}, 30);
function updateScale () {
if (html.getBoundingClientRect().width !== wrapper.getBoundingClientRect().width) {
selectHandler();
}
}
var injectCaptureMouseMoves = BI.MouseMoveTracker.prototype.captureMouseMoves;
var injectOnMouseMove = BI.MouseMoveTracker.prototype._onMouseMove;
// 用jQEvent代替MouseEvent
function injectMouseMoveTracker() {
BI.MouseMoveTracker.prototype.captureMouseMoves = function (e) {
var jQEvent = e.originalEvent ? e : jQuery.event.fix(e);
injectCaptureMouseMoves.call(this, correctEvent(jQEvent));
};
BI.MouseMoveTracker.prototype._onMouseMove = function (e) {
var jQEvent = e.originalEvent ? e : jQuery.event.fix(e);
injectOnMouseMove.call(this, correctEvent(jQEvent));
}
}
injectMouseMoveTracker();
selectHandler();
BI.config("bi.constant.dashboard.toolbar.left.items", function (config) {
return BI.concat(config, [{
type: "bi.multi_select_item",
text: BI.i18nText("BI-Plugin-Scale_Adaptive"),
selected: true,
listeners: [{
eventName: BI.MultiSelectItem.EVENT_CHANGE,
action: function () {
selected = this.isSelected();
selectHandler();
}
}]
}, {
type: 'bi.text_value_combo',
text: '自定义缩放比例',
width: 120,
value: globalScaleRatio,
items: [
{
text: '自动',
value: null,
lgap: 10,
},
{
text: '50%',
value: 0.5,
lgap: 10,
},
{
text: '60%',
value: 0.6,
lgap: 10,
},
{
text: '70%',
value: 0.7,
lgap: 10,
},
{
lgap: 10,
text: '80%',
value: 0.8,
lgap: 10,
},
{
lgap: 10,
text: '90%',
value: 0.9,
lgap: 10,
},
{
lgap: 10,
text: '100%',
value: 1.0,
lgap: 10,
},
{
lgap: 10,
text: '110%',
value: 1.1,
lgap: 10,
},
{
lgap: 10,
text: '120%',
value: 1.2,
lgap: 10,
},
{
lgap: 10,
text: '130%',
value: 1.3,
lgap: 10,
},
{
lgap: 10,
text: '140%',
value: 1.4,
lgap: 10,
},
{
lgap: 10,
text: '150%',
value: 1.5,
lgap: 10,
},
{
lgap: 10,
text: '160%',
value: 1.6,
lgap: 10,
},
{
lgap: 10,
text: '170%',
value: 1.7,
lgap: 10,
},
{
lgap: 10,
text: '180%',
value: 1.8,
lgap: 10,
},
{
lgap: 10,
text: '190%',
value: 1.9,
lgap: 10,
},
{
lgap: 10,
text: '200%',
value: 2.0,
lgap: 10,
},
],
listeners: [{
eventName: "EVENT_CHANGE",
action: function (v) {
BI.Cache.setItem('scaleRatio', v);
globalScaleRatio = v;
selectHandler();
}
}],
}])
});
}());