2013-09-08 14:42:11 +08:00
|
|
|
suite('Path', function() {
|
|
|
|
// ======================================================
|
|
|
|
test('add simple path', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2013-09-08 14:42:11 +08:00
|
|
|
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
data: 'M200,100h100v50z',
|
|
|
|
fill: '#ccc',
|
|
|
|
stroke: '#333',
|
|
|
|
strokeWidth: 2,
|
2013-01-01 02:46:23 +08:00
|
|
|
shadowColor: 'black',
|
|
|
|
shadowBlur: 2,
|
|
|
|
shadowOffset: [10, 10],
|
|
|
|
shadowOpacity: 0.5,
|
2012-11-14 13:37:28 +08:00
|
|
|
draggable: true
|
|
|
|
});
|
|
|
|
|
|
|
|
path.on('mouseover', function() {
|
|
|
|
this.setFill('red');
|
|
|
|
layer.draw();
|
|
|
|
});
|
|
|
|
|
|
|
|
path.on('mouseout', function() {
|
|
|
|
this.setFill('#ccc');
|
|
|
|
layer.draw();
|
|
|
|
});
|
|
|
|
|
|
|
|
layer.add(path);
|
|
|
|
|
|
|
|
stage.add(layer);
|
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
assert.equal(path.getData(), 'M200,100h100v50z');
|
|
|
|
assert.equal(path.dataArray.length, 4);
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
path.setData('M200');
|
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
assert.equal(path.getData(), 'M200');
|
|
|
|
assert.equal(path.dataArray.length, 1);
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
path.setData('M200,100h100v50z');
|
2013-03-24 15:14:42 +08:00
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
assert.equal(path.getClassName(), 'Path');
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('add path with line cap and line join', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
data: 'M200,100h100v50',
|
|
|
|
stroke: '#333',
|
|
|
|
strokeWidth: 20,
|
|
|
|
draggable: true,
|
|
|
|
lineCap: 'round',
|
|
|
|
lineJoin: 'round'
|
|
|
|
});
|
|
|
|
|
|
|
|
layer.add(path);
|
|
|
|
|
|
|
|
stage.add(layer);
|
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('moveTo with implied lineTos and trailing comma', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
data: 'm200,100,100,0,0,50,z',
|
|
|
|
fill: '#fcc',
|
|
|
|
stroke: '#333',
|
|
|
|
strokeWidth: 2,
|
2013-01-01 02:46:23 +08:00
|
|
|
shadowColor: 'maroon',
|
|
|
|
shadowBlur: 2,
|
|
|
|
shadowOffset: [10, 10],
|
|
|
|
shadowOpacity: 0.5,
|
2012-11-14 13:37:28 +08:00
|
|
|
draggable: true
|
|
|
|
});
|
|
|
|
|
|
|
|
path.on('mouseover', function() {
|
|
|
|
this.setFill('red');
|
|
|
|
layer.draw();
|
|
|
|
});
|
|
|
|
|
|
|
|
path.on('mouseout', function() {
|
|
|
|
this.setFill('#ccc');
|
|
|
|
layer.draw();
|
|
|
|
});
|
|
|
|
|
|
|
|
layer.add(path);
|
|
|
|
|
|
|
|
stage.add(layer);
|
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
assert.equal(path.getData(), 'm200,100,100,0,0,50,z');
|
|
|
|
assert.equal(path.dataArray.length, 4);
|
|
|
|
|
|
|
|
assert.equal(path.dataArray[1].command, 'L');
|
|
|
|
|
|
|
|
var trace = layer.getContext().getTrace();
|
|
|
|
|
|
|
|
//console.log(trace);
|
2013-09-26 16:39:50 +08:00
|
|
|
assert.equal(trace, 'clearRect(0,0,578,200);save();save();globalAlpha=0.5;shadowColor=maroon;shadowBlur=2;shadowOffsetX=10;shadowOffsetY=10;drawImage([object HTMLCanvasElement],0,0);restore();drawImage([object HTMLCanvasElement],0,0);restore();');
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('add map path', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var mapLayer = new Kinetic.Layer();
|
|
|
|
|
|
|
|
for(var key in worldMap.shapes) {
|
|
|
|
var c = worldMap.shapes[key];
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
data: c,
|
|
|
|
fill: '#ccc',
|
|
|
|
stroke: '#999',
|
|
|
|
strokeWidth: 1
|
|
|
|
});
|
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
if(key === 'US') {
|
|
|
|
assert.equal(path.dataArray[0].command, 'M');
|
|
|
|
}
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
path.on('mouseover', function() {
|
|
|
|
this.setFill('red');
|
|
|
|
mapLayer.drawScene();
|
|
|
|
});
|
|
|
|
|
|
|
|
path.on('mouseout', function() {
|
|
|
|
this.setFill('#ccc');
|
|
|
|
mapLayer.drawScene();
|
|
|
|
});
|
|
|
|
|
|
|
|
mapLayer.add(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
stage.add(mapLayer);
|
|
|
|
|
|
|
|
//document.body.appendChild(mapLayer.bufferCanvas.element);
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('curved arrow path', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
|
|
|
var c = "M12.582,9.551C3.251,16.237,0.921,29.021,7.08,38.564l-2.36,1.689l4.893,2.262l4.893,2.262l-0.568-5.36l-0.567-5.359l-2.365,1.694c-4.657-7.375-2.83-17.185,4.352-22.33c7.451-5.338,17.817-3.625,23.156,3.824c5.337,7.449,3.625,17.813-3.821,23.152l2.857,3.988c9.617-6.893,11.827-20.277,4.935-29.896C35.591,4.87,22.204,2.658,12.582,9.551z";
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
data: c,
|
|
|
|
fill: '#ccc',
|
|
|
|
stroke: '#999',
|
|
|
|
strokeWidth: 1
|
|
|
|
});
|
|
|
|
|
|
|
|
path.on('mouseover', function() {
|
|
|
|
this.setFill('red');
|
|
|
|
layer.draw();
|
|
|
|
});
|
|
|
|
|
|
|
|
path.on('mouseout', function() {
|
|
|
|
this.setFill('#ccc');
|
|
|
|
layer.draw();
|
|
|
|
});
|
|
|
|
|
|
|
|
layer.add(path);
|
|
|
|
stage.add(layer);
|
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('Quadradic Curve test from SVG w3c spec', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
|
|
|
var c = "M200,300 Q400,50 600,300 T1000,300";
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
data: c,
|
|
|
|
stroke: 'red',
|
|
|
|
strokeWidth: 5
|
|
|
|
});
|
|
|
|
|
|
|
|
layer.add(path);
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 200,
|
|
|
|
y: 300,
|
|
|
|
radius: 10,
|
|
|
|
fill: 'black'
|
|
|
|
}));
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 600,
|
|
|
|
y: 300,
|
|
|
|
radius: 10,
|
|
|
|
fill: 'black'
|
|
|
|
}));
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 1000,
|
|
|
|
y: 300,
|
|
|
|
radius: 10,
|
|
|
|
fill: 'black'
|
|
|
|
}));
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 400,
|
|
|
|
y: 50,
|
|
|
|
radius: 10,
|
|
|
|
fill: '#888'
|
|
|
|
}));
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 800,
|
|
|
|
y: 550,
|
|
|
|
radius: 10,
|
|
|
|
fill: '#888'
|
|
|
|
}));
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
layer.add(new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
data: "M200,300 L400,50L600,300L800,550L1000,300",
|
|
|
|
stroke: "#888",
|
|
|
|
strokeWidth: 2
|
|
|
|
}));
|
|
|
|
|
|
|
|
stage.add(layer);
|
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('Cubic Bezier Curve test from SVG w3c spec using setData', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
|
|
|
var c = "M100,200 C100,100 250,100 250,200 S400,300 400,200";
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
stroke: 'red',
|
|
|
|
strokeWidth: 5
|
|
|
|
});
|
|
|
|
|
|
|
|
path.setData(c);
|
|
|
|
|
|
|
|
layer.add(path);
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 100,
|
|
|
|
y: 200,
|
|
|
|
radius: 10,
|
|
|
|
stroke: '#888'
|
|
|
|
}));
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 250,
|
|
|
|
y: 200,
|
|
|
|
radius: 10,
|
|
|
|
stroke: '#888'
|
|
|
|
}));
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 400,
|
|
|
|
y: 200,
|
|
|
|
radius: 10,
|
|
|
|
stroke: '#888'
|
|
|
|
}));
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 100,
|
|
|
|
y: 100,
|
|
|
|
radius: 10,
|
|
|
|
fill: '#888'
|
|
|
|
}));
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 250,
|
|
|
|
y: 100,
|
|
|
|
radius: 10,
|
|
|
|
fill: '#888'
|
|
|
|
}));
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 400,
|
|
|
|
y: 300,
|
|
|
|
radius: 10,
|
|
|
|
fill: '#888'
|
|
|
|
}));
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 250,
|
|
|
|
y: 300,
|
|
|
|
radius: 10,
|
|
|
|
stroke: 'blue'
|
|
|
|
}));
|
|
|
|
|
|
|
|
stage.add(layer);
|
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('path arc', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
|
|
|
var c = "M100,350 l 50,-25 a25,25 -30 0,1 50,-25 l 50,-25 a25,50 -30 0,1 50,-25 l 50,-25 a25,75 -30 0,1 50,-25 l 50,-25 a25,100 -30 0,1 50,-25 l 50,-25";
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
data: c,
|
|
|
|
fill: 'none',
|
|
|
|
stroke: '#999',
|
|
|
|
strokeWidth: 1
|
|
|
|
});
|
|
|
|
|
|
|
|
path.on('mouseover', function() {
|
|
|
|
this.setFill('red');
|
|
|
|
layer.draw();
|
|
|
|
});
|
|
|
|
|
|
|
|
path.on('mouseout', function() {
|
|
|
|
this.setFill('none');
|
|
|
|
layer.draw();
|
|
|
|
});
|
|
|
|
|
|
|
|
layer.add(path);
|
|
|
|
stage.add(layer);
|
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('Tiger (RAWR!)', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
var group = new Kinetic.Group();
|
|
|
|
|
|
|
|
for(var i = 0; i < tiger.length; i++) {
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path(tiger[i]);
|
2012-11-14 13:37:28 +08:00
|
|
|
group.add(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
group.setDraggable(true);
|
|
|
|
layer.add(group);
|
|
|
|
stage.add(layer);
|
|
|
|
|
2013-08-26 20:10:32 +08:00
|
|
|
showHit(layer);
|
2012-11-14 13:37:28 +08:00
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('Able to determine point on line some distance from another point on line', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
|
|
|
var c = "M10,10 210,160";
|
|
|
|
// i.e., from a 3-4-5 triangle
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
stroke: 'red',
|
|
|
|
strokeWidth: 3
|
|
|
|
});
|
|
|
|
|
|
|
|
path.setData(c);
|
|
|
|
layer.add(path);
|
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: 10,
|
|
|
|
y: 10,
|
|
|
|
radius: 10,
|
|
|
|
fill: 'black'
|
|
|
|
}));
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var p1 = Kinetic.Path.getPointOnLine(125, 10, 10, 210, 160);
|
2012-11-14 13:37:28 +08:00
|
|
|
// should be 1/2 way, or (110,85)
|
2013-09-08 14:42:11 +08:00
|
|
|
assert.equal(Math.round(p1.x), 110);
|
|
|
|
assert.equal(Math.round(p1.y), 85);
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
layer.add(new Kinetic.Circle({
|
|
|
|
x: p1.x,
|
|
|
|
y: p1.y,
|
|
|
|
radius: 10,
|
|
|
|
fill: 'blue'
|
|
|
|
}));
|
|
|
|
|
|
|
|
stage.add(layer);
|
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('Able to determine points on Cubic Bezier Curve', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
|
|
|
var c = "M100,200 C100,100 250,100 250,200 S400,300 400,200";
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
stroke: 'red',
|
|
|
|
strokeWidth: 3
|
|
|
|
});
|
|
|
|
|
|
|
|
path.setData(c);
|
|
|
|
|
|
|
|
layer.add(path);
|
|
|
|
c = 'M 100 200';
|
|
|
|
|
|
|
|
for( t = 0.25; t <= 1; t += 0.25) {
|
2013-03-25 11:42:27 +08:00
|
|
|
var p1 = Kinetic.Path.getPointOnCubicBezier(t, 100, 200, 100, 100, 250, 100, 250, 200);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
for( t = 0.25; t <= 1; t += 0.25) {
|
2013-03-25 11:42:27 +08:00
|
|
|
var p1 = Kinetic.Path.getPointOnCubicBezier(t, 250, 200, 250, 300, 400, 300, 400, 200);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
}
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var testPath = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
stroke: 'black',
|
|
|
|
strokewidth: 2,
|
|
|
|
data: c
|
|
|
|
});
|
|
|
|
|
|
|
|
layer.add(testPath);
|
|
|
|
stage.add(layer);
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('Able to determine points on Quadratic Curve', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
|
|
|
var c = "M200,300 Q400,50 600,300 T1000,300";
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
stroke: 'red',
|
|
|
|
strokeWidth: 3
|
|
|
|
});
|
|
|
|
|
|
|
|
path.setData(c);
|
|
|
|
|
|
|
|
layer.add(path);
|
|
|
|
c = 'M 200 300';
|
|
|
|
|
|
|
|
for( t = 0.333; t <= 1; t += 0.333) {
|
2013-03-25 11:42:27 +08:00
|
|
|
var p1 = Kinetic.Path.getPointOnQuadraticBezier(t, 200, 300, 400, 50, 600, 300);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
for( t = 0.333; t <= 1; t += 0.333) {
|
2013-03-25 11:42:27 +08:00
|
|
|
var p1 = Kinetic.Path.getPointOnQuadraticBezier(t, 600, 300, 800, 550, 1000, 300);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
}
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var testPath = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
stroke: 'black',
|
|
|
|
strokewidth: 2,
|
|
|
|
data: c
|
|
|
|
});
|
|
|
|
|
|
|
|
layer.add(testPath);
|
|
|
|
stage.add(layer);
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('Able to determine points on Elliptical Arc with clockwise stroke', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
|
|
|
var c = "M 50,100 A 100 50 0 1 1 150 150";
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
stroke: 'red',
|
|
|
|
strokeWidth: 3
|
|
|
|
});
|
|
|
|
|
|
|
|
path.setData(c);
|
|
|
|
|
|
|
|
layer.add(path);
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var centerParamPoints = Kinetic.Path.convertEndpointToCenterParameterization(50, 100, 150, 150, 1, 1, 100, 50, 0);
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
var start = centerParamPoints[4];
|
|
|
|
// 4 = theta
|
|
|
|
var dTheta = centerParamPoints[5];
|
|
|
|
// 5 = dTheta
|
|
|
|
var end = centerParamPoints[4] + dTheta;
|
|
|
|
var inc = Math.PI / 6.0;
|
|
|
|
// 30 degree resolution
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var p1 = Kinetic.Path.getPointOnEllipticalArc(centerParamPoints[0], centerParamPoints[1], centerParamPoints[2], centerParamPoints[3], start, 0);
|
2012-11-14 13:37:28 +08:00
|
|
|
c = 'M ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
|
|
|
|
if(dTheta < 0)// clockwise
|
|
|
|
{
|
|
|
|
for( t = start - inc; t > end; t -= inc) {
|
2013-03-25 11:42:27 +08:00
|
|
|
p1 = Kinetic.Path.getPointOnEllipticalArc(centerParamPoints[0], centerParamPoints[1], centerParamPoints[2], centerParamPoints[3], t, 0);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else// counter-clockwise
|
|
|
|
{
|
|
|
|
for( t = start + inc; t < end; t += inc) {
|
2013-03-25 11:42:27 +08:00
|
|
|
p1 = Kinetic.Path.getPointOnEllipticalArc(centerParamPoints[0], centerParamPoints[1], centerParamPoints[2], centerParamPoints[3], t, 0);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
}
|
|
|
|
}
|
2013-03-25 11:42:27 +08:00
|
|
|
p1 = Kinetic.Path.getPointOnEllipticalArc(centerParamPoints[0], centerParamPoints[1], centerParamPoints[2], centerParamPoints[3], end, 0);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var testpath = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
stroke: 'black',
|
|
|
|
strokeWidth: 2,
|
|
|
|
data: c
|
|
|
|
});
|
|
|
|
|
|
|
|
layer.add(testpath);
|
|
|
|
stage.add(layer);
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('Able to determine points on Elliptical Arc with counter-clockwise stroke', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
|
|
|
var c = "M 250,100 A 100 50 0 1 0 150 150";
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
stroke: 'red',
|
|
|
|
strokeWidth: 3
|
|
|
|
});
|
|
|
|
|
|
|
|
path.setData(c);
|
|
|
|
|
|
|
|
layer.add(path);
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var centerParamPoints = Kinetic.Path.convertEndpointToCenterParameterization(250, 100, 150, 150, 1, 0, 100, 50, 0);
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
var start = centerParamPoints[4];
|
|
|
|
// 4 = theta
|
|
|
|
var dTheta = centerParamPoints[5];
|
|
|
|
// 5 = dTheta
|
|
|
|
var end = centerParamPoints[4] + dTheta;
|
|
|
|
var inc = Math.PI / 6.0;
|
|
|
|
// 30 degree resolution
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var p1 = Kinetic.Path.getPointOnEllipticalArc(centerParamPoints[0], centerParamPoints[1], centerParamPoints[2], centerParamPoints[3], start, 0);
|
2012-11-14 13:37:28 +08:00
|
|
|
c = 'M ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
|
|
|
|
if(dTheta < 0)// clockwise
|
|
|
|
{
|
|
|
|
for( t = start - inc; t > end; t -= inc) {
|
2013-03-25 11:42:27 +08:00
|
|
|
p1 = Kinetic.Path.getPointOnEllipticalArc(centerParamPoints[0], centerParamPoints[1], centerParamPoints[2], centerParamPoints[3], t, 0);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else// counter-clockwise
|
|
|
|
{
|
|
|
|
for( t = start + inc; t < end; t += inc) {
|
2013-03-25 11:42:27 +08:00
|
|
|
p1 = Kinetic.Path.getPointOnEllipticalArc(centerParamPoints[0], centerParamPoints[1], centerParamPoints[2], centerParamPoints[3], t, 0);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
}
|
|
|
|
}
|
2013-03-25 11:42:27 +08:00
|
|
|
p1 = Kinetic.Path.getPointOnEllipticalArc(centerParamPoints[0], centerParamPoints[1], centerParamPoints[2], centerParamPoints[3], end, 0);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var testpath = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
stroke: 'black',
|
|
|
|
strokeWidth: 2,
|
|
|
|
data: c
|
|
|
|
});
|
|
|
|
|
|
|
|
layer.add(testpath);
|
|
|
|
stage.add(layer);
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('Able to determine points on Elliptical Arc when rotated', function() {
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
|
|
|
var c = "M 250,100 A 100 50 30 1 0 150 150";
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var path = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
stroke: 'red',
|
|
|
|
strokeWidth: 3
|
|
|
|
});
|
|
|
|
|
|
|
|
path.setData(c);
|
|
|
|
|
|
|
|
layer.add(path);
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var centerParamPoints = Kinetic.Path.convertEndpointToCenterParameterization(250, 100, 150, 150, 1, 0, 100, 50, 30);
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
var start = centerParamPoints[4];
|
|
|
|
// 4 = theta
|
|
|
|
var dTheta = centerParamPoints[5];
|
|
|
|
// 5 = dTheta
|
|
|
|
var end = centerParamPoints[4] + dTheta;
|
|
|
|
var inc = Math.PI / 6.0;
|
|
|
|
// 30 degree resolution
|
|
|
|
var psi = centerParamPoints[6];
|
|
|
|
// 6 = psi radians
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var p1 = Kinetic.Path.getPointOnEllipticalArc(centerParamPoints[0], centerParamPoints[1], centerParamPoints[2], centerParamPoints[3], start, psi);
|
2012-11-14 13:37:28 +08:00
|
|
|
c = 'M ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
|
|
|
|
if(dTheta < 0)// clockwise
|
|
|
|
{
|
|
|
|
for( t = start - inc; t > end; t -= inc) {
|
2013-03-25 11:42:27 +08:00
|
|
|
p1 = Kinetic.Path.getPointOnEllipticalArc(centerParamPoints[0], centerParamPoints[1], centerParamPoints[2], centerParamPoints[3], t, psi);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else// counter-clockwise
|
|
|
|
{
|
|
|
|
for( t = start + inc; t < end; t += inc) {
|
2013-03-25 11:42:27 +08:00
|
|
|
p1 = Kinetic.Path.getPointOnEllipticalArc(centerParamPoints[0], centerParamPoints[1], centerParamPoints[2], centerParamPoints[3], t, psi);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
}
|
|
|
|
}
|
2013-03-25 11:42:27 +08:00
|
|
|
p1 = Kinetic.Path.getPointOnEllipticalArc(centerParamPoints[0], centerParamPoints[1], centerParamPoints[2], centerParamPoints[3], end, psi);
|
2012-11-14 13:37:28 +08:00
|
|
|
c += ' ' + p1.x.toString() + ' ' + p1.y.toString();
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var testpath = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
stroke: 'black',
|
|
|
|
strokeWidth: 2,
|
|
|
|
data: c
|
|
|
|
});
|
|
|
|
|
|
|
|
layer.add(testpath);
|
|
|
|
stage.add(layer);
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('getPointOnLine for different directions', function() {
|
2012-11-14 13:37:28 +08:00
|
|
|
var origo = {
|
|
|
|
x: 0,
|
|
|
|
y: 0
|
|
|
|
};
|
|
|
|
|
|
|
|
var p, point;
|
|
|
|
|
|
|
|
//point up left
|
|
|
|
p = {
|
|
|
|
x: -10,
|
|
|
|
y: -10
|
|
|
|
};
|
2013-03-25 11:42:27 +08:00
|
|
|
point = Kinetic.Path.getPointOnLine(10, origo.x, origo.y, p.x, p.y);
|
2013-09-08 14:42:11 +08:00
|
|
|
assert(point.x < 0 && point.y < 0, 'The new point should be up left');
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
//point up right
|
|
|
|
p = {
|
|
|
|
x: 10,
|
|
|
|
y: -10
|
|
|
|
};
|
2013-03-25 11:42:27 +08:00
|
|
|
point = Kinetic.Path.getPointOnLine(10, origo.x, origo.y, p.x, p.y);
|
2013-09-08 14:42:11 +08:00
|
|
|
assert(point.x > 0 && point.y < 0, 'The new point should be up right');
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
//point down right
|
|
|
|
p = {
|
|
|
|
x: 10,
|
|
|
|
y: 10
|
|
|
|
};
|
2013-03-25 11:42:27 +08:00
|
|
|
point = Kinetic.Path.getPointOnLine(10, origo.x, origo.y, p.x, p.y);
|
2013-09-08 14:42:11 +08:00
|
|
|
assert(point.x > 0 && point.y > 0, 'The new point should be down right');
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
//point down left
|
|
|
|
p = {
|
|
|
|
x: -10,
|
|
|
|
y: 10
|
|
|
|
};
|
2013-03-25 11:42:27 +08:00
|
|
|
point = Kinetic.Path.getPointOnLine(10, origo.x, origo.y, p.x, p.y);
|
2013-09-08 14:42:11 +08:00
|
|
|
assert(point.x < 0 && point.y > 0, 'The new point should be down left');
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
//point left
|
|
|
|
p = {
|
|
|
|
x: -10,
|
|
|
|
y: 0
|
|
|
|
};
|
2013-03-25 11:42:27 +08:00
|
|
|
point = Kinetic.Path.getPointOnLine(10, origo.x, origo.y, p.x, p.y);
|
2013-09-08 14:42:11 +08:00
|
|
|
assert(point.x == -10 && point.y == 0, 'The new point should be left');
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
//point up
|
|
|
|
p = {
|
|
|
|
x: 0,
|
|
|
|
y: -10
|
|
|
|
};
|
2013-03-25 11:42:27 +08:00
|
|
|
point = Kinetic.Path.getPointOnLine(10, origo.x, origo.y, p.x, p.y);
|
2013-09-08 14:42:11 +08:00
|
|
|
assert(Math.abs(point.x) < 0.0000001 && point.y == -10, 'The new point should be up');
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
//point right
|
|
|
|
p = {
|
|
|
|
x: 10,
|
|
|
|
y: 0
|
|
|
|
};
|
2013-03-25 11:42:27 +08:00
|
|
|
point = Kinetic.Path.getPointOnLine(10, origo.x, origo.y, p.x, p.y);
|
2013-09-08 14:42:11 +08:00
|
|
|
assert(point.x == 10 && point.y == 0, 'The new point should be right');
|
2012-11-14 13:37:28 +08:00
|
|
|
|
|
|
|
//point down
|
|
|
|
p = {
|
|
|
|
x: 0,
|
|
|
|
y: 10
|
|
|
|
};
|
2013-03-25 11:42:27 +08:00
|
|
|
point = Kinetic.Path.getPointOnLine(10, origo.x, origo.y, p.x, p.y);
|
2013-09-08 14:42:11 +08:00
|
|
|
assert(Math.abs(point.x) < 0.0000001 && point.y == 10, 'The new point should be down');
|
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('Borneo Map (has scientific notation: -10e-4)', function() {
|
|
|
|
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2012-11-14 13:37:28 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
2013-03-25 11:42:27 +08:00
|
|
|
var borneo = new Kinetic.Path({
|
2012-11-14 13:37:28 +08:00
|
|
|
data: "m 136.68513,236.08861 c -0.63689,-0.67792 -0.75417,-1.28099 -1.03556,-5.32352 -0.26489,-3.80589 -0.4465,-4.81397 -1.09951,-6.1026 -0.51169,-1.00981 -0.98721,-1.54361 -1.375,-1.54361 -0.8911,0 -3.48931,-1.22828 -3.80975,-1.80103 -0.16294,-0.29089 -0.87295,-0.56825 -1.68693,-0.65886 -1.13423,-0.12629 -1.91094,0.0661 -4.02248,0.99633 -4.0367,1.77835 -5.46464,1.87106 -6.79674,0.44127 -0.51948,-0.55765 -0.64763,-1.12674 -0.64763,-2.87683 l 0,-2.18167 -0.87832,0.20996 c -0.48312,0.11549 -1.12041,0.33383 -1.41635,0.4852 -1.52799,0.78172 -4.61534,-0.0398 -5.55846,-1.47906 -0.30603,-0.46718 -1.06518,-1.19501 -1.68667,-1.61739 -1.27136,-0.86387 -1.62607,-0.6501 -1.63439,0.98494 -0.007,1.00822 -0.76687,2.38672 -1.31885,2.38672 -0.17579,0 -1.27182,0.66553 -2.4356,1.47895 -4.016775,2.8076 -6.006455,3.29182 -7.693525,1.87231 -0.52348,-0.44054 -1.43004,-1.00203 -2.01445,-1.24775 -1.35902,-0.57143 -2.10139,-0.21496 -5.36296,2.57523 -2.00259,1.71315 -2.55857,2.02869 -3.57441,2.02869 -0.66172,0 -1.31931,-0.17966 -1.46135,-0.39925 -0.27734,-0.42865 -0.75823,-5.15099 -0.87007,-8.54399 -0.0708,-2.14922 -0.41754,-3.83281 -0.78935,-3.83281 -0.1176,0 -0.45993,0.28746 -0.76078,0.63881 -0.66657,0.77849 -3.4572,0.87321 -4.70537,0.15969 -1.29782,-0.7419 -2.38029,-0.55672 -5.01545,0.85797 -2.16783,1.16385 -2.75945,1.33971 -4.5666,1.35746 -1.66762,0.0163 -2.276,-0.12217 -3.09174,-0.70405 -0.61985,-0.44211 -1.09397,-0.5977 -1.21663,-0.39925 -0.32993,0.53385 -2.25686,0.37294 -2.80642,-0.23436 -0.27856,-0.30774 -0.65658,-0.95453 -0.8401,-1.43731 -0.42448,-1.11632 -0.91809,-1.10316 -3.01531,0.0804 -0.93379,0.52702 -2.13107,0.9582 -2.66054,0.9582 -1.46554,0 -1.97734,-0.82307 -2.19476,-3.52955 -0.10515,-1.30865 -0.4137,-2.90864 -0.68575,-3.55553 -0.37975,-0.90312 -0.41736,-1.39768 -0.16196,-2.13038 0.35544,-1.01957 -0.24711,-3.50377 -1.40121,-5.77657 -0.48023,-0.94578 -0.50724,-1.33822 -0.19445,-2.82926 0.40575,-1.93441 -0.0409,-3.36568 -1.16059,-3.72114 -0.3255,-0.10331 -0.93466,-0.55279 -1.35374,-0.99885 -1.12569,-1.19829 -1.03821,-2.92553 0.22088,-4.35957 0.85079,-0.96896 1.01308,-1.45348 1.2082,-3.60666 l 0.22545,-2.48734 -1.16949,-1.19763 c -0.64324,-0.65869 -1.26203,-1.64897 -1.37517,-2.20061 -0.13388,-0.6528 -0.56813,-1.23242 -1.24372,-1.66009 l -1.03807,-0.65709 0,1.0782 c 0,0.59301 -0.21786,1.38922 -0.48413,1.76937 -0.68007,0.97099 -4.56312,2.96438 -5.77445,2.96438 -1.55729,0 -1.88611,-0.67097 -1.88611,-3.84837 0,-3.52819 0.41663,-4.13666 2.83284,-4.13666 1.49279,0 1.57631,-0.0396 1.09598,-0.51996 -0.4316,-0.43155 -0.69566,-0.4587 -1.55343,-0.15971 -0.56839,0.19815 -1.3354,0.35443 -1.70442,0.34729 -0.86278,-0.0167 -2.61563,-1.51607 -3.02205,-2.58498 -0.3513,-0.92403 -0.12267,-3.38466 0.34119,-3.67132 0.16474,-0.1018 -0.39367,-0.50661 -1.24085,-0.89959 -2.032471,-0.94281 -2.321421,-1.35146 -2.487701,-3.51839 -0.0772,-1.00533 -0.30119,-2.31552 -0.4979,-2.91152 -0.48076,-1.45668 -0.16499,-2.30832 0.90163,-2.43139 0.843711,-0.0974 0.860511,-0.14171 0.748911,-1.97594 -0.0696,-1.14269 0.0236,-1.96143 0.23793,-2.09396 0.47223,-0.29188 -2.501621,-3.97433 -3.330171,-4.12358 -0.34456,-0.062 -0.75956,-0.23921 -0.92229,-0.39365 -0.3459,-0.32835 -0.78945,-2.83658 -0.98794,-5.58637 -0.0769,-1.06517 -0.35848,-2.55647 -0.62576,-3.31402 -0.71739,-2.03331 -0.61465,-2.55112 0.76687,-3.86532 l 1.25273,-1.19173 -0.46915,-1.36178 c -0.53343,-1.54826 -0.33638,-2.99085 0.48923,-3.5815 0.65547,-0.46898 1.32731,-2.61652 1.52388,-4.87126 0.13191,-1.51252 0.2658,-1.7153 2.531131,-3.83281 2.21127,-2.06705 2.41106,-2.36144 2.64687,-3.89989 0.31881,-2.07979 0.74608,-2.60075 2.34208,-2.85597 0.69615,-0.11132 1.66359,-0.53718 2.14988,-0.94636 1.89204,-1.59201 4.16695,-1.77416 4.16695,-0.33363 0,0.40454 -0.23171,1.4157 -0.51499,2.24703 -0.28322,0.83134 -0.45486,1.57164 -0.38139,1.64512 0.0735,0.0735 1.32057,0.92807 2.77127,1.89909 2.57827,1.72574 2.68847,1.7655 4.89522,1.7655 1.74495,0 2.50706,-0.15424 3.35669,-0.67937 0.91121,-0.56315 1.2344,-0.61779 1.88934,-0.3194 0.43449,0.19798 1.19684,0.35997 1.69411,0.35997 1.03354,0 1.51204,0.45563 1.67033,1.59058 0.109
|
|
|
|
fill: "blue"
|
|
|
|
});
|
|
|
|
layer.add(borneo);
|
|
|
|
stage.add(layer);
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// ======================================================
|
|
|
|
test('Stroke only when no fill', function() {
|
2013-08-26 20:07:17 +08:00
|
|
|
|
2013-08-26 20:10:32 +08:00
|
|
|
// https://github.com/ericdrowell/KineticJS/issues/567
|
|
|
|
|
2013-09-09 12:36:54 +08:00
|
|
|
var stage = addStage();
|
2013-08-26 20:07:17 +08:00
|
|
|
var layer = new Kinetic.Layer();
|
|
|
|
|
|
|
|
var path = new Kinetic.Path({
|
|
|
|
data: "M 50 0 C 50 150 170 170 200 170",
|
2013-08-26 20:10:32 +08:00
|
|
|
stroke: 'black'
|
|
|
|
});
|
2013-09-08 14:42:11 +08:00
|
|
|
|
|
|
|
// override color key so that we can test the context trace
|
|
|
|
path.colorKey = 'black';
|
|
|
|
|
2013-08-26 20:10:32 +08:00
|
|
|
path.on('mouseover', function () {
|
|
|
|
this.setStroke("#f00");
|
|
|
|
layer.draw();
|
2013-08-26 20:07:17 +08:00
|
|
|
});
|
|
|
|
|
2013-08-26 20:10:32 +08:00
|
|
|
path.on('mouseout', function(){
|
|
|
|
this.setStroke("#000");
|
|
|
|
layer.draw();
|
|
|
|
});
|
2013-08-26 20:07:17 +08:00
|
|
|
|
2013-09-08 14:42:11 +08:00
|
|
|
|
2013-08-26 20:07:17 +08:00
|
|
|
layer.add(path);
|
|
|
|
stage.add(layer);
|
2013-09-08 14:42:11 +08:00
|
|
|
|
|
|
|
showHit(layer);
|
|
|
|
|
|
|
|
var trace = layer.getContext().getTrace();
|
|
|
|
|
|
|
|
//console.log(trace);
|
|
|
|
|
|
|
|
var hitTrace = layer.hitCanvas.getContext().getTrace();
|
|
|
|
//console.log(hitTrace);
|
|
|
|
|
2013-09-16 13:59:09 +08:00
|
|
|
assert.equal(trace, 'clearRect(0,0,578,200);save();transform(1,0,0,1,0,0);beginPath();moveTo(50,0);bezierCurveTo(50,150,170,170,200,170);lineWidth=2;strokeStyle=black;stroke();restore();');
|
|
|
|
assert.equal(hitTrace, 'clearRect(0,0,578,200);save();transform(1,0,0,1,0,0);beginPath();moveTo(50,0);bezierCurveTo(50,150,170,170,200,170);lineWidth=2;strokeStyle=black;stroke();restore();');
|
2013-09-08 14:42:11 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
});
|