在Fabric.js中分层画布对象

时间:2013-02-22 20:16:55

标签: javascript sorting fabricjs layer

有没有办法通过官方API在Fabric.js画布上分层对象?现在,我发现这样做的唯一方法是手动迭代canvas._objects并重新排序它们,以便按特定顺序绘制它们。是否有更好的方法可以做到这一点(可能)破坏对象?

4 个答案:

答案 0 :(得分:43)

[编辑] 我已经在下面更正了我的信息(我的错,我最初想的是KineticJs api)。

FabricJS具有这些API方法,可以更改对象的z-index:

canvas.sendBackwards(myObject)
canvas.sendToBack(myObject)
canvas.bringForward(myObject)
canvas.bringToFront(myObject)

在封面下,FabricJs通过从getObjects()数组中删除对象并将其拼接回所需位置来更改z-index。它有一个很好的优化,可以检查交叉对象。

bringForward: function (object) {
       var objects = this.getObjects(),
           idx = objects.indexOf(object),
           nextIntersectingIdx = idx;


       // if object is not on top of stack (last item in an array)
       if (idx !== objects.length-1) {

         // traverse up the stack looking for the nearest intersecting object
         for (var i = idx + 1, l = this._objects.length; i < l; ++i) {

           var isIntersecting = object.intersectsWithObject(objects[i]) ||
                                object.isContainedWithinObject(this._objects[i]) ||
                                this._objects[i].isContainedWithinObject(object);

           if (isIntersecting) {
             nextIntersectingIdx = i;
             break;
           }
         }
         removeFromArray(objects, object);
         objects.splice(nextIntersectingIdx, 0, object);
       }
       this.renderAll();
     },

答案 1 :(得分:2)

第1步:您可以使用(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.locationManager = [[CLLocationManager alloc]init]; self.locationManager.delegate = self; [self.locationManager requestAlwaysAuthorization]; self.locationManager.desiredAccuracy = kCLLocationAccuracyBest; if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { [self.locationManager startMonitoringSignificantLocationChanges]; } else { [self.locationManager startUpdatingLocation]; } return YES; } (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. [locationManager stopUpdatingLocation]; [locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; [locationManager setDistanceFilter:kCLDistanceFilterNone]; locationManager.pausesLocationUpdatesAutomatically = NO; locationManager.activityType = CLActivityTypeAutomotiveNavigation; [locationManager startUpdatingLocation]; } (void)applicationDidEnterBackground:(UIApplication *)application { [locationManager stopUpdatingLocation]; __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{ bgTask = UIBackgroundTaskInvalid; }]; NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(startTrackingBg) userInfo:nil repeats:YES]; } (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. // Saves changes in the application's managed object context before the application terminates. __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{ bgTask = UIBackgroundTaskInvalid; NSLog(@"App terminated"); }]; } (void)startTrackingBg { [locationManager startUpdatingLocation]; NSLog(@"App is running in background"); }

第2步:然后使用sendtoback,sendtofront .... fabricjs选项,如下所示

Answered over here

答案 2 :(得分:1)

如果你想为所有对象设置一个特定的顺序,而不是向前/向后移动一个对象,那么带来/发送到前/后的迭代调用很慢。

您可以使用bringToFront的代码作为灵感来加速此用例:https://github.com/kangax/fabric.js/blob/586e61dd282b22c1d50e15c0361875707e526fd8/src/static_canvas.class.js#L1468

这样做:

fabric.Canvas.prototype.orderObjects = function(compare) {
    this._objects.sort(compare);
    this.renderAll();
}

比较定义排序,如:

function compare(x,y) {
    return x.getWidth() * x.getHeight() < y.getWidth() * y.getHeight();
}

some_canvas.orderObjects(compare)

如果您希望将较小的物体放在前面。

答案 3 :(得分:0)

我就是这样做的。我为每个结构对象添加了一个 zIndex 属性,然后在将它们添加到画布后调用了一个排序函数:

const CIRCLE_INDEX = 1
let object = new fabric.Circle({
    left: 10,
    top: 10,
    radius: 5
    ...other properties
    zIndex: CIRCLE_INDEX
});

然后在添加对象后调用这样的函数

const sortObjects = () => {
    canvas._objects.sort((a, b) => (a.zIndex > b.zIndex) ? 1 : -1);
    canvas.renderAll();
}