日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

fabricjs 高级篇(自定义类型)

發布時間:2024/8/26 综合教程 40 生活家
生活随笔 收集整理的這篇文章主要介紹了 fabricjs 高级篇(自定义类型) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文:https://www.sitepoint.com/fabric-js-advanced/

<html>
<head>
     <script  src='./js/fabric.min.js'></script>
</head>
<body>
    <canvas id="c"></canvas>
<script>
var canvas = new fabric.Canvas('c',{backgroundColor : "#0ff", '600',height: '600'});
var LabeledRect = fabric.util.createClass(fabric.Rect, {
	    type: 'labeledRect',
	    initialize: function(options) {
		    options || (options = { });
		    this.callSuper('initialize', options);
		    this.set('label', options.label || '');
		    this.set('labelFont', options.labelFont || '');
		    this.set('labelFill', options.labelFill || '');
	    },
	    toObject: function() {
		    return fabric.util.object.extend(this.callSuper('toObject'), {
			    label: this.get('label'),
			    labelFont: this.get('labelFont'),
			    labelFill: this.get('labelFill')
		    });
	    },
	    _render: function(ctx) {
		    this.callSuper('_render', ctx);
		    // ctx.font = '20px Helvetica';
		    // ctx.fillStyle = '#333';
		    console.log('this', this);
		    ctx.font = this.labelFont;
		    ctx.fillStyle = this.labelFill;
		    // ctx.fillText(this.label, -this.width/2, -this.height/2 + 20);
		    ctx.fillText(this.label, 0, 0+10);
	    }
    });

    var labeledRect = new LabeledRect({
	     100,
	    height: 50,
	    left: 100,
	    top: 100,
	    label: 'test',
	    fill: '#faa',
        labelFont: '30px Helvetica',
        labelFill: '#00ff00'
    });
    canvas.add(labeledRect);
    setTimeout(function(){
	    labeledRect.set({
		    label: 'trololo',
		    fill: '#aaf',
		    rx: 10,
		    ry: 10,
            labelFill: '#0000ff'
	    });
	    canvas.renderAll();
    }, 3000)
</script>
</body>
</html>

  結果如下:

----------------------------------------

We’ve covered most of the basics of Fabric in thefirstandsecondparts of this series. In this article, I’ll move on to more advanced features: groups, serialization (and deserialization) and classes.

Groups

The first topic I’ll talk about is groups, one of Fabric’s most powerful features. Groups are exactly what they sound like—a simple way to group Fabric objects into a single entity so that you can work with those objects as a unit. (SeeFigure 1.)


Figure 1. A Selection Becomes a Group in Fabric

Remember that any number of Fabric objects on the canvas can be grouped with the mouse to form a single selection. Once grouped, the objects can be moved and even modified as one. You can scale the group, rotate it, and even change its presentational properties—its color, transparency, borders, and so on.

Every time you select objects like this on the canvas, Fabric creates a group implicitly, behind the scenes. Given this, it only makes sense to provide access to groups programmatically, which is wherefabric.Groupcomes in.

Let’s create a group from two objects, a circle and text:

       var text = new fabric.Text('hello world', {
	  fontSize: 30
	});
	var circle = new fabric.Circle({
	  radius: 100,
	  fill: '#eef',
	  scaleY: 0.5
	});
	var group = new fabric.Group([ text, circle ], {
	  left: 150,
	  top: 100,
	  angle: -10
	});
	canvas.add(group);

First, I created a “hello world” text object. Then, I created a circle with a 100 px radius, filled with the “#eef” color and squeezed vertically (scaleY=0.5). I next created afabric.Groupinstance, passing it an array with these two objects and giving it a position of 150/100 at a -10 degree angle. Finally, I added the group to the canvas, as I would with any other object, by usingcanvas.add().

Voila! You see an object on the canvas as shown inFigure 2, a labeled ellipse, and can now work with this object as a single entity. To modify that object, you simply change properties of the group, here giving it custom left, top and angle values.


Figure 2.A Group Created Programmatically

And now that we have a group on our canvas, let’s change it up a little:

       group.item(0).set({
	  text: 'trololo',
	  fill: 'white'
	});
	group.item(1).setFill('red');

Here, we access individual objects in a group via the item method and modify their properties. The first object is the text, and the second is the squeezed circle.Figure 3shows the results.


Figure 3. Squeezed Red Circle with New Text

One important idea you’ve probably noticed by now is that objects in a group are all positioned relative to the center of the group. When I changed the text property of the text object, it remained centered even when I changed its width. If you don’t want this behavior, you need to specify an object’s left/top coordinates, in which case they’ll be grouped according to those coordinates.

Here’s how to create and group three circles so that they’re positioned horizontally one after the other, such as those shown inFigure 4.

       var circle1 = new fabric.Circle({
	  radius: 50,
	  fill: 'red',
	  left: 0
	});
	var circle2 = new fabric.Circle({
	  radius: 50,
	  fill: 'green',
	  left: 100
	});
	var circle3 = new fabric.Circle({
	  radius: 50,
	  fill: 'blue',
	  left: 200
	});
	var group = new fabric.Group([ circle1, circle2, circle3 ], {
	  left: 200,
	  top: 100
	});
	canvas.add(group);


Figure 4. A Group with Three Circles Aligned Horizontally

Another point to keep in mind when working with groups is the state of the objects. For example, when forming a group with images, you need to be sure those images are fully loaded. Since Fabric already provides helper methods for ensuring that an image is loaded, this operation becomes fairly easy, as you can see in this code and in Figure 5.

       fabric.Image.fromURL('/assets/pug.jpg', function(img) {
	  var img1 = img.scale(0.1).set({ left: 100, top: 100 });
	  fabric.Image.fromURL('/assets/pug.jpg', function(img) {
	    var img2 = img.scale(0.1).set({ left: 175, top: 175 });
	    fabric.Image.fromURL('/assets/pug.jpg', function(img) {
	      var img3 = img.scale(0.1).set({ left: 250, top: 250 });
	      canvas.add(new fabric.Group([ img1, img2, img3],
	        { left: 200, top: 200 }))
	    });
	  });
	});


Figure 5. A Group with Three Images

Several other methods are available for working with groups:

getObjects works exactly like fabric.Canvas#getObjects() and returns an array of all objects in a group
size represents the number of objects in a group
contains allows you to check whether a particular object is in a group
item (which you saw earlier) allows you to retrieve a specific object from a group
forEachObject also mirrors fabric.Canvas#forEachObject, but in relation to group objects
add and remove add and remove objects from a group, respectively

You can add or remove objects with or without updating group dimensions and position. Here are several examples:

To add a rectangle at the center of a group (left=0, top=0), use this code:

       group.add(newfabric.Rect({
	...
	}));

To add a rectangle 100 px from the center of the group, do this:

       group.add(new fabric.Rect({
	  ...
	  left: 100,
	  top: 100
	}));

To add a rectangle at the center of a group and update the group’s dimensions, use the following code:

       group.addWithUpdate(newfabric.Rect({
	...
	left:group.getLeft(),
	top:group.getTop()
	}));

To add a rectangle at 100 px off from the center of a group and update the group’s dimensions, do this:

       group.addWithUpdate(newfabric.Rect({
	...
	left:group.getLeft()+100,
	top:group.getTop()+100
	}));

Finally, if you want to create a group with objects that are already present on the canvas, you need to clone them first:

       // create a group with copies of existing (2) objects
	var group = new fabric.Group([
	  canvas.item(0).clone(),
	  canvas.item(1).clone()
	]);
	// remove all objects and re-render
	canvas.clear().renderAll();
	// add group onto canvas
	canvas.add(group);

Serialization

As soon as you start building a stateful application of some sort—perhaps one that allows users to save results of canvas contents on a server or streaming contents to a different client—you need canvas serialization. There’s always an option to export the canvas to an image, but uploading a large image to a server requires a lot of bandwidth. Nothing beats text when it comes to size, and that’s exactly why Fabric provides an excellent support for canvas serialization and deserialization.

toObject, toJSON

