Web 图集应用,属于非游戏类的图集/雪碧图对象/JS雪碧图/前端图集/JS图集

在非游戏领域其实也是存在很多细小的图标需求的。但是找遍全网却没有方便简洁的图集插件。

 

所以在此特写一个属于前端的图集插件,该插件使用非常简单。

首先准备需要打成图集的小图标若干

再使用国际标准的图集打包软件【texturepacker】,软件长这样

 然后将图片拖进软件内,

注意数据格式要选择【JSON(Array)】类型该插件才能解析成功,就是这个东西

接下来将生成的图集文件拖入工程内,比如我刚刚生成的文件分别是【asd.json 和 asd.png】

asd.json 是图集描述文件,里面记录着每个小图标的信息,位置大小等等

asd.png 是多个小图的合并生成的大图

json 文件长这样


好了准备工作做好了,接下来就来写代码

首先引入插件代码

然后在需要使用图集的【img】标签上添加属性【frame】

最后启动图集插件即可,如图所示

这是效果

 这是全部代码

/*
 * @Author: Summer
 * @LastEditors: Summer
 * @Description: 
 * @Date: 2022-04-13 18:07:24 +0800
 * @LastEditTime: 2022-04-15 08:52:08 +0800
 * @FilePath: \test\atlas.js
 */

(function () {

    /**
     * 加载 Image 图片元素
     * @param {*} url 
     * @returns 
     */
    function loadImage(url) {
        return new Promise((resolve, reject) => {
            let image = new Image();
            image.onerror = reject;
            image.onload = () => resolve(image);
            image.src = url;
        })
    }
    /**
     * Canvas 转 Image
     * @param {*} canvas 
     * @returns 
     */
    function createImageByCanvas(canvas) {
        return new Promise((resolve, reject) => canvas.toBlob(blob => {
            let image = new Image();
            image.onerror = reject;
            image.onload = () => { URL.revokeObjectURL(image.src); resolve(image) }
            image.src = URL.createObjectURL(blob);
        }))
    }
    function createFrameByCanvas(canvas) {
        return new Promise(resolve => canvas.toBlob(blob => resolve(new Frame(blob))));
    }
    class Frame {
        constructor(blob) {
            this.data = blob;
            this.image = new Image();
            this.url = this.image.src = URL.createObjectURL(blob);
            Object.defineProperties(this, {
                data: { writable: false, configurable: false },
                image: { writable: false, configurable: false },
                url: { writable: false, configurable: false },
            })
        }

        get width() { return this.image.naturalWidth }
        get height() { return this.image.naturalHeight }
    }
    class EventClass extends Event {
        constructor(type, data) {
            super(type);
            this.data = data;
        }
    }
    /**
     * 图集对象
     */
    window.Atlas = class Atlas extends EventTarget {
        _frames = new Map();
        
        on = this.addEventListener;
        once(type, callback) { this.addEventListener(type, callback, { once: true }) }
        emit(type, data) { this.dispatchEvent(new EventClass(type, data)) }
        constructor() {
            super()
            Object.defineProperty(this, "_frames", { writable: false, configurable: false });
            document.body.addEventListener("DOMSubtreeModified", this.scanning.bind(this), false);
        }
        /**
         * 初始化图集数据
         * @param {*} urls 图集的路径
         */
        async init(urls = {}) {
            let container = document.createElement("canvas");
            let scene = document.createElement("canvas");
            let s2d = scene.getContext("2d");
            let c2d = container.getContext("2d");
            let total = 0;
            let count = 0;
            
            for (let name in resources) {
                try {
                    let atlas = await fetch(urls[name] + ".json").then(body => body.json());
                    let boot = await loadImage(urls[name] + ".png");
                    scene.width = boot.naturalWidth; scene.height = boot.naturalHeight;
                    ///
                    s2d.clearRect(0, 0, boot.naturalWidth, boot.naturalHeight);
                    s2d.drawImage(boot, 0, 0, boot.naturalWidth, boot.naturalHeight);
                    for (let { filename, sourceSize: { w: sw, h: sh }, spriteSourceSize: { x: sx, y: sy }, frame: { x, y, w, h }, rotated } of atlas.frames) {
                        if (rotated) [w, h, sx, sy, sw, sh] = [h, w, sy, sx, sh, sw];
                        container.width = sw, container.height = sh;
                        c2d.clearRect(0, 0, sw, sh);
                        c2d.putImageData(s2d.getImageData(x, y, w, h), sx, sy, 0, 0, sw, sh);
                        if (rotated) {
                            let image = await createImageByCanvas(container);
                            [sw, sh] = [sh, sw];
                            container.width = sw, container.height = sh;
                            c2d.clearRect(0, 0, sw, sh);
                            // 先位移坐标到中心
                            c2d.translate(sw / 2, sh / 2);
                            // 旋转90度
                            c2d.rotate(-90 * Math.PI / 180);
                            // 此时按照旋转后的尺寸
                            // 把定位中心移动到左上角
                            c2d.translate(-1 * sh / 2, -1 * sw / 2);
                            // 绘制图片
                            c2d.drawImage(image, 0, 0, sh, sw, 0, 0, sh, sw)
                            // 坐标系还原到初始
                            c2d.setTransform(1, 0, 0, 1, 0, 0);
                        }
                        this._frames.set(`${name}/${filename}`, await createFrameByCanvas(container));
                        this.emit("process", { name:`${name}/${filename}`, total:total+=atlas.frames.length, count:++count });
                    }
                } catch (error) {
                    console.error(error);
                }
            }

            return this;
        }
        /**
         * 获取图集中的某个图片元素
         * @param {*} name 图集名称/图片名称
         * @returns 
         */
        getFrame(name) { return this._frames.get(name) }
        /**
         * 获取图集中的某个图片地址
         * @param {*} name 图集名称/图片名称
         * @returns 
         */
        getFrameUrl(name) { return this._frames.get(name)?.url; }
        /**
         * 获取图集中所有的图片元素
         * @returns 
         */
        getFrames() { return [...this._frames.values()] };
        /**
         * 开始扫描文档中使用图集规则的【Image】元素, 进行图集映射
         * 规则就是在 Img 标签添加属性【frame="图集名称/图片名称"】
         */
        scanning() {
            /// 扫描所有的 Image 节点,实现图集映射
            for (let ele of document.body.querySelectorAll("img")) if (ele.getAttribute("frame") || ele.frame) {
                ele.src = this.getFrameUrl(ele.getAttribute("frame") || ele.frame)
            }
        }
    }
})()

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值