1

我有一个用 Flash 和 ActionScript 编写的应用程序。我想用画布和 KineticJS 库替换 flash。我遇到了一个小问题。在 ActionScript 中是方法“getRect”(http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#getRect%28%29)和“getBounds”(http: //help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#getBounds%28%29 ) 返回对象的 minX、minY、宽度和高度。就我而言,这是层。使用这两个函数,我可以获得图层上最左侧和最顶部的坐标。然后我只是设置舞台的新位置,所有项目都位于最左上角。

所以,我想在 javascript 中创建类似的东西。要获得最左侧,图层上最顶部的可见点。我必须检查所有图层和上面的形状,以获得 minX 和 minY。

我制作了示例代码,可在此处获得:http: //jsfiddle.net/JercSi/v63hC/1/

如果形状是“多边形”,那么所有坐标 x,y 都是 0,宽度和高度也是 0。我期待 x=100,y=100,宽度=100,高度=100。

如果形状是“文本”,那么我会得到形状的 x,y 以及正确的宽度和高度——这没关系,除非形状被旋转。对于我想要获得的“文本”对象:x=-8 和 y=126。而不是 x=150,y=150。

这是应该返回 minX 和 minY 的脚本。它不会返回 minX、minY 而是将坐标打印到控制台(使用 FireBug 或类似的浏览器插件)。

<script type="text/javascript">
var _le = stage.children.length; // get number of children (stage)
var i, j, _le2;
for (i = 0; i < _le; ++i) {
  _le2 = stage.children[i].children.length; // get number of children on each layer
  for (j = 0; j < _le2; ++j) {
    // check all shapes on the layer
    console.log(stage.children[i].children[j].getAbsolutePosition());
    console.log(stage.children[i].children[j].getX()+", "+stage.children[i].children[j].getY());
    console.log(stage.children[i].children[j].getWidth()+", "+stage.children[i].children[j].getHeight());
  }
}
</script>

让我总结一下我的问题,我想得到 minX 和 minY 然后设置舞台的新位置 - 当前位置:

http://www.jerc.si/wp-content/uploads/2013/10/kinetic-js-stage-1.png

舞台/图层的新位置:

http://www.jerc.si/wp-content/uploads/2013/10/kinetic-js-stage-2.png

也许这样的东西已经存在 - 没有计算 minX 和 minY - 但我没有找到。

4

1 回答 1

1

Kinetic.Polygon 不会自动计算最小/最大或宽度/高度。

但是您可以轻松地进行这些计算并让您的多边形报告这些值。

这是一个由红色边界框包含的 kinetic.polygon。

边界框是使用添加到多边形的最小/最大、宽度/高度属性定义的。

在此处输入图像描述

首先,当给定 myPolygon.getPoints 时,此代码返回 min、max、width、height。

function getPolyBounds(points){
    var minX=100000;
    var minY=100000;
    var maxX=-100000;
    var maxY=-100000;
    for(var i=0;i<points.length;i++){
        var pt=points[i];
        if(pt.x<minX){minX=pt.x;}
        if(pt.y<minY){minY=pt.y;}
        if(pt.x>maxX){maxX=pt.x;}
        if(pt.y>maxY){maxY=pt.y;}
    }
    return({minX:minX,minY:minY,maxX:maxX,maxY:maxY});
}

您可以向动力学多边形添加方法以返回 minX 和 minY。

poly.bounds=getPolyBounds(poly.getPoints());
poly.minX=function(){return(this.getX()+this.bounds.minX-this.getStrokeWidth());};
poly.minY=function(){return(this.getY()+this.bounds.minY-this.getStrokeWidth());};

您可以向动力学多边形添加属性以获取宽度和高度。

poly.bounds=getPolyBounds(poly.getPoints());
poly.width=poly.bounds.maxX-poly.bounds.minX+poly.getStrokeWidth()*2;
poly.height=poly.bounds.maxY-poly.bounds.minY+poly.getStrokeWidth()*2;

[加法:寻找其他形状的界限]

线:(实际上是一条折线):与多边形相同的解决方案(获取所有点的最小值/最大值)

所有矩形形状(矩形、图像、文本、精灵):minX/minY 始终是 getX/getY。

圆:minX=getX-getRadius,minY=getY-getRadius

曲线(样条曲线、斑点)可以通过获取所有 blob.getPoints() 的最小值/最大值来近似。

[加法:寻找旋转形状的界限]

要获得旋转形状的新边界,请计算原始点的旋转位置并使用通常的边界方法(上图)。

此代码将获取已围绕其枢轴点旋转指定弧度角的任何点的 newXY:

// calculate the distance from the pivot point to the original point
var dx = originalPoint.x - pivotpoint.x;
var dy = originalPoint.y - pivotpoint.y;
var radius = Math.sqrt(dx*dx+dy*dy);

// calculate the unrotated radian angle
var originalAngle=Math.atan2(dy,dx);

// the new angle is the sum of the original angle and rotation angle
var radianAngle+=originalAngle;


// calculate where the original point has been rotated to
var newX = originalPoint.x + radius * Math.cos(radianAngle);
var newY = originalPoint.y + radius * Math.sin(radianAngle);

[补充:找到更精确的曲线边界]

通过沿曲线绘制许多点并找到它们的最小值/最大值,可以得到更精确的曲线边界框。

此代码将获得构成曲线的 XY 点。在这些公式中,T 是沿曲线的区间,其中 T=0.00 是曲线的起点,T=1.00 是曲线的终点。

// quadratic bezier: T is 0-1
function getQuadraticBezierXYatT(startPt,controlPt,endPt,T) {
    var x = Math.pow(1-T,2) * startPt.x + 2 * (1-T) * T * controlPt.x + Math.pow(T,2) * endPt.x; 
    var y = Math.pow(1-T,2) * startPt.y + 2 * (1-T) * T * controlPt.y + Math.pow(T,2) * endPt.y; 
    return( {x:x,y:y} );
}

// cubic bezier T is 0-1
function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
    var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
    var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
    return({x:x,y:y});
}