The backbone of canvas serialization in Fabric are thefabric.Canvas#toObjectandfabric.Canvas#toJSONmethods. Let’s take a look at a simple example, first serializing an empty canvas:

       varcanvas=newfabric.Canvas('c');
	JSON.stringify(canvas);//'{"objects":[],"background":"rgba(0,0,0,0)"}'

Here I’m using the ES5JSON.stringifymethod, which implicitly calls the toJSON method on the passed object if that method exists. Because a canvas instance in Fabric has a toJSON method, it’s as though we calledJSON.stringify(canvas.toJSON())instead.

Notice the returned string that represents the empty canvas. It’s in JSON format, and essentially consists of “objects” and “background” properties. The “objects” property is currently empty because there’s nothing on the canvas, and “background” has a default transparent value (“rgba(0, 0, 0, 0)”).

Let’s give our canvas a different background and see how things change:

canvas.backgroundColor='red';
	JSON.stringify(canvas);//'{"objects":[],"background":"red"}'

As you would expect, the canvas representation reflects the new background color. Now let’s add some objects:

       canvas.add(new fabric.Rect({
	  left: 50,
	  top: 50,
	  height: 20,
	   20,
	  fill: 'green'
	}));
	console.log(JSON.stringify(canvas));

The logged output is as follows:

'{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null,
"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,
"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,
"perPixelTargetFind":false,"rx":0,"ry":0}],"background":"rgba(0, 0, 0, 0)"}'

Wow! At first sight, quite a lot has changed, but looking more closely, you can see that the newly added object is now part of the “objects” array, serialized into JSON. Notice how its representation includes all its visual traits—left, top, width, height, fill, stroke and so on.

If we were to add another object—say, a red circle positioned next to the rectangle—you would see that the representation changed accordingly:

canvas.add(new fabric.Circle({
	  left: 100,
	  top: 100,
	  radius: 50,
	  fill: 'red'
	}));
	console.log(JSON.stringify(canvas));

Here’s the logged output now:

'{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null,
"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,
"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,
"perPixelTargetFind":false,"rx":0,"ry":0},"type":"circle","left":100,"top":100,"width":100,"height":100,"fill":"red",
"overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,
"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,
"transparentCorners":true,"perPixelTargetFind":false,"radius":50}],"background":"rgba(0, 0, 0, 0)"}'

Notice the “type”:”rect” and “type”:”circle” parts so that you can see better where those objects are. Even though it might seem like a lot of output at first, it is nothing compared to what you would get with image serialization. Just for fun, take a look at about one-tenth (!) of a string you would get withcanvas.toDataURL('png'):

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAK8CAYAAAAXo9vkAAAgAElEQVR4Xu3dP4xtBbnG4WPAQOQ2YBCLK1qpoQE1
/m+NVlCDwUACicRCEuysrOwkwcJgAglEItRQaWz9HxEaolSKtxCJ0FwMRIj32zqFcjm8e868s2fNWoJygl+e397rWetk5xf5pyZd13wPwIEC
BAgQIAAAQIECBxI4F0H+hwfQ4AAAQIECBAgQIAAgQsCxENAgAABAgQIECBAgMDBBATIwah9EAECBAgQIECAAAECAsQzQIAAAQIECBAgQIDAw
QQEyMGofRABAgQIECBAgAABAgLEM0CAAAECBAgQIECAwMEEBMjBqH0QAQIECBAgQIAAAQICxDNAgAABAgQIECBAgMDBBATIwah9EAECBAgQI
ECAAAECAsQzQIAAAQIECBAgQIDAwQQEyMGofRABAgQIECBAgAABAgLEM0CAAAECBAgQIECAwMEEBMjBqH0QAQIECBAgQIAAAQICxDNAgAABA
gQIECBAgMDBBATIwah9EAECBAgQIECAAAECAsQzQIAAAQIECBAgQIDAwQQEyMGofRABAgQIECBAgAABAgLEM0CAAAECBAgQIECAwMEEBMjBq
H0QAQIECBAgQIAAAQICxDNAgAABAgQIECBAgMDBBATIwah9EAECBAgQIECAAAECAsQzQIAAAQIECBAgQIDAwQQEyMGofRABAgQIECBAgAABA
gLEM0CAAAECBAgQIECAwMEEBMjBqH0QAQIECBAgQIAAAQICxDNAgAABAgQIECBAgMDBBATIwah9EAECBAgQIECAAAECAsQzQIAAAQIECBAgQ
IDAwQQEyMGofRABAgQIECBAgAABAgLEM0CAAAECBAgQIECAwMEEBMjBqH0QAQIECBAgQIAAAQICxDNAgAABAgQIECBAgMDBBATIwah9EAECB
AgQIECAAAECAsQzQIAAAQIECBAgQIDAwQQEyMGofRABAgQIECBAgAABAgLEM0CAAAECBAgQIECAwMEEBMjBqH0QAQIECBAgQIAAAQICxDNAg
AABAgQIECBAgMDBBATIwah9EAECBAgQIECAAAECyw+Qb134RU2fevC8q+5esGWESBAgAABAgQIEFiOwPLMC5AlvO0OBMCBAgQIECAAAECJxQ
QICcE9HYCBAgQIECAAAECBPYXECD7W3klAQIECBAgQIAAAQInFBAgJwT0dgIECBAgQIAAAQIE9hcQIPtbeSUBAgQIECBAgAABAicUECAnBPR
2AgQIECBAgAABAgT2FxAg+1t5JQECBAgQIECAAAECJxQQICcE9HYCBAgQIECAAAECBPYXECD7W3klAQIECBAgQIAAAQInFBAgJwTc9+3z49y
vmNd+dI7PzPHJOW6Y4wNzXD3HlXNc9pZdb85/vzbHK3P8aY7n5vj1HL+Y43dz417f97O9jgABAgQIECBAgMBSBATIKd2JCY5dWNwyx5fn+Pw
cV5U/6tXZ99M5fjjHk3Mjd6HifwQIECBAgAABAgQWLSBAirdnouP6WXfvHHfOcU1x9T6rXp4XPTLHA3NTX9jnDV5DgAABAgQIECBA4NACAuS
E4hMdl8+Kr83xzTmuO+G61ttfnEXfnuN7c4PfaC21hwABAgQIECBAgMBJBQTIJQpOeFw7b71/jtsvccWh3vbYfNB9c6NfOtQH+hwCBAgQIEC
AAAECFxMQIMd8No7C4+F5283HfOtZv/ypOYG7hMhZ3wafT4AAAQIECBDYtoAA2fP+H/1Vqwd3f4jf8y1Lfdkunu7xV7OWenucFwECBAgQIEB
g3QICZI/7O/Fxx7xs9wf3t36r3D3evciX7L7F7+6rIY8u8uycFAECBAgQIE

…and there’s approximately 17,000 characters more.

You might be wondering why there’s alsofabric.Canvas#toObject.Quite simply,toObjectreturns the same representation as toJSON, only in a form of the actual object, without string serialization. For example, using the earlier example of a canvas with just a green rectangle, the output forcanvas.toObjectis as follows:

       { "background" : "rgba(0, 0, 0, 0)",
	  "objects" : [
	    {
	      "angle" : 0,
	      "fill" : "green",
	      "flipX" : false,
	      "flipY" : false,
	      "hasBorders" : true,
	      "hasControls" : true,
	      "hasRotatingPoint" : false,
	      "height" : 20,
	      "left" : 50,
	      "opacity" : 1,
	      "overlayFill" : null,
	      "perPixelTargetFind" : false,
	      "scaleX" : 1,
	      "scaleY" : 1,
	      "selectable" : true,
	      "stroke" : null,
	      "strokeDashArray" : null,
	      "strokeWidth" : 1,
	      "top" : 50,
	      "transparentCorners" : true,
	      "type" : "rect",
	      "width" : 20
	    }
	  ]
	}

As you can see, toJSON output is essentially stringifiedtoObjectoutput. Now, the interesting (and useful) thing is thattoObjectoutput is smart and lazy. What you see inside an “objects” array is the result of iterating over all canvas objects and delegating to each object’s owntoObjectmethod. For example,fabric.Pathhas its owntoObjectthat knows to return path’s “points” array, andfabric.Imagehas atoObjectthat knows to return image’s “src” property. In true object-oriented fashion, all objects are capable of serializing themselves.

