用于Web开发的九个补丁图像

时间:2010-09-07 14:15:48

标签: html android css

我想知道Android中是否有像9-patch这样的东西,但是对于网络开发呢?

披露:我根本不了解网络开发,但我很想知道它是否存在。使用术语9-patch的简单网络搜索没有提出任何相关结果,所以我认为它有另一个术语,或者它不存在或者用得不够广泛。

有谁知道?

4 个答案:

答案 0 :(得分:24)

答案 1 :(得分:6)

如果您仍然感兴趣,我创建了一个Javascript文件,该文件使用canvas为Web创建真正的九个补丁图像支持。开源项目可以在这里找到:

https://github.com/chrislondon/9-Patch-Image-for-Websites

答案 2 :(得分:0)

好吧,我煞费苦心地纠正了我在上面链接中发现的沙漠错误。

了解NinePath android是一个有用的工具,可以添加动态绘制和填充识别(在之前的插入中缺失)。我可以添加一些脚本来完成所有功能。

替换库path9.js中的以下代码!

function NinePatchGetStyle(element, style)
{
    if (window.getComputedStyle)
    {
        var computedStyle = window.getComputedStyle(element, "");
        if (computedStyle === null)
            return "";
        return computedStyle.getPropertyValue(style);
    }
    else if (element.currentStyle)
    {
        return element.currentStyle[style];
    }
    else
    {
        return "";
    }
}

// Cross browser function to find valid property
function NinePatchGetSupportedProp(propArray)
{
    var root = document.documentElement; //reference root element of document
    for (var i = 0; i < propArray.length; i++)
    {
        // loop through possible properties
        if (typeof root.style[propArray[i]] === "string")
        {
            //if the property value is a string (versus undefined)
            return propArray[i]; // return that string
        }
    }
    return false;
}


/**
 * 9patch constructer. Sets up cached data and runs initial draw.
 * @param {Dom Element} div El Elemento dom en donde se pinta el ninepath
 * @param {function} callback La funcion que se llamara cuando se termina 
 * la carga de la imagen y el pintado del elemento div.
 * @returns {NinePatch} Un objeto nine path
 */