// cubic helper formula at T distance
function CubicN(pct, a,b,c,d) {
    var t2 = pct * pct;
    var t3 = t2 * pct;
    return a + (-a * 3 + pct * (3 * a - a * pct)) * pct
    + (3 * b + pct * (-6 * b + b * 3 * pct)) * pct
    + (c * 3 - c * 3 * pct) * t2
    + d * t3;
}

这是多边形边界的代码和小提琴:http: //jsfiddle.net/m1erickson/SYp5j/

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Prototype</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    <script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.7.0.min.js"></script>

<style>
#container{
  border:solid 1px #ccc;
  margin-top: 10px;
  width:400px;
  height:400px;
}
</style>        
<script>
$(function(){

    var stage = new Kinetic.Stage({
        container: 'container',
        width: 400,
        height: 400
    });
    var layer = new Kinetic.Layer();
    stage.add(layer);


    function getPolyBounds(points){
        var minX=100000;
        var minY=100000;
        var maxX=-100000;
        var maxY=-100000;
        for(var i=0;i<points.length;i++){
            var pt=points[i];
            if(pt.x<minX){minX=pt.x;}
            if(pt.y<minY){minY=pt.y;}
            if(pt.x>maxX){maxX=pt.x;}
            if(pt.y>maxY){maxY=pt.y;}
        }
        return({minX:minX,minY:minY,maxX:maxX,maxY:maxY});
    }

    function newPoly(polypoints){

        var poly = new Kinetic.Polygon({
            points:polypoints,
            x: 25,
            y: 25,
            fill: 'skyblue',
            stroke: 'lightgray',
            strokeWidth: 3
        });
        poly.bounds=getPolyBounds(poly.getPoints());
        poly.minX=function(){return(this.getX()+this.bounds.minX-this.getStrokeWidth());};
        poly.minY=function(){return(this.getY()+this.bounds.minY-this.getStrokeWidth());};
        poly.width=poly.bounds.maxX-poly.bounds.minX+poly.getStrokeWidth()*2;
        poly.height=poly.bounds.maxY-poly.bounds.minY+poly.getStrokeWidth()*2;
        layer.add(poly);
        layer.draw();
        return(poly);
    }


    // test
    var polypoints=[];
    polypoints.push({x:20,y:50});
    polypoints.push({x:120,y:75});
    polypoints.push({x:220,y:50});
    polypoints.push({x:120,y:200});
    polypoints.push({x:20,y:50});
    //
    var myPoly=newPoly(polypoints);
    //
    var boundary=new Kinetic.Rect({
        x:myPoly.minX(),
        y:myPoly.minY(),
        width:myPoly.width,
        height:myPoly.height,
        stroke:"red",
        strokeWidth:0.50
    });
    layer.add(boundary);
    layer.draw();


}); // end $(function(){});

</script>       
</head>

<body>
    <button id="rotateBtn">rotate</button>
    <div id="container"></div>
</body>
</html>
于 2013-10-16T18:12:07.423 回答