/* * 3d标签云 * 功能:鼠标移入标签,当前标签静止放大 * 说明:radius 控制滚动区域(横椭圆、纵椭圆、正圆) * 版本:2.2 * */ window.tagCloud = (function (win, doc) { // 判断对象 function isObject(obj) { return Object.prototype.toString.call(obj) === "[object Object]"; } // 构造函数 function TagCloud(options) { var self = this; self.config = TagCloud._getConfig(options); self.box = self.config.element; // 组件元素 self.fontsize = self.config.fontsize; // 平均字体大小 if (Number.isInteger(self.config.radius)) { self._radiusX = self._radiusY = self.config.radius; } else if (self.config.radius instanceof Array) { if (self.config.radius.length === 1) { self._radiusX = self._radiusY = self.config.radius[0]; } else { self._radiusX = self.config.radius[0]; self._radiusY = self.config.radius[1]; } } self.radius = self._radiusX; // 滚动半径 _ratio = Math.round((self._radiusX * 10) / self._radiusY) / 10; // 滚动区域比例,保留一位小数 if (_ratio < 1) { // 焦点在Y轴的椭圆 self.ratioX = _ratio; self.ratioY = 1; self.radius = self._radiusY; // 滚动半径,选择长半径 } else if (_ratio > 1) { // 焦点在X轴的椭圆 self.ratioX = 1; self.ratioY = _ratio; } else { self.ratioX = self.ratioY = 1; // 正圆 } self.depth = 2 * self.radius; // 滚动深度 self.size = 2 * self.radius; // 随鼠标滚动变速作用区域 self.mspeed = TagCloud._getMsSpeed(self.config.mspeed); self.ispeed = TagCloud._getIsSpeed(self.config.ispeed); self.items = self._getItems(); self.direction = self.config.direction; // 初始滚动方向 self.keep = self.config.keep; // 鼠标移出后是否保持之前滚动 // 初始化 self.active = false; // 是否为激活状态 self.lasta = 1; self.lastb = 1; self.mouseX0 = self.ispeed * Math.sin((self.direction * Math.PI) / 180); // 鼠标与滚动圆心x轴初始距离 self.mouseY0 = -self.ispeed * Math.cos((self.direction * Math.PI) / 180); // 鼠标与滚动圆心y轴初始距离 self.mouseX = self.mouseX0; // 鼠标与滚动圆心x轴距离 self.mouseY = self.mouseY0; // 鼠标与滚动圆心y轴距离 self.index = -1; // 鼠标移入 TagCloud._on(self.box, "mouseover", function () { self.active = true; }); // 鼠标移出 TagCloud._on(self.box, "mouseout", function () { self.active = false; }); // 鼠标在内移动 TagCloud._on(self.keep ? win : self.box, "mousemove", function (ev) { var oEvent = win.event || ev; var boxPosition = self.box.getBoundingClientRect(); self.mouseX = (oEvent.clientX - (boxPosition.left + self.box.offsetWidth / 2)) / 5; self.mouseY = (oEvent.clientY - (boxPosition.top + self.box.offsetHeight / 2)) / 5; }); for (var j = 0, len = self.items.length; j < len; j++) { self.items[j].element.index = j; // 鼠标移出子元素,当前元素静止放大 self.items[j].element.onmouseover = function () { self.index = this.index; }; // 鼠标移出子元素,当前元素继续滚动 self.items[j].element.onmouseout = function () { self.index = -1; }; } // 定时更新 TagCloud.boxs.push(self.box); self.update(self); // 初始更新 self.box.style.visibility = "visible"; self.box.style.position = "relative"; for (var j = 0, len = self.items.length; j < len; j++) { self.items[j].element.style.position = "absolute"; self.items[j].element.style.zIndex = j + 1; } self.up = setInterval(function () { self.update(self); }); } //实例 TagCloud.boxs = []; //实例元素数组 // 静态方法们 TagCloud._set = function (element) { if (TagCloud.boxs.indexOf(element) === -1) { // ie8不支持数组的indexOf方法,所以自定义indexOf return true; } }; //添加数组IndexOf方法 if (!Array.prototype.indexOf) { // Array.prototype.indexOf = function (elt /*, from*/) { Array.prototype.indexOf = function (elt) { var len = this.length >>> 0; var from = Number(arguments[1]) || 0; from = from < 0 ? Math.ceil(from) : Math.floor(from); if (from < 0) from += len; for (; from < len; from++) { if (from in this && this[from] === elt) return from; } return -1; }; } TagCloud._getConfig = function (config) { var defaultConfig = { // 默认值 fontsize: 16, // 基本字体大小, 单位px radius: 60, // 滚动纵轴半径, 默认60, 单位px,取值60,[60],[60, 60] mspeed: "normal", // 滚动最大速度, 取值: slow, normal(默认), fast ispeed: "normal", // 滚动初速度, 取值: slow, normal(默认), fast direction: 135, // 初始滚动方向, 取值角度(顺时针360): 0对应top, 90对应left, 135对应right-bottom(默认)... keep: true, // 鼠标移出组件后是否继续随鼠标滚动, 取值: false, true(默认) 对应 减速至初速度滚动, 随鼠标滚动 multicolour: true, // 是否为彩色字体,颜色随机,取值:true(默认),false }; if (isObject(config)) { for (var i in config) { if (config.hasOwnProperty(i)) { //hasOwnProperty()用来判断一个属性是定义在对象本身而不是继承自原型链 defaultConfig[i] = config[i]; //用户配置 } } } return defaultConfig; // 配置 Merge }; TagCloud._getMsSpeed = function (mspeed) { //滚动最大速度 var speedMap = { slow: 1.5, normal: 3, fast: 5, }; return speedMap[mspeed] || 3; }; TagCloud._getIsSpeed = function (ispeed) { //滚动初速度 var speedMap = { slow: 10, normal: 25, fast: 50, }; return speedMap[ispeed] || 25; }; TagCloud._getSc = function (a, b) { var l = Math.PI / 180; //数组顺序0,1,2,3表示asin,acos,bsin,bcos return [Math.sin(a * l), Math.cos(a * l), Math.sin(b * l), Math.cos(b * l)]; }; TagCloud._on = function (ele, eve, handler, cap) { if (ele.addEventListener) { ele.addEventListener(eve, handler, cap); } else if (ele.attachEvent) { ele.attachEvent("on" + eve, handler); } else { ele["on" + eve] = handler; } }; // 原型方法 TagCloud.prototype = { constructor: TagCloud, // 反向引用构造器 update: function () { var self = this, a, b; if (!self.active && !self.keep) { self.mouseX = Math.abs(self.mouseX - self.mouseX0) < 1 ? self.mouseX0 : (self.mouseX + self.mouseX0) / 2; //重置鼠标与滚动圆心x轴距离 self.mouseY = Math.abs(self.mouseY - self.mouseY0) < 1 ? self.mouseY0 : (self.mouseY + self.mouseY0) / 2; //重置鼠标与滚动圆心y轴距离 } a = -((Math.min(Math.max(-self.mouseY, -self.size), self.size) * 2) / self.radius) * self.mspeed; b = ((Math.min(Math.max(-self.mouseX, -self.size), self.size) * 2) / self.radius) * self.mspeed; if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01) { return; } self.lasta = a; self.lastb = b; var sc = TagCloud._getSc(a, b); for (var j = 0, len = self.items.length; j < len; j++) { var rx1 = self.items[j].x, ry1 = self.items[j].y * sc[1] + self.items[j].z * -sc[0], rz1 = self.items[j].y * sc[0] + self.items[j].z * sc[1]; var rx2 = rx1 * sc[3] + rz1 * sc[2], ry2 = ry1, rz2 = rz1 * sc[3] - rx1 * sc[2]; if (self.index == j) { self.items[j].scale = 1; //取值范围0.6 ~ 3 self.items[j].fontsize = 18; self.items[j].alpha = 1; self.items[j].element.style.zIndex = 99; } else { var per = self.depth / (self.depth + rz2); self.items[j].x = rx2; self.items[j].y = ry2; self.items[j].z = rz2; self.items[j].scale = per; //取值范围0.6 ~ 3 self.items[j].fontsize = Math.ceil(per * 2) + self.fontsize - 6; self.items[j].alpha = 1.5 * per - 0.5; self.items[j].element.style.zIndex = Math.ceil(per * 10 - 5); } self.items[j].element.style.fontSize = self.items[j].fontsize + "px"; self.items[j].element.style.left = self.items[j].x * self.ratioX + (self.box.offsetWidth - self.items[j].offsetWidth) / 2 + "px"; self.items[j].element.style.top = self.items[j].y / self.ratioY + (self.box.offsetHeight - self.items[j].offsetHeight) / 2 + "px"; self.items[j].element.style.filter = "alpha(opacity=" + 100 * self.items[j].alpha + ")"; self.items[j].element.style.opacity = self.items[j].alpha; } }, _getItems: function () { var self = this, items = [], element = self.box.children, // children 全部是Element length = element.length, item; for (var i = 0; i < length; i++) { item = {}; item.angle = {}; item.angle.phi = Math.acos(-1 + (2 * i + 1) / length); item.angle.theta = Math.sqrt((length + 1) * Math.PI) * item.angle.phi; item.element = element[i]; item.offsetWidth = item.element.offsetWidth; item.offsetHeight = item.element.offsetHeight; item.x = (self.radius / 2) * 1.5 * Math.cos(item.angle.theta) * Math.sin(item.angle.phi); item.y = (self.radius / 2) * 1.5 * Math.sin(item.angle.theta) * Math.sin(item.angle.phi); item.z = (self.radius / 2) * 1.5 * Math.cos(item.angle.phi); item.element.style.left = item.x * self.ratioX + (self.box.offsetWidth - item.offsetWidth) / 2 + "px"; item.element.style.top = item.y / self.ratioY + (self.box.offsetHeight - item.offsetHeight) / 2 + "px"; if (self.config.multicolour) { // 初始化文字颜色为彩色 _color = self._randomNumBoth(0, 360); // 定义色相 (0 到 360) - 0 (或 360) 红,120绿,180青,240蓝,300紫 _light = self._randomNumBoth(30, 60); // 定义亮度 0% 为暗, 50% 为普通, 100% 为白 item.element.style.color = "hsl(" + _color + ", 100%, " + _light + "%)"; // 中间值为饱和度; 0%灰色,100%全色 // item.element.style.color = 'rgb(' + parseInt(Math.random() * 255) + ',' + parseInt(Math.random() * 255) + ',' + parseInt(Math.random() * 255) + ')'; } items.push(item); } return items; //单元素数组 }, // 取随机值,Min ≤ num ≤ Max _randomNumBoth: function (Min, Max) { var Range = Max - Min; var Rand = Math.random(); var num = Min + Math.round(Rand * Range); //四舍五入 return num; }, }; if (!doc.querySelectorAll) { // ie7不支持querySelectorAll,所以要重新定义 doc.querySelectorAll = function (selectors) { var style = doc.createElement("style"), elements = [], element; doc.documentElement.firstChild.appendChild(style); doc._qsa = []; style.styleSheet.cssText = selectors + "{x-qsa:expression(document._qsa && document._qsa.push(this))}"; window.scrollBy(0, 0); style.parentNode.removeChild(style); while (doc._qsa.length) { element = doc._qsa.shift(); element.style.removeAttribute("x-qsa"); elements.push(element); } doc._qsa = null; return elements; }; } return function (options) { // factory options = options || {}; // 短路语法 var selector = options.selector || ".tagcloud", // 默认选择class为tagcloud的元素 elements = doc.querySelectorAll(selector), instance = []; for (var index = 0, len = elements.length; index < len; index++) { options.element = elements[index]; if (!!TagCloud._set(options.element)) { instance.push(new TagCloud(options)); } } return instance; }; })(window, document);