This means that when you create your own class, or simply need to customize an object’s serialized representation, all you need to do is work with thetoObjectmethod, either completely replacing it or extending it. Here’s an example:

var rect = new fabric.Rect();
	rect.toObject = function() {
	  return { name: 'trololo' };
	};
	canvas.add(rect);
	console.log(JSON.stringify(canvas));

The logged output is:

'{"objects":[{"name":"trololo"}],"background":"rgba(0, 0, 0, 0)"}'

As you can see, the objects array now has a custom representation of our rectangle. This kind of override brings the point across but is probably not very useful. Instead, here’s how to extend a rectangle’stoObjectmethod with an additional property:

var rect = new fabric.Rect();
	rect.toObject = (function(toObject) {
	  return function() {
	    return fabric.util.object.extend(toObject.call(this), {
	      name: this.name
	    });
	  };
	})(rect.toObject);
	canvas.add(rect);
	rect.name = 'trololo';
	console.log(JSON.stringify(canvas));

And here’s the logged output:

'{"objects":[{"type":"rect","left":0,"top":0,"width":0,"height":0,"fill":"rgb(0,0,0)","overlayFill":null,
"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,
"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,
"transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0,"name":"trololo"}],
"background":"rgba(0, 0, 0, 0)"}'

I extended the object’s existingtoObjectmethod with the additional property “name”, which means that property is now part of thetoObjectoutput, and as a result it appears in the canvas JSON representation. One other item worth mentioning is that if you extend objects like this, you’ll also want to be sure the object’s “class” (fabric.Rectin this case) has this property in the “stateProperties” array so that loading a canvas from a string representation will parse and add it to an object correctly.

toSVG

Another efficient text-based canvas representation is in SVG format. Since Fabric specializes in SVG parsing and rendering on canvas, it makes sense to make this a two-way process and provide canvas-to-SVG conversion. Let’s add the same rectangle to our canvas and see what kind of representation is returned from thetoSVGmethod:

       canvas.add(new fabric.Rect({
	  left: 50,
	  top: 50,
	  height: 20,
	   20,
	  fill: 'green'
	}));
	console.log(canvas.toSVG());

The logged output is as follows:

'<?xml version="1.0" standalone="no" ?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" 
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"><svg xmlns="http://www.w3.org/2000/svg" 
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800" height="700" 
xml:space="preserve"><desc>Created with Fabric.js 0.9.21</desc><rect x="-10" y="-10" 
rx="0" ry="0" width="20" height="20" transform="translate(50 50)" /></svg>'

Just like withtoJSONandtoObject, thetoSVGmethod—when called on canvas—delegates its logic to each individual object, and each individual object has its owntoSVGmethod that is special to the type of object. If you ever need to modify or extend an SVG representation of an object, you can do the same thing withtoSVGas I did earlier withtoObject.

The benefit of SVG representation, compared to Fabric’s proprietarytoObject/toJSON, is that you can throw it into any SVG-capable renderer (browser, application, printer, camera, and so on), and it should just work. WithtoObject/toJSON, however, you first need to load it onto a canvas.

And speaking of loading things onto a canvas, now that you know how to serialize a canvas into an efficient chunk of text, how do you go about loading this data back onto canvas?

Deserialization and the SVG Parser

As with serialization, there’s two ways to load a canvas from a string: from JSON representation or from SVG. When using JSON representation, there are thefabric.Canvas#loadFromJSONandfabric.Canvas#loadFromDatalessJSONmethods. When using SVG, there arefabric.loadSVGFromURLandfabric.loadSVGFromString.

Notice that the first two methods are instance methods and are called on a canvas instance directly, whereas the other two methods are static methods and are called on the “fabric” object rather than on canvas.

There’s not much to say about most of these methods. They work exactly as you would expect them to. Let’s take as an example the previous JSON output from our canvas and load it on a clean canvas:

       varcanvas=newfabric.Canvas();
	canvas.loadFromJSON('{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20, 
fill":"green","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,
"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,
"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,
"rx":0,"ry":0},"type":"circle","left":100,"top":100,"width":100,"height":100,"fill":"red",
"overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,
"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,
"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,
"radius":50}],"background":"rgba(0,0,0,0)"}');

Both objects magically appear on canvas, as shown inFigure 6.


Figure 6. A Circle and a Square Rendered on Canvas

So loading canvas from a string is pretty easy, but what about that strange-lookingloadFromDatalessJSONmethod? How is it different fromloadFromJSON, which we just used? To understand why you need this method, look at a serialized canvas that has a more or less complex path object, like the one shown inFigure 7.


Figure 7. A Complex Shape Rendered on Canvas

JSON.stringify(canvas) output for the shape inFigure 7is as follows:

