fis-spriter-csssprites-dj
Version:
基于fis的csssprite,支持分组合并图片,@media处理,合并路径指定
433 lines (389 loc) • 15.6 kB
JavaScript
/*
* fis
* http://fis.baidu.com/
*/
'use strict';
var Image = require('images');
var util = require('./util.js');
module.exports = function(file, index, list, images, ret, settings, opt) {
var gen = new Generator(file, index, list, images, ret, settings, opt);
return gen.css;
};
function Generator(file, index, list, images, ret, settings, opt) {
var default_settings = {
'margin': 3,
'width_limit': 10240,
'height_limit': 10240,
'layout': 'linear',
'ie_bug_fix': true,
'to': ''
};
fis.util.map(default_settings, function (key, value) {
if (settings.hasOwnProperty(key)) {
if ((typeof value) == 'number') {
settings[key] = parseFloat(settings[key]);
}
} else {
settings[key] = value;
}
});
//如果layout不支持的类型,默认为linear
var layouts = ['matrix', 'linear'];
if (layouts.indexOf(settings.layout) == -1) {
settings.layout = 'linear';
}
//设置宽高限制
Image.setLimit(settings.width_limit, settings.height_limit);
var that = this;
this.file = file;
this.ret = ret;
this.settings = settings;
this.opt = opt;
this.css = '';
this.images = images;
this.index = index;
this.rem = settings.rem || 1;
this.units = settings.unit || (settings.rem ? "rem" : "px");
fis.util.map(list, function (group, glist) {
that.create(group, glist);
});
}
Generator.prototype = {
create: function(group, list) {
var that = this;
var list_ = {};
var scales = {};
function getImage(release) {
if (that.images.hasOwnProperty(release)) {
return that.images[release];
}
return false;
}
function insertToObject(o, key, elm) {
if (o[key]) {
o[key].push(elm);
} else {
o[key] = [elm];
}
}
fis.util.map(list, function (k, bg) {
var image_ = Image(getImage(bg.getImageUrl()).getContent());
var direct = bg.getDirect();
var imgScale = bg.getScale();
bg.image_ = image_;
var scale_ = bg.size[0] / image_.size().width;
// rem为单位
if(bg.units) that.units = bg.units;
if(that.units=='rem') {
scale_ = 1;
}
if (((that.units == 'rem' || bg.size[ 0 ] != -1) && scale_ != that.settings.scale)
|| (imgScale != 1.0)) {
if (imgScale != 1.0) {
scale_ = '' + imgScale;
} else {
scale_ = '' + scale_;
}
//不支持x, y
if (direct === 'z') {
if (scales[scale_]) {
insertToObject(scales[scale_], direct, bg);
} else {
scales[scale_] = {};
insertToObject(scales[scale_], direct, bg);
}
}
} else {
insertToObject(list_, direct, bg);
}
});
this.fill(group, list_['x'], 'x');
this.fill(group, list_['y'], 'y');
this.zFill(group, list_['z'], that.settings.scale);
//background-size
fis.util.map(scales, function (s, l) {
s = parseFloat(s);
that.zFill(group, l['z'], s);
});
},
_imageExist: function (images, url) {
for (var i = 0, len = images.length; i < len; i++) {
if (url == images[i].url) {
return i;
}
}
return false;
},
after: function (group, image, arr_selector, direct, scale, list) {
var ext = '_' + direct + '.png';
var size = image.size();
if (this.index) {
ext = '_' + this.index + ext;
}
if (scale) {
ext = '_' + scale + ext;
}
ext = (group=='__default__' ? '' : '_'+group) + ext;
var root = fis.project.getProjectPath(),
to = this.file.spriteTo ? this.file.spriteTo : this.settings.to,
to_path = root + fis.util((to.substr(0,1)=='/' ? '/' : this.file.subdirname) +'/'+ to +'/'+ this.file.filename + ext),
pkg_path = to_path.substring(root.length);
var image_file = fis.file.wrap(to_path);
image_file.setContent(image.encode('png'));
fis.compile(image_file);
this.ret.pkg[pkg_path] = image_file;
// 记录这些图片已经被打包到其他文件上了。
var images = this.images;
list.forEach(function(item) {
var image = images[item.image],
map = image.map = image.map || {};
map.cssspritePkg = image_file.getId();
});
function unique(arr) {
var map = {};
return arr.filter(function(item){
return map.hasOwnProperty(item) ? false : map[item] = true;
});
}
var rem = this.units=='rem' ? this.rem : 1;
var imageUrl = util.getUrl(image_file, this.file, this.opt);
if (this.settings.ie_bug_fix) {
var MAX = this.settings.max_selectores || 30; //max 36
var arr_selector = unique(arr_selector.join(',').split(','));
var len = arr_selector.length;
var n = Math.ceil(len / MAX);
for (var i = 0; i < n; i++) {
var step = i * MAX
this.css += arr_selector.slice(step, step + MAX).join(',')
+ '{'
+ (scale ? 'background-size: ' + (size.width * scale / rem) + this.units + ' ' + (size.height * scale / rem) + this.units + ';': '')
+ 'background-image: url(' + imageUrl + ')}';
}
} else {
this.css += unique(arr_selector.join(',').split(',')).join(',')
+ '{'
+ (scale ? 'background-size: ' + (size.width * scale / rem) + this.units + ' ' + (size.height * scale / rem) + this.units + ';': '')
+ 'background-image: url(' + imageUrl + ')}';
}
//@TODO record
var report = {};
report[image_file.subpath] = unique(arr_selector.join(',').split(',')).length;
fis.emitter.emit('csssprite:record', report);
},
z_pack: require('./pack.js'),
fill: function(group, list, direct) {
if (!list || list.length == 0) {
return;
}
var max = 0;
var images = [];
//宽度或者高的和
var total = 0;
var parsed = [];
var i, k, len, count, op_max;
for (i = 0, k = -1, len = list.length; i < len; i++) {
if (parsed.indexOf(list[i].getImageUrl()) == -1) {
parsed.push(list[i].getImageUrl());
k++;
var img = list[i].image_;
var size = img.size();
images[k] = {
url: list[i].getImageUrl(),
cls: [],
image: img,
width: size.width,
height: size.height
};
images[k].cls.push({
selector: list[i].getId(),
position:list[i].getPosition()
});
//如果是repeat-x的,记录最大宽度;如果是repeat-y的,记录最大高度
op_max = (direct == 'x') ? size.width : size.height;
if (op_max > max) {
max = op_max;
}
//如果是repeat-x的,计算高度和;如果是repeat-y的,计算宽度和
total += (direct == 'x' ? size.height : size.width) + this.settings.margin;
} else {
var key = this._imageExist(images, list[i].getImageUrl());
images[key].cls.push({
selector: list[i].getId(),
position: list[i].getPosition()
});
}
}
if (images.length == 0) {
return;
}
//减掉多加的一次margin
total -= this.settings.margin;
var height = direct == 'x' ? total : max;
var width = direct == 'x' ? max : total;
var image = Image(width, height);
var rem = this.units=='rem' ? this.rem : 1;
var x = 0, y = 0, cls = [];
for (i = 0, len = images.length; i < len; i++) {
image.draw(images[i].image, x, y);
if (direct == 'y' && images[i].height < max) {
//如果高度小于最大高度,则在Y轴平铺当前图
for (k = 0, count = max / images[i].height; k < count; k++) {
image.draw(images[i].image, x, images[i].height * (k + 1));
}
} else if (direct == 'x' && images[i].width < max) {
//如果宽度小于最大宽度,则在X轴方向平铺当前图
for (k = 0, count = max / images[i].width; k < count; k++) {
image.draw(images[i].image, images[i].width * (k + 1), y);
}
}
for (k = 0, count = images[i].cls.length; k < count; k++) {
this.css += images[i].cls[k].selector + '{background-position:'
+ (images[i].cls[k].position[0] + -x) / rem + this.units + ' '
+ (images[i].cls[k].position[1] + -y) / rem + this.units + '}';
cls.push(images[i].cls[k].selector);
}
if (direct == 'x') {
y += images[i].height + this.settings.margin;
} else {
x += images[i].width + this.settings.margin;
}
}
this.after(group, image, cls, direct, null, list);
},
zFill: function(group, list, scale) {
if (!list || list.length == 0) {
return;
}
var i, k, k0, length, images = [[], []], parsed = [[], []], max = [0, 0], total = [0, 0];
for (i = 0, k = [-1, -1], length = list.length; i < length; i++) {
var item = list[i];
// 如果默认是linear,type全都设为left
if (this.settings.layout == 'linear') {
item.setType('left');
}
if (item.getType() == 'left') {
k0 = 0;
} else {
k0 = 1;
}
if (parsed[k0].indexOf(item.getImageUrl()) == -1) {
parsed[k0].push(item.getImageUrl());
var img = item.image_;
var size = img.size();
if (item.getType() == 'left') {
//计算最大宽度
if (size.width > max[k0]) {
max[k0] = size.width;
}
total[k0] += size.height + this.settings.margin;
}
k[k0] ++;
images[k0][k[k0]] = {
url: item.getImageUrl(),
cls: [],
image: img,
w: size.width + this.settings.margin,
h: size.height + this.settings.margin
};
if (k0 == 0) {
//left合并为一竖行,不需要在宽度上加margin
images[k0][k[k0]].w -= this.settings.margin;
}
images[k0][k[k0]].cls.push({
selector: list[i].getId(),
position:list[i].getPosition()
});
} else {
var key = this._imageExist(images[k0], item.getImageUrl());
images[k0][key].cls.push({
selector: list[i].getId(),
position:list[i].getPosition()
});
}
}
var left = 0, zero = 1;
if (images[zero].length == 0
&& images[left].length == 0) {
return;
}
if (images[zero]) {
var zero_root;
//高度从大到小排序
images[zero].sort(function(a, b) {
return -(a.h - b.h);
});
this.z_pack.fit(images[zero]);
zero_root = this.z_pack.getRoot();
max[zero] = zero_root.w;
total[zero] = zero_root.h;
}
var height = 0;
for (i = 0, length = total.length; i < length; i++) {
if (total[i] > height) {
height = total[i];
}
}
//减掉多加了一次的margin
height = height - this.settings.margin;
//left, zero
//zero | left
var rem = this.units=='rem' ? this.rem : 1;
var image = Image(max[left] + max[zero], height)
, x = 0
, y = 0
, j = 0
, cls = []
, count = 0
, current;
if (images[zero]) {
for (i = 0, length = images[zero].length; i < length; i++) {
current = images[zero][i];
x = current.fit.x;
y = current.fit.y;
image.draw(Image(current.image), x, y);
for (j = 0, count = current.cls.length; j < count; j++) {
var x_ = current.cls[j].position[0] + -x;
var y_ = current.cls[j].position[1] + -y;
if (scale) {
x_ = x_ * scale;
y_ = y_ * scale;
}
// console.log(this.units);
this.css += current.cls[j].selector + '{background-position:'
+ x_ / rem + this.units + ' '
+ y_ / rem + this.units + '}';
cls.push(current.cls[j].selector);
}
}
}
if (images[left]) {
y = 0;
for (i = 0, length = images[left].length; i < length; i++) {
current = images[left][i];
x = max[zero] + max[left] - current.w;
image.draw(Image(current.image), x, y);
for (j = 0, count = current.cls.length; j < count; j++) {
var x_, y_ = (current.cls[j].position[1] + -y) / rem + this.units + ' ';
if (scale) {
y_ = ((current.cls[j].position[1] + -y) * scale) / rem + this.units + ''
}
if (current.cls[j].position[0] == 'right') {
x_ = 'right ';
} else {
x_ = -x + current.cls[j].position[0];
if (scale) {
x_ = x_ * scale;
}
x_ = x_ / rem + this.units + ' ';
}
this.css += current.cls[j].selector + '{background-position:'
+ x_
+ y_ + '}';
cls.push(current.cls[j].selector);
}
y += current.h;
}
}
this.after(group, image, cls, 'z', scale, list);
}
};