function NinePatch(div,callback)
{
    this.div = div;
    this.callback =callback;
    this.padding = {top:0,left:0,right:0,bottom:0};
    // Load 9patch from background-image
    this.bgImage = new Image();
    this.bgImage.src = NinePatchGetStyle(this.div, 'background-image').replace(/"/g, "").replace(/url\(|\)$/ig, "");
    var este = this;

    this.bgImage.onload = function()
    {
        este.originalBgColor = NinePatchGetStyle(este.div, 'background-color');
        este.div.style.background = 'none';

        // Create a temporary canvas to get the 9Patch index data.
        var tempCtx, tempCanvas;
        tempCanvas = document.createElement('canvas');
        tempCanvas.width  = este.bgImage.width;
        tempCanvas.height = este.bgImage.height;
        tempCtx = tempCanvas.getContext('2d');
        tempCtx.drawImage(este.bgImage, 0, 0);

        // Obteniendo el padding lateral derecho
        var dataPad = tempCtx.getImageData(este.bgImage.width-1,0,1,este.bgImage.height).data;
        var padRight = este.getPadBorder(dataPad,este.bgImage.width,este.bgImage.height);
        este.padding.top = padRight.top;
        este.padding.bottom = padRight.bottom;
        dataPad = tempCtx.getImageData(0,este.bgImage.height-1,este.bgImage.width,1).data;
        var padBottom = este.getPadBorder(dataPad,este.bgImage.width,este.bgImage.height);

        este.padding.left = padBottom.top;
        este.padding.right = padBottom.bottom;

        // Loop over each  horizontal pixel and get piece
        var data = tempCtx.getImageData(0, 0, este.bgImage.width, 1).data;

        // Use the upper-left corner to get staticColor, use the upper-right corner
        // to get the repeatColor.
        var tempLength = data.length - 4;
        var staticColor = data[0] + ',' + data[1] + ',' + data[2] + ',' + data[3];
        var repeatColor = data[tempLength] + ',' + data[tempLength + 1] + ',' +
                data[tempLength + 2] + ',' + data[tempLength + 3];

        este.horizontalPieces = este.getPieces(data, staticColor, repeatColor);

        // Loop over each  horizontal pixel and get piece
        data = tempCtx.getImageData(0, 0, 1, este.bgImage.height).data;
        este.verticalPieces = este.getPieces(data, staticColor, repeatColor);

        // use this.horizontalPieces and this.verticalPieces to generate image
        este.draw();
        este.div.onresize = function()
        {
            este.draw();
        };
        if(callback !== undefined)
        {
            if (typeof(callback) === "function")
                callback();
        }
    };
}

// Stores the HTMLDivElement that's using the 9patch image
NinePatch.prototype.div = null;
// Padding
NinePatch.prototype.padding = null;
// Get padding
NinePatch.prototype.callback = null;
// Stores the original background css color to use later
NinePatch.prototype.originalBG = null;
// Stores the pieces used to generate the horizontal layout
NinePatch.prototype.horizontalPieces = null;
// Stores the pieces used to generate the vertical layout
NinePatch.prototype.verticalPieces = null;
// Stores the 9patch image
NinePatch.prototype.bgImage = null;

// Gets the horizontal|vertical pieces based on image data
NinePatch.prototype.getPieces = function(data, staticColor, repeatColor)
{
    var tempDS, tempPosition, tempWidth, tempColor, tempType;
    var tempArray = new Array();

    tempColor = data[4] + ',' + data[5] + ',' + data[6] + ',' + data[7];
    tempDS = (tempColor === staticColor ? 's' : (tempColor === repeatColor ? 'r' : 'd'));
    tempPosition = 1;

    for (var i = 4, n = data.length - 4; i < n; i += 4)
    {
        tempColor = data[i] + ',' + data[i + 1] + ',' + data[i + 2] + ',' + data[i + 3];
        tempType = (tempColor === staticColor ? 's' : (tempColor === repeatColor ? 'r' : 'd'));
        if (tempDS !== tempType)
        {
            // box changed colors
            tempWidth = (i / 4) - tempPosition;
            tempArray.push(new Array(tempDS, tempPosition, tempWidth));

            tempDS = tempType;
            tempPosition = i / 4;
            tempWidth = 1;
        }
    }

    // push end
    tempWidth = (i / 4) - tempPosition;
    tempArray.push(new Array(tempDS, tempPosition, tempWidth));
    return tempArray;
};

NinePatch.prototype.getPadBorder = function(dataPad,width,height)
{
    var staticRight = dataPad[0] + ',' + dataPad[1] + ',' + dataPad[2] + ',' + dataPad[3];
    var pad={top:0,bottom:0};

    // Padding para la parte superior
    for (var i=0;i<dataPad.length;i+=4)
    {
        var tempColor = dataPad[i] + ',' + dataPad[i + 1] + ',' + dataPad[i + 2] + ',' + dataPad[i + 3];
        if(tempColor !==staticRight)
            break;
        pad.top++;
    }
    // padding inferior
    for (var i=dataPad.length-4;i>=0;i-=4)
    {
        var tempColor = dataPad[i] + ',' + dataPad[i + 1] + ',' + dataPad[i + 2] + ',' + dataPad[i + 3];
        if(tempColor !==staticRight)
            break;
        pad.bottom++;
    }
    return pad;
};

// Function to draw the background for the given element size.
NinePatch.prototype.draw = function()
{
    var dCtx, dCanvas, dWidth, dHeight;

    if(this.horizontalPieces === null)
        return;
    dWidth = this.div.offsetWidth;
    dHeight = this.div.offsetHeight;

    dCanvas = document.createElement('canvas');
    dCtx = dCanvas.getContext('2d');

    dCanvas.width = dWidth;
    dCanvas.height = dHeight;

    var fillWidth, fillHeight;

    // Determine the width for the static and dynamic pieces
    var tempStaticWidth = 0;
    var tempDynamicCount = 0;

    for (var i = 0, n = this.horizontalPieces.length; i < n; i++)
    {
        if (this.horizontalPieces[i][0] === 's')
            tempStaticWidth += this.horizontalPieces[i][2];
        else
            tempDynamicCount++;
    }

    fillWidth = (dWidth - tempStaticWidth) / tempDynamicCount;

    // Determine the height for the static and dynamic pieces
    var tempStaticHeight = 0;
    tempDynamicCount = 0;
    for (var i = 0, n = this.verticalPieces.length; i < n; i++)
    {
        if (this.verticalPieces[i][0] === 's')
            tempStaticHeight += this.verticalPieces[i][2];
        else
            tempDynamicCount++;
    }

    fillHeight = (dHeight - tempStaticHeight) / tempDynamicCount;

    // Loop through each of the vertical/horizontal pieces and draw on
    // the canvas
    for (var i = 0, m = this.verticalPieces.length; i < m; i++)
    {
        for (var j = 0, n = this.horizontalPieces.length; j < n; j++)
        {
            var tempFillWidth, tempFillHeight;

            tempFillWidth = (this.horizontalPieces[j][0] === 'd') ?
                    fillWidth : this.horizontalPieces[j][2];
            tempFillHeight = (this.verticalPieces[i][0] === 'd') ?
                    fillHeight : this.verticalPieces[i][2];

            // Stretching :
            if (this.verticalPieces[i][0] !== 'r') {
                // Stretching is the same function for the static squares
                // the only difference is the widths/heights are the same.
                dCtx.drawImage(
                        this.bgImage,
                        this.horizontalPieces[j][1], this.verticalPieces[i][1],
                        this.horizontalPieces[j][2], this.verticalPieces[i][2],
                        0, 0,
                        tempFillWidth, tempFillHeight);
            } else {
                var tempCanvas = document.createElement('canvas');
                tempCanvas.width = this.horizontalPieces[j][2];
                tempCanvas.height = this.verticalPieces[i][2];

                var tempCtx = tempCanvas.getContext('2d');
                tempCtx.drawImage(this.bgImage,
                        this.horizontalPieces[j][1], this.verticalPieces[i][1],
                        this.horizontalPieces[j][2], this.verticalPieces[i][2],
                        0, 0,
                        this.horizontalPieces[j][2], this.verticalPieces[i][2]);

                var tempPattern = dCtx.createPattern(tempCanvas, 'repeat');
                dCtx.fillStyle = tempPattern;
                dCtx.fillRect(
                        0, 0,
                        tempFillWidth, tempFillHeight);
            }

            // Shift to next x position
            dCtx.translate(tempFillWidth, 0);
        }

        // shift back to 0 x and down to the next line
        dCtx.translate(-dWidth, (this.verticalPieces[i][0] === 's' ? this.verticalPieces[i][2] : fillHeight));
    }

    // store the canvas as the div's background
    var url = dCanvas.toDataURL("image/png");
    var tempIMG = new Image();

    var _this = this;
    tempIMG.onload = function(event)
    {
        _this.div.style.background = _this.originalBgColor + " url(" + url + ") no-repeat";
    };
    tempIMG.src = url;
};


The usage is the following:


    var elemDom = document.getElementById("idDiv");
    var background = "border.9.png";
    if (background.match(/\.9\.(png|gif)/i)) // Es nine path?
    {
        elemDom.style.backgroundRepeat = "no-repeat";
        elemDom.style.backgroundPosition = "-1000px -1000px";
        elemDom.style.backgroundImage = "url('"+background+"')";
        var ninePatch = new NinePatch(elemDom,function()
        {
            elemDom.style.paddingLeft = ninePatch.padding.left;
            elemDom.style.paddingTop = ninePatch.padding.top;
            elemDom.style.paddingRight = ninePatch.padding.right;
            elemDom.style.paddingBottom = ninePatch.padding.bottom;
        });
    }

答案 3 :(得分:0)

我分叉了https://github.com/chrislondon/9-Patch-Image-for-Websites并根据以上评论修复了错误。现在,9-Patch javascript可以正常运行了。请查看https://github.com/blackmonkey/jQuery-9-Patch