{"objects":[{"type":"path","left":184,"top":177,"width":175,"height":151,"fill":"#231F20","overlayFill":null,
"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":-19,"flipX":false,
"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,
"transparentCorners":true,"perPixelTargetFind":false,"path":[["M",39.502,61.823],["c",-1.235,-0.902,-3.038,
-3.605,-3.038,-3.605],["s",0.702,0.4,3.907,1.203],["c",3.205,0.8,7.444,-0.668,10.114,-1.97],["c",2.671,-1.302,
7.11,-1.436,9.448,-1.336],["c",2.336,0.101,4.707,0.602,4.373,2.036],["c",-0.334,1.437,-5.742,3.94,-5.742,3.94],
["s",0.4,0.334,1.236,0.334],["c",0.833,0,6.075,-1.403,6.542,-4.173],["s",-1.802,-8.377,-3.272,-9.013],["c",-1.468,
-0.633,-4.172,0,-4.172,0],["c",4.039,1.438,4.941,6.176,4.941,6.176],["c",-2.604,-1.504,-9.279,-1.234,-12.619,
0.501],["c",-3.337,1.736,-8.379,2.67,-10.083,2.503],["c",-1.701,-0.167,-3.571,-1.036,-3.571,-1.036],["c",1.837,
0.034,3.239,-2.669,3.239,-2.669],["s",-2.068,2.269,-5.542,0.434],["c",-3.47,-1.837,-1.704,-8.18,-1.704,-8.18],
["s",-2.937,5.909,-1,9.816],["C",34.496,60.688,39.502,61.823,39.502,61.823],["z"],["M",77.002,40.772],["c",0,0,
-1.78,-5.03,-2.804,-8.546],["l",-1.557,8.411],["l",1.646,1.602],["c",0,0,0,-0.622,-0.668,-1.691],["C",72.952,
39.48,76.513,40.371,77.002,40.772],["z"],["M",102.989,86.943],["M",102.396,86.424],["c",0.25,0.22,0.447,0.391,
0.594,0.519],["C",102.796,86.774,102.571,86.578,102.396,86.424],["z"],["M",169.407,119.374],["c",-0.09,-5.429,
-3.917,-3.914,-3.917,-2.402],["c",0,0,-11.396,1.603,-13.086,-6.677],["c",0,0,3.56,-5.43,1.69,-12.461],["c",
-0.575,-2.163,-1.691,-5.337,-3.637,-8.605],["c",11.104,2.121,21.701,-5.08,19.038,-15.519],["c",-3.34,-13.087,
-19.63,-9.481,-24.437,-9.349],["c",-4.809,0.135,-13.486,-2.002,-8.011,-11.618],["c",5.473,-9.613,18.024,-5.874,
18.024,-5.874],["c",-2.136,0.668,-4.674,4.807,-4.674,4.807],["c",9.748,-6.811,22.301,4.541,22.301,4.541],["c",
-3.097,-13.678,-23.153,-14.636,-30.041,-12.635],["c",-4.286,-0.377,-5.241,-3.391,-3.073,-6.637],["c",2.314,
-3.473,10.503,-13.976,10.503,-13.976],["s",-2.048,2.046,-6.231,4.005],["c",-4.184,1.96,-6.321,-2.227,-4.362,
-6.854],["c",1.96,-4.627,8.191,-16.559,8.191,-16.559],["c",-1.96,3.207,-24.571,31.247,-21.723,26.707],["c",
2.85,-4.541,5.253,-11.93,5.253,-11.93],["c",-2.849,6.943,-22.434,25.283,-30.713,34.274],["s",-5.786,19.583,
-4.005,21.987],["c",0.43,0.58,0.601,0.972,0.62,1.232],["c",-4.868,-3.052,-3.884,-13.936,-0.264,-19.66],["c",
3.829,-6.053,18.427,-20.207,18.427,-20.207],["v",-1.336],["c",0,0,0.444,-1.513,-0.089,-0.444],["c",-0.535,
1.068,-3.65,1.245,-3.384,-0.889],["c",0.268,-2.137,-0.356,-8.549,-0.356,-8.549],["s",-1.157,5.789,-2.758,
5.61],["c",-1.603,-0.179,-2.493,-2.672,-2.405,-5.432],["c",0.089,-2.758,-1.157,-9.702,-1.157,-9.702],["c",
-0.8,11.75,-8.277,8.011,-8.277,3.74],["c",0,-4.274,-4.541,-12.82,-4.541,-12.82],["s",2.403,14.421,-1.336,
14.421],["c",-3.737,0,-6.944,-5.074,-9.879,-9.882],["C",78.161,5.874,68.279,0,68.279,0],["c",13.428,16.088,
17.656,32.111,18.397,44.512],["c",-1.793,0.422,-2.908,2.224,-2.908,2.224],["c",0.356,-2.847,-0.624,-7.745,
-1.245,-9.882],["c",-0.624,-2.137,-1.159,-9.168,-1.159,-9.168],["c",0,2.67,-0.979,5.253,-2.048,9.079],["c",
-1.068,3.828,-0.801,6.054,-0.801,6.054],["c",-1.068,-2.227,-4.271,-2.137,-4.271,-2.137],["c",1.336,1.783,
0.177,2.493,0.177,2.493],["s",0,0,-1.424,-1.601],["c",-1.424,-1.603,-3.473,-0.981,-3.384,0.265],["c",0.089,
1.247,0,1.959,-2.849,1.959],["c",-2.846,0,-5.874,-3.47,-9.078,-3.116],["c",-3.206,0.356,-5.521,2.137,-5.698,
6.678],["c",-0.179,4.541,1.869,5.251,1.869,5.251],["c",-0.801,-0.443,-0.891,-1.067,-0.891,-3.473],...

…and that’s only 20 percent of the entire output!

What’s going on here? Well, it turns out that thisfabric.Pathinstance—this shape—consists of literally hundreds of Bezier lines dictating how exactly it is to be rendered. All those [“c”,0,2.67,-0.979,5.253,-2.048,9.079] chunks in JSON representation correspond to each one of those curves. And when there’s hundreds (or even thousands) of them, the canvas representation ends up being quite enormous.

Situations like these are wherefabric.Canvas#toDatalessJSONcomes in handy. Let’s try it:

       canvas.item(0).sourcePath='/assets/dragon.svg';
	console.log(JSON.stringify(canvas.toDatalessJSON()));

Here’s the logged output:

{"objects":[{"type":"path","left":143,"top":143,"width":175,"height":151,"fill":"#231F20","overlayFill":null,
"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":-19,"flipX":false,
"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,
"transparentCorners":true,"perPixelTargetFind":false,"path":"/assets/dragon.svg"}],"background":"rgba(0, 0, 0, 0)"}

That’s certainly smaller, so what happened? Notice that before callingtoDatalessJSON, I gave the path (dragon shape) object asourcePath property of “/assets/dragon.svg”. Then, when I calledtoDatalessJSON, the entire humongous path string from the previous output (those hundreds of path commands) is replaced with a single “dragon.svg” string.

When you’re working with lots of complex shapes,toDatalessJSONallows you to reduce canvas representation even further and replace huge path data representations with a simple link to SVG.

You can probably guess that theloadFromDatalessJSONmethod simply allows you to load a canvas from a data less version of a canvas representation. TheloadFromDatalessJSONmethod pretty much knows how to take those “path” strings (like “/assets/dragon.svg”), load them, and use them as the data for corresponding path objects.

Now, let’s take a look at SVG-loading methods. We can use either string or URL. Let’s look at the string example first:

       fabric.loadSVGFromString('...',function(objects,options){
	varobj=fabric.util.groupSVGElements(objects,options);
	canvas.add(obj).renderAll();
	});

The first argument is the SVG string, and the second is the callback function. The callback is invoked when SVG is parsed and loaded and receives two arguments—objects and options. The first, objects, contains an array of objects parsed from SVG—paths, path groups (for complex objects), images, text, and so on. To group those objects into a cohesive collection—and to make them look the way they do in an SVG document—we’re usingfabric.util.groupSVGElements and passing it both objects and options. In return, we get either an instance offabric.Pathorfabric.PathGroup, which we can then add onto our canvas.

Thefabric.loadSVGFromURLmethod works the same way, except that you pass a string containing a URL rather than SVG contents. Note that Fabric will attempt to fetch that URL via XMLHttpRequest, so the SVG needs to conform to the usual SOP rules.

Subclassing

Since Fabric is built in a truly object-oriented fashion, it’s designed to make subclassing and extension simple and natural. As described in the first article in this series, there’s an existing hierarchy of objects in Fabric. All two-dimensional objects (paths, images, text, and so on) inherit fromfabric.Object, and some “classes”—likefabric.PathGroup— even form a third-level inheritance.

So how do you go about subclassing one of the existing “classes” in Fabric, or maybe even creating a class of your own?

For this task you need thefabric.util.createClassutility method. This method is nothing but a simple abstraction over JavaScript’s prototypal inheritance. Let’s first create a simple Point “class”:

       var Point = fabric.util.createClass({
	  initialize: function(x, y) {
	    this.x = x || 0;
	    this.y = y || 0;
	  },
	  toString: function() {
	    return this.x + '/' + this.y;
	  }
	});

ThecreateClassmethod takes an object and uses that object’s properties to create a class with instance-level properties. The only specially treated property is initialize, which is used as a constructor. Now, when initializing Point, we’ll create an instance with x and y properties and thetoStringmethod:

       varpoint=newPoint(10,20);
	point.x;//10
	point.y;//20
	point.toString();//"10/20"

If we wanted to create a child of “Point” class—say a colored point—we would usecreateClasslike so:

       var ColoredPoint = fabric.util.createClass(Point, {
	  initialize: function(x, y, color) {
	    this.callSuper('initialize', x, y);
	    this.color = color || '#000';
	  },
	  toString: function() {
	    return this.callSuper('toString') + ' (color: ' + this.color + ')';
	  }
	});

Notice how the object with instance-level properties is now passed as a second argument. And the first argument receives Point “class”, which tellscreateClassto use it as a parent class of this one. To avoid duplication, we’re using thecallSupermethod, which calls the method of a parent class. This means that if we were to changePoint, the changes would also propagate to theColoredPointclass.

Here’s ColoredPoint in action:

var redPoint = new ColoredPoint(15, 33, '#f55');
	redPoint.x; // 15
	redPoint.y; // 33
	redPoint.color; // "#f55"
	redPoint.toString(); "15/35 (color: #f55)"

Now let’s see how to work with existing Fabric classes. For example, let’s create aLabeledRectclass that will essentially be a rectangle that has some kind of label associated with it. When rendered on our canvas, that label will be represented as a text inside a rectangle (similar to the earlier group example with a circle and text). As you’re working with Fabric, you’ll notice that combined abstractions like this can be achieved either by using groups or by using custom classes.

       var LabeledRect = fabric.util.createClass(fabric.Rect, {
	  type: 'labeledRect',
	  initialize: function(options) {
	    options || (options = { });
	    this.callSuper('initialize', options);
	    this.set('label', options.label || '');
	  },
	  toObject: function() {
	    return fabric.util.object.extend(this.callSuper('toObject'), {
	      label: this.get('label')
	    });
	  },
	  _render: function(ctx) {
	    this.callSuper('_render', ctx);
	    ctx.font = '20px Helvetica';
	    ctx.fillStyle = '#333';
	    ctx.fillText(this.label, -this.width/2, -this.height/2 + 20);
	  }
	});

It looks like there’s quite a lot going on here, but it’s actually pretty simple. First, we’re specifying the parent class asfabric.Rect, to utilize its rendering abilities. Next, we define the type property, setting it to “labeledRect“. This is just for consistency, because all Fabric objects have the type property (rect, circle, path, text, and so on.) Then there’s the already-familiar constructor (initialize), in which we utilizecallSuperonce again. Additionally, we set the object’s label to whichever value was passed via options. Finally, we’re left with two methods—toObjectand_render. ThetoObject method, as you already know from the serialization section, is responsible for object (and JSON) representation of an instance. SinceLabeledRecthas the same properties as regularrectbut also a label, we’re extending the parent’stoObjectmethod and simply adding a label into it. Last but not least, the_rendermethod is what’s responsible for the actually drawing of an instance. There’s anothercallSupercall in it, which is what renders rectangle, and an additional three lines of text-rendering logic.

If you were to render such object, you do something like the following.Figure 8shows the results.

       var labeledRect = new LabeledRect({
	   100,
	  height: 50,
	  left: 100,
	  top: 100,
	  label: 'test',
	  fill: '#faa'
	});
	canvas.add(labeledRect);


Figure 8. Rendering of labeledRect

Changing the label value or any of the other usual rectangle properties would obviously work as expected, as you can see here and inFigure 9.

labeledRect.set({
	  label: 'trololo',
	  fill: '#aaf',
	  rx: 10,
	  ry: 10
	}


Figure 9. Modified labeledRect

Of course, at this point you’re free to modify the behavior of this class anyway you want. For example, you could make certain values the default values to avoid passing them every time to the constructor, or you could make certain configurable properties available on the instance. If you do make additional properties configurable, you might want to account for them intoObjectandinitialize, as I’ve shown here:

       ...
	initialize: function(options) {
	  options || (options = { });
	  this.callSuper('initialize', options);
	  // give all labeled rectangles fixed width/height of 100/50
	  this.set({  100, height: 50 });
	  this.set('label', options.label || '');
	}
	...
	_render: function(ctx) {
	  // make font and fill values of labels configurable
	  ctx.font = this.labelFont;
	  ctx.fillStyle = this.labelFill;
	  ctx.fillText(this.label, -this.width/2, -this.height/2 + 20);
	}
	...

Wrapping Up

That closes the third installment of this series, in which I’ve dived into some of the more advanced aspects of Fabric. With help from groups, serialization and deserialization and classes, you can take your app to a whole new level.

總結

以上是生活随笔為你收集整理的fabricjs 高级篇(自定义类型)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

91精品国产自产老师啪 | 碰超人人| 国产成人精品电影久久久 | 欧美日韩高清一区 | 亚洲,播放 | 久久一区91 | 国产成人l区 | 欧美色噜噜噜 | 日日干美女| 精产嫩模国品一二三区 | 亚洲国产播放 | 国产一级电影 | 2022中文字幕在线观看 | av在线播放免费 | 黄色免费观看网址 | 日日夜夜免费精品 | 久久免费在线 | 久久激情综合网 | 亚洲综合一区二区精品导航 | 少妇资源站 | 手机在线看片日韩 | 亚洲日本三级 | av中文在线影视 | 91最新中文字幕 | 伊色综合久久之综合久久 | 久久久午夜视频 | 久草免费手机视频 | 国产亚洲精品久久久久久电影 | 国产成人精品一区二三区 | 久久久国际精品 | 最近中文国产在线视频 | 在线视频专区 | 国产999精品久久久久久麻豆 | 久久伦理影院 | 日本黄色a级大片 | 一区二区中文字幕在线播放 | 免费看毛片网站 | 免费看国产a| 激情婷婷六月 | 国产91精品在线播放 | 超碰97中文 | 一级特黄aaa大片在线观看 | 91黄视频在线 | 亚洲一级在线观看 | 久久久不卡影院 | 国产精品免费在线视频 | 亚州国产精品久久久 | 国产日韩在线播放 | 国产免费一区二区三区最新 | 午夜色大片在线观看 | 国产在线黄 | 国产黄色片在线 | 在线观看色视频 | 亚洲成年人免费网站 | 成人一区二区三区在线观看 | 日本资源中文字幕在线 | 99热 精品在线 | 黄av资源| 国产专区欧美专区 | 久久高清精品 | 久久久影院一区二区三区 | 在线免费观看黄色 | 人人精品| 日韩在线视频二区 | 国产精品免费观看久久 | 精品国内| 99re国产| 亚洲日本国产 | 亚洲精品午夜国产va久久成人 | 亚洲高清激情 | 国产在线观看免 | 激情开心站 | 亚洲免费一级电影 | 久久综合色婷婷 | 精品亚洲午夜久久久久91 | 久草电影免费在线观看 | 中文字幕在线观看完整版电影 | 久久成人精品电影 | 中文字幕免费不卡视频 | 激情五月在线观看 | 国产又粗又猛又黄视频 | 国模一二三区 | 精品黄色片 | 五月天综合网站 | 欧美va天堂在线电影 | 婷婷激情av | 久久久综合色 | 99久久精品国产欧美主题曲 | 日日干 天天干 | 一区二区三区在线看 | 69国产盗摄一区二区三区五区 | 永久免费av在线播放 | 国产亚洲人 | 一区二区视频欧美 | 特级西西444www高清大视频 | 一级特黄aaa大片在线观看 | 96亚洲精品久久久蜜桃 | 涩涩网站在线看 | 五月婷婷欧美视频 | 99久久激情 | 欧美小视频在线 | 日日弄天天弄美女bbbb | 天天躁天天躁天天躁婷 | 国产亚洲精品久久久久秋 | 字幕网av| 久久亚洲区 | 亚洲精品乱码久久久久v最新版 | 国产精品黄色在线观看 | 亚洲精品国产精品99久久 | 欧美另类成人 | 五月激情丁香 | 91日韩精品视频 | 中文字幕乱码电影 | 免费看黄20分钟 | 91亚洲精品久久久久图片蜜桃 | 日韩欧美视频在线观看免费 | 2022中文字幕在线观看 | 97视频在线观看成人 | 草在线视频 | 国产亚州精品视频 | 99视频在线精品国自产拍免费观看 | 玖玖爱在线观看 | 九色视频网 | 国产精品原创视频 | 91在线影视| 在线观看免费av网 | 日韩 在线 | 国产资源网站 | 国产精品福利视频 | 一级性视频 | 黄色免费网| 男女激情免费网站 | 日韩在线不卡视频 | 日韩在线电影一区二区 | 久久人人爽av | 正在播放国产一区 | 久久精品一区二区国产 | 丁香 婷婷 激情 | 成人免费观看网站 | www.国产在线 | 久久精彩视频 | 日韩特黄一级欧美毛片特黄 | 深夜视频久久 | 激情小说网站亚洲综合网 | 一区中文字幕 | 激情欧美一区二区免费视频 | 欧美一级黄色片 | 日韩电影久久久 | 久久精品精品电影网 | 国产一级做a爱片久久毛片a | 国产高清视频在线免费观看 | 国产精品久久久久久久av大片 | 四虎精品成人免费网站 | 日韩精品免费 | 中文字幕视频免费观看 | 日韩激情片在线观看 | 人人干网站 | 色婷久久 | 精品国产一二三四区 | 国产精品久久久av | 91在线观看黄 | 中文字幕91 | 最新国产精品拍自在线播放 | 国产精品麻豆三级一区视频 | 欧美激情视频一区二区三区 | 久久深夜福利免费观看 | 激情黄色一级片 | 国产亚洲精品久久久久久移动网络 | 日韩黄色大片在线观看 | 午夜精品久久久久久久久久久久 | 久草在线费播放视频 | 人人爽人人爽av | 亚洲经典视频在线观看 | sm免费xx网站 | 五月激情综合婷婷 | a在线播放 | 免费a视频 | 国产精品视频久久 | 免费a v在线 | 91成人精品 | 91成人精品一区在线播放 | 亚洲精品欧美精品 | 九九免费精品视频在线观看 | 99精品热视频只有精品10 | 亚洲日韩欧美一区二区在线 | 天天草综合网 | 国产日产欧美在线观看 | 婷婷亚洲五月 | 日韩二区三区在线观看 | 色欲综合视频天天天 | 亚州欧美视频 | 亚洲黄在线观看 | 九色琪琪久久综合网天天 | 日韩美一区二区三区 | 中文字幕人成乱码在线观看 | 色综合久久久久网 | 久久96| 欧美日韩高清一区二区三区 | 亚洲精品视频中文字幕 | 99久久婷婷国产综合精品 | 久久爽久久爽久久av东京爽 | 免费美女av| 91av视频在线免费观看 | 00av视频| 成人在线播放视频 | 久久视频这里只有精品 | 久久精品99精品国产香蕉 | 久草网首页 | 在线播放一区二区三区 | 国产区精品 | 精品女同一区二区三区在线观看 | 亚洲欧洲成人 | 久久夜色精品国产欧美乱极品 | 国产一级免费在线 | 国产不卡在线视频 | 久久精品综合一区 | 狠狠狠干狠狠 | 久久99久久精品 | 国产日韩欧美在线 | 免费观看福利视频 | 国产精品久久电影网 | 免费在线国产视频 | 97色婷婷| 韩日电影在线 | 青青河边草免费直播 | 国产尤物在线视频 | 免费看91的网站 | 丁香花在线视频观看免费 | 中文字幕在线视频国产 | 日韩欧美v | 中文字幕在线观看视频一区二区三区 | www.操.com| 激情五月婷婷丁香 | 国产精品小视频网站 | 91中文字幕在线播放 | 久久久国产一区二区 | 最新日韩精品 | 99夜色| 国产精品久久久久久吹潮天美传媒 | 日韩在线三级 | 久久无码av一区二区三区电影网 | www日韩| 伊人亚洲精品 | 欧美一区影院 | 狠狠色伊人亚洲综合网站色 | 中文字幕av免费在线观看 | 九九热精品视频在线播放 | 97精品国自产拍在线观看 | 一区二区三区免费网站 | 久久97精品 | www免费在线观看 | 欧美日韩成人一区 | 97人人模人人爽人人少妇 | 欧美日韩在线观看一区二区三区 | 精品福利网站 | 99精品乱码国产在线观看 | 99热官网 | a级国产片| 麻豆免费在线视频 | 天天干天天操天天爱 | 99 久久久久 | 久久综合久久久久88 | 日日干天天插 | 欧美久久久久久久 | 日本爱爱免费 | 国产一区二区视频在线播放 | av怡红院 | 97在线观视频免费观看 | 亚洲激情电影在线 | 麻豆视频观看 | 久久精品国产精品亚洲 | 久热免费在线 | 免费在线国产精品 | 五月婷婷色丁香 | 久久久久久久综合色一本 | 在线免费黄网站 | 狠狠操操网 | 91系列在线观看 | 成人在线观看影院 | 国产一级片播放 | 国产精品久久久久久久午夜片 | 日韩一二区在线 | 久久免费视频精品 | 久久久久| 国产成人精品午夜在线播放 | 视频在线观看一区 | 黄色大片中国 | 99国产精品久久久久老师 | 日韩二区在线观看 | 国产午夜免费视频 | 国产黄在线播放 | 日韩在线观看精品 | 久久这里只有精品首页 | 国产精品久久久久久一区二区三区 | 免费a现在观看 | 日韩一级黄色片 | 九九九九精品九九九九 | 欧美一级黄色片 | 日韩成人黄色 | 色哟哟国产精品 | 91丨精品丨蝌蚪丨白丝jk | 国产一区二区三区免费视频 | av看片网址 | 色婷婷综合成人av | 99操视频| 人人狠狠综合久久亚洲婷 | 日韩精品一区二区三区水蜜桃 | 国产视频欧美视频 | 国产免费黄视频在线观看 | 国产黄色av | 天天操天天舔天天爽 | 狠狠干天天射 | 人人爱人人爽 | 激情丁香综合 | 欧美9999 | 日韩精品第一区 | 日日摸日日 | 久久精品观看 | 久久综合成人 | 国产成人在线网站 | 国产 欧美 日本 | 狠狠地日| av在线一级 | free,性欧美 九九交易行官网 | 日本中文字幕高清 | 丁香综合| 国产粉嫩在线观看 | 俺要去色综合狠狠 | 超碰人人超 | av黄色av | 久草在在线 | 深爱激情综合网 | 欧美一级淫片videoshd | 91麻豆产精品久久久久久 | 国产精美视频 | 99久久精| 午夜久久久影院 | 成人在线观看你懂的 | 午夜黄色一级片 | 色在线国产 | 久草免费在线观看视频 | 91成人精品 | 国产一区二区网址 | 久久免费精品一区二区三区 | 国产高清视频在线 | 久久久久久久久精 | 亚洲精品白浆高清久久久久久 | 国产国产人免费人成免费视频 | 亚洲欧洲美洲av | 中文字幕日韩有码 | 欧美日韩在线播放 | 久草网站 | 特级西西www44高清大胆图片 | 手机在线中文字幕 | 久久国产亚洲视频 | 在线国产一区 | www.xxxx欧美| 蜜臀av性久久久久蜜臀aⅴ涩爱 | 欧美成人xxxxxxxx | 久久亚洲成人网 | 国产高清免费av | 麻豆一区二区三区视频 | 国产999精品久久久影片官网 | 欧美日本三级 | 亚洲一一在线 | 天天久久综合 | 婷婷激情站 | 99视| 又爽又黄又刺激的视频 | 九九欧美视频 | 丁香六月在线 | 99精品欧美一区二区蜜桃免费 | 久久黄色精品视频 | 日本激情视频中文字幕 | 亚洲日本va中文字幕 | 久草在线观看 | 久久女同性恋中文字幕 | 国产大尺度视频 | 欧美日韩国产一区 | 日韩在线观看视频免费 | 免费毛片一区二区三区久久久 | 国产视频资源在线观看 | 国产在线国产 | 久久成人福利 | se视频网址| 一级精品视频在线观看宜春院 | 久操免费视频 | 米奇四色影视 | 欧美极品在线播放 | 久久精品一 | 亚洲精品色婷婷 | 97超碰资源站 | 亚洲成av人影片在线观看 | 人人爱人人做人人爽 | www.久久久.com| 日韩丝袜在线观看 | 国产高清日韩 | av大片免费在线观看 | 中文字幕日韩一区二区三区不卡 | 天天干天天在线 | 欧美吞精| 狠狠干成人综合网 | 天天色天天艹 | 在线免费av网站 | 亚洲国产精品女人久久久 | 五月婷网 | 午夜色站 | 亚洲欧洲av | 夜夜狠狠 | 久久福利在线 | 日韩免费中文 | 成人av资源网站 | 99久久精品国产毛片 | 国产美女精品久久久 | 日韩中午字幕 | 成年人视频免费在线播放 | 综合在线色 | 日韩电影中文字幕在线 | 9免费视频| 美女网站色在线观看 | 成人午夜免费福利 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 久久任你操 | 亚洲午夜久久久久 | 国产精品成人一区 | 91麻豆精品国产91久久久久久久久 | 久久99热精品这里久久精品 | 亚洲精品字幕在线观看 | 欧美日韩精品在线观看视频 | 91成人网页版 | 免费网址在线播放 | 国产只有精品 | 亚洲精品系列 | 综合精品久久久 | 午夜骚影 | 亚洲精品一区二区三区高潮 | 一本到在线 | 亚洲精品99| 久久久亚洲国产精品麻豆综合天堂 | 91成人国产| www日韩| 美女福利视频一区二区 | 国产福利精品一区二区 | 国产高清在线观看 | 久久久久久久久久久久国产精品 | 成人影片在线免费观看 | 免费在线观看视频a | 成人污视频在线观看 | 超碰97免费观看 | 国产在线精品一区 | 激情综合网五月婷婷 | 久久久久久久久久久影视 | 9992tv成人免费看片 | 午夜123| 国产在线欧美 | 日韩中字在线 | 久久狠狠干 | 激情久久伊人 | 玖草在线观看 | 国产精品av电影 | 免费观看丰满少妇做爰 | av在线免费在线观看 | 久久久精品久久日韩一区综合 | 夜夜躁天天躁很躁波 | a视频在线观看免费 | 精品极品在线 | 国产黄色视| 91福利区一区二区三区 | 亚洲欧美久久 | 精品国产片 | 玖玖爱国产在线 | 久久综合爱 | 精品在线不卡 | 欧美久久久久久久 | 在线 精品 国产 | 丁香av在线 | 精品美女在线视频 | 国产精品专区h在线观看 | 国产小视频在线免费观看视频 | 99久热在线精品视频观看 | 国产96精品| 日韩 精品 一区 国产 麻豆 | 国产成人一区二区三区免费看 | 美女网站视频色 | 日日摸日日添夜夜爽97 | 天天操天天色天天射 | 在线观看国产麻豆 | 最近免费观看的电影完整版 | 欧美成人精品欧美一级乱黄 | 啪啪动态视频 | 亚洲精品久久视频 | 亚洲国产精品久久 | 亚洲资源在线网 | 欧美午夜精品久久久久 | 91九色精品| 一级a性色生活片久久毛片波多野 | 91伊人影院 | a午夜电影 | 免费在线观看成人 | 久久激情五月婷婷 | 丁香5月婷婷久久 | 一区中文字幕 | 中文字幕亚洲高清 | 黄色1级大片 | 国产午夜一级毛片 | 最近日本韩国中文字幕 | 欧美一级免费黄色片 | 日本特黄特色aaa大片免费 | 国产美女免费观看 | 操操操日日日 | 国产一级片一区二区三区 | 久久99久久99精品免观看粉嫩 | 国产99久久久欧美黑人 | 国产精品99久久久久久久久久久久 | 91中文在线| 天天色宗合 | 中文字幕精品在线 | 精品国产激情 | 欧美日韩国产一二 | 国产99亚洲 | 69亚洲视频 | 久久色在线观看 | 在线成人免费av | 黄色成年 | 天天插天天干天天操 | 中文字幕字幕中文 | 欧美激情视频免费看 | 国产又粗又硬又长又爽的视频 | 特级毛片爽www免费版 | 91丨九色丨丝袜 | 人人舔人人爽 | 免费精品 | 久久激情视频免费观看 | www夜夜操| 国产精品99在线播放 | 欧美一进一出抽搐大尺度视频 | 麻豆免费看片 | 91九色蝌蚪国产 | 一级黄色免费网站 | 在线精品视频免费播放 | 国产一区视频在线播放 | 欧美日韩亚洲精品在线 | 一区二区精品在线 | 99久久er热在这里只有精品15 | 六月天色婷婷 | 国产精品福利无圣光在线一区 | 久久久久久久久久亚洲精品 | 国产成人久久av免费高清密臂 | 麻豆视频免费入口 | av在线a| 成人av在线播放网站 | 日韩视频精品在线 | 麻豆一二三精选视频 | 在线黄色av电影 | 色干综合 | 亚洲视频免费在线观看 | 九九九九热精品免费视频点播观看 | 日韩精品2区 | 欧美性猛片, | 在线观看中文字幕第一页 | 欧美激情第十页 | 亚洲国产精品99久久久久久久久 | 二区视频在线观看 | 久久久久久久久久影视 | 超碰在线日韩 | 日韩av成人在线观看 | 国产一级在线免费观看 | 国产精品短视频 | 麻豆小视频在线观看 | 日韩一区二区三区观看 | 操操操av | 四虎在线免费观看视频 | 不卡国产视频 | 99久久婷婷国产综合精品 | 日本中文在线播放 | 在线免费高清 | 超碰999 | 99tvdz@gmail.com | 欧美成人在线免费观看 | av在观看 | 欧美日韩视频在线观看免费 | 这里有精品在线视频 | 黄色三级在线 | 成人小视频在线免费观看 | 国产美女视频免费观看的网站 | 久久久久亚洲精品国产 | 999视频网| 国产精品欧美一区二区三区不卡 | 97超碰资源总站 | 国产美女视频 | 九九热视频在线免费观看 | 精品免费一区二区三区 | 丁香激情视频 | 久久精品久久久精品美女 | 91精品国产成人 | 午夜精品三区 | 91精品国产综合久久福利 | 美女av免费 | 久久在线 | 日韩欧美视频免费观看 | 国产一区二区三区免费在线观看 | 国产免费一区二区三区网站免费 | 97碰碰碰| av亚洲产国偷v产偷v自拍小说 | 婷婷视频 | 狠狠色2019综合网 | 久久人人爽人人爽人人 | 久久99中文字幕 | 欧美日韩亚洲在线 | 国产精品国产三级国产aⅴ无密码 | 日韩在线视频精品 | 日韩免费在线看 | www蜜桃视频 | 国产精品av久久久久久无 | 成人综合日日夜夜 | 欧美在线观看视频 | 成人影片在线播放 | 2022久久国产露脸精品国产 | 国产视频精品网 | 99国产成+人+综合+亚洲 欧美 | 国产一区私人高清影院 | 国内少妇自拍视频一区 | 日韩欧美视频二区 | 亚洲精品国产综合99久久夜夜嗨 | 久久撸在线视频 | 中文字幕人成不卡一区 | 天天操天天透 | 美女网站在线 | 天天爽天天爽天天爽 | 久久久久国产一区二区三区 | 国产91亚洲 | 国产一级黄色电影 | 免费一级片观看 | 500部大龄熟乱视频使用方法 | 婷婷色综合色 | 久久精品欧美日韩精品 | 国产成视频在线观看 | 久久精品福利视频 | 99视频在线免费看 | 国产精品99久久免费观看 | 四虎国产视频 | 在线中文字幕电影 | 337p日本欧洲亚洲大胆裸体艺术 | 西西www444| 青青草久草在线 | 日韩av在线资源 | 欧美日韩在线视频一区 | 伊人影院99 | 99久久精品国产毛片 | av一区二区三区在线播放 | 国产亚洲视频在线 | 日韩免费一级a毛片在线播放一级 | 国产精品成人一区二区 | 97天天干| 在线看av的网址 | 日本久久久久久久久久 | 日日爱夜夜爱 | 蜜桃视频在线观看一区 | 中文字幕av免费观看 | 国产成人一区二区啪在线观看 | 久久免费视频播放 | 日韩一二区在线 | 色综合中文综合网 | 中文字幕国内精品 | 在线中文字幕一区二区 | 亚洲综合成人专区片 | 开心激情网五月天 | 国产成人91 | 国产色拍| 中文 一区二区 | 国产成人不卡 | 色婷婷免费 | 中文字幕精品一区久久久久 | 久久综合九色综合97_ 久久久 | 成人a免费| 日韩在线小视频 | 国产精品欧美久久久久无广告 | 免费成人av电影 | 色午夜影院 | www.99在线观看 | av一区二区三区在线播放 | 免费看国产一级片 | 国产日韩欧美在线影视 | 五月激情在线 | 四虎4hu永久免费 | 久久久国内精品 | 91完整版在线观看 | 婷婷激情5月天 | 久久亚洲免费视频 | 色婷婷视频 | 久久高视频| 成年人在线观看网站 | 欧洲成人av | 国产九九热视频 | 久久女同性恋中文字幕 | 在线观看成人毛片 | 中文区中文字幕免费看 | 久久成人18免费网站 | 久久国产露脸精品国产 | 黄毛片在线观看 | 成人精品一区二区三区中文字幕 | 免费一级特黄录像 | 亚洲精品九九 | 五月婷婷六月丁香 | 99这里只有精品99 | 992tv人人草| 免费国产ww | 欧美色噜噜噜 | 人人澡超碰碰97碰碰碰软件 | 国产日韩欧美在线观看 | 婷婷五情天综123 | 天堂成人在线 | 欧美日韩一级久久久久久免费看 | 日韩三级免费观看 | 二区三区在线视频 | 91精品秘密在线观看 | 国产香蕉视频在线观看 | 久久精品亚洲一区二区三区观看模式 | 成年人免费看片网站 | av三级在线免费观看 | 九九热只有这里有精品 | 欧美一区二区三区在线视频观看 | 欧美激情视频一区二区三区免费 | 免费久久久 | 久久九九网站 | 天天伊人狠狠 | 日韩中文字幕91 | 精品v亚洲v欧美v高清v | 99精品在线播放 | 精品国产亚洲一区二区麻豆 | 日韩高清不卡一区二区三区 | 天堂av在线中文在线 | 午夜三级在线 | 在线看片91 | 成人免费观看电影 | 玖草影院 | 美女视频黄是免费的 | 亚洲人成人在线 | 四虎精品成人免费网站 | 欧美在线久久 | 成年人电影免费看 | 欧美日韩高清在线 | 中文字幕韩在线第一页 | 91热这里只有精品 | 97成人资源 | 国产中文字幕在线 | 国产国语在线 | 天天操天天操天天操天天操天天操天天操 | 日韩精品久久一区二区三区 | 蜜桃视频精品 | 2019天天干夜夜操 | 精品uu| 色吧av色av| 日韩中文三级 | 免费黄色看片 | 成人av免费在线 | 黄色在线视频网址 | 91在线视频网址 | 色综合久久88色综合天天免费 | 成人影片免费 | 在线播放视频一区 | 欧美一级片在线免费观看 | 成人久久网 | 国产精品久久久区三区天天噜 | 91网址在线| 亚洲美女视频在线 | 欧美一级爽 | 97在线超碰| 国产97在线观看 | 91在线91| 中文字幕av全部资源www中文字幕在线观看 | 欧美国产日韩一区二区 | 成人午夜电影在线 | 久久久精品国产一区二区电影四季 | 69国产在线观看 | 亚洲天堂网在线观看视频 | 亚洲最新av在线网站 | 国产亚洲精品久久久久久电影 | 草久在线观看 | 国内精品小视频 | 国产精品夜夜夜一区二区三区尤 | 久久好看免费视频 | 久久久国产99久久国产一 | 国产精品久久久一区二区三区网站 | www操操| a级片久久久 | 在线观看岛国 | 手机av资源 | 国产原创在线 | 日韩欧美91 | 久久免费观看视频 | 一区二区三区精品在线视频 | 开心激情久久 | 人人草在线观看 | 久久国产精品网站 | 日韩av手机在线看 | 三上悠亚一区二区在线观看 | 亚洲精品免费在线 | 久久人人爽人人爽人人片 | 丁香激情综合久久伊人久久 | 久久精品久久久久久久 | 日韩中文字幕免费在线播放 | 天堂网av在线 | 国产成人一二三 | 免费在线观看av网址 | 国产69精品久久久久久久久久 | 西西4444www大胆无视频 | 日韩av高清在线观看 | 天天拍天天操 | 97超级碰碰碰碰久久久久 | 高清不卡毛片 | 黄色小说网站在线 | 国产一区视频在线播放 | 中文字幕精品一区 | 国产日韩三级 | 久久久久久黄色 | 欧美日韩国产一区二 | 超碰97人| 人九九精品| 久久高清国产视频 | 国产精品免费久久久久久 | 99免费国产 | 国产福利精品一区二区 | 日韩在线观看免费 | 久久手机看片 | 日韩视频一区二区在线 | 热99在线视频 | 久久久五月天 | 最近中文字幕国语免费高清6 | 最近乱久中文字幕 | 9幺看片| 99精品视频免费观看 | 二区三区视频 | 久久高清国产 | 亚洲经典视频在线观看 | 国产一区高清在线 | 一级大片在线观看 | 久久这里只有精品23 | 国产成人综合图片 | 黄色资源网站 | 中文字幕在线观看完整版电影 | 99久久精品免费看国产四区 | 夜夜骑天天操 | 91在线看黄 | 国产成人精品亚洲 | 日本99热| 国产精品理论片 | 欧美人体xx | 日韩在线观看中文 | 最近免费在线观看 | 国产一级性生活视频 | 久久精品综合网 | 亚洲视频1区2区 | 国产一在线精品一区在线观看 | 欧美调教网站 | 最新中文在线视频 | 亚洲天堂网在线观看视频 | 91中文在线 | 操操操com | 欧美精品乱码久久久久久按摩 | 国产免费久久久久 | 五月婷婷中文 | 99精品国产99久久久久久福利 | 97香蕉超级碰碰久久免费软件 | 色天天中文 | 九九九九九精品 | 不卡视频在线看 | 成人污视频在线观看 | 久久av伊人 | av中文字幕免费在线观看 | 婷婷综合电影 | 黄色免费在线视频 | 日本丰满少妇免费一区 | 中日韩欧美精彩视频 | 国产女人40精品一区毛片视频 | 色婷婷色 | 久久草在线免费 | 99一区二区三区 | 在线观看激情av | 五月天色综合 | 午夜丰满寂寞少妇精品 | 久久综合狠狠综合久久狠狠色综合 | 97成人精品视频在线观看 | 丝袜美腿在线播放 | 国产成人精品久久二区二区 | 日本中文一级片 | 91麻豆精品 | 久草在线手机观看 | 国产福利在线 | 超碰人人在线 | 网站在线观看你们懂的 | 热久久最新地址 | 亚洲精品免费观看视频 | 久久久久一区二区三区四区 | 久久精品国产一区 | 天天干天天做天天操 | 国产精品一区二区久久 | 国产精品自产拍在线观看桃花 | 黄色av免费电影 | 96香蕉视频| 国产99久久九九精品免费 | 中文字幕一区二区三区乱码在线 | 亚洲精品一区二区在线观看 | 日本在线观看一区 | 国产高清福利在线 | 国产综合激情 | 久久婷婷激情 | 日本中文字幕在线电影 | 中文字幕亚洲精品在线观看 | 久久久网页| 国产精品久久一区二区无卡 | 四虎5151久久欧美毛片 | 欧美日韩中文在线视频 | www五月婷婷 | 久久黄色片 | aaa亚洲精品一二三区 | 天天操天天舔天天爽 | 成人app在线免费观看 | 色婷婷色 | 亚洲精品日韩av | 国产黄色片免费观看 | 黄色日视频 | 九九免费在线观看 | 黄色成人91| 成人精品亚洲 | 五月天国产| 久久国产精品小视频 | 久久国产精品一区二区三区 | 美女国产网站 | 国产日韩欧美自拍 | 欧美亚洲专区 | av看片网址 | 91污视频在线观看 | 9999免费视频 | 亚洲色图 校园春色 | 久久激五月天综合精品 | 中文字幕一区二区三区久久蜜桃 | 久久久久久毛片精品免费不卡 | 久久官网 | 国产精品第一页在线 | 久久精品老司机 | 91丨九色丨国产在线 | 欧美日韩一区二区三区不卡 | 六月丁香婷婷网 | 久久久久亚洲国产精品 | www178ccom视频在线 | 不卡的一区二区三区 | 国产一级不卡毛片 | 在线观看久久久久久 | 一区二区在线电影 | 午夜久久网站 | 在线中文字幕av观看 | 日韩中文字幕91 | 日韩在线二区 | 探花视频在线观看+在线播放 | 欧美精品国产精品 | 999电影免费在线观看2020 | 国产视频一区在线 | 国内成人精品视频 | 亚洲最新av网站 | 看av免费 | 99精品久久精品一区二区 | 亚洲欧美观看 | 国产精品精品久久久 | 久久国语 | 99热这里只有精品8 久久综合毛片 | 在线视频欧美精品 | 亚洲综合色婷婷 | 国产精品久久久久久久久久不蜜月 | 免费看一及片 | 精品美女久久久久久免费 | 天天射天天操天天 | 成年人免费av | 在线免费黄色 | 欧美激情视频在线免费观看 | 人人澡人| 激情开心| 国产在线精品区 | 亚洲第一中文网 | av中文字幕第一页 | 91香蕉视频污在线 | 四虎在线观看网址 | 国产免费人成xvideos视频 | 狠狠做深爱婷婷综合一区 | 久久天天躁夜夜躁狠狠85麻豆 | 天天干亚洲| 国产精久久久久久妇女av | 婷婷在线免费视频 | 国产精品一区二区麻豆 | 成人黄色大片在线观看 | av中文字幕第一页 | 成年人免费av | 国产亚洲在线视频 | 奇米影视8888| 成年人app网址 | 久久久999精品视频 国产美女免费观看 | 久久综合九色综合久久久精品综合 | 日韩久久精品一区二区三区 |