created _getFillType utility to help manage fill type objects. You can now dynamically switch between different fill types, including colors, linear gradients, radial gradients, and patterns

This commit is contained in:
ericdrowell 2012-09-25 15:57:57 -07:00
parent ff926b34af
commit d4734ba33a
6 changed files with 300 additions and 223 deletions

242
dist/kinetic-core.js vendored
View File

@ -1659,14 +1659,7 @@ Kinetic.Node.prototype = {
this.parent.children.splice(index, 1);
this.parent.children.push(this);
this.parent._setChildrenIndices();
if(this.nodeType === 'Layer') {
var stage = this.getStage();
if(stage) {
stage.content.removeChild(this.canvas.element);
stage.content.appendChild(this.canvas.element);
}
}
return true;
},
/**
* move node up
@ -1679,20 +1672,7 @@ Kinetic.Node.prototype = {
this.parent.children.splice(index, 1);
this.parent.children.splice(index + 1, 0, this);
this.parent._setChildrenIndices();
if(this.nodeType === 'Layer') {
var stage = this.getStage();
if(stage) {
stage.content.removeChild(this.canvas.element);
if(this.index < stage.getChildren().length - 1) {
stage.content.insertBefore(this.canvas.element, stage.getChildren()[this.index + 1].canvas.element);
}
else {
stage.content.appendChild(this.canvas.element);
}
}
}
return true;
}
},
/**
@ -1706,15 +1686,7 @@ Kinetic.Node.prototype = {
this.parent.children.splice(index, 1);
this.parent.children.splice(index - 1, 0, this);
this.parent._setChildrenIndices();
if(this.nodeType === 'Layer') {
var stage = this.getStage();
if(stage) {
var children = stage.getChildren();
stage.content.removeChild(this.canvas.element);
stage.content.insertBefore(this.canvas.element, children[this.index + 1].canvas.element);
}
}
return true;
}
},
/**
@ -1728,15 +1700,7 @@ Kinetic.Node.prototype = {
this.parent.children.splice(index, 1);
this.parent.children.unshift(this);
this.parent._setChildrenIndices();
if(this.nodeType === 'Layer') {
var stage = this.getStage();
if(stage) {
var children = stage.getChildren();
stage.content.removeChild(this.canvas.element);
stage.content.insertBefore(this.canvas.element, children[1].canvas.element);
}
}
return true;
}
},
/**
@ -1807,12 +1771,7 @@ Kinetic.Node.prototype = {
* @methodOf Kinetic.Node.prototype
*/
getLayer: function() {
if(this.nodeType === 'Layer') {
return this;
}
else {
return this.getParent().getLayer();
}
return this.getParent().getLayer();
},
/**
* get stage that contains the node
@ -1820,12 +1779,9 @@ Kinetic.Node.prototype = {
* @methodOf Kinetic.Node.prototype
*/
getStage: function() {
if(this.nodeType !== 'Stage' && this.getParent()) {
if(this.getParent()) {
return this.getParent().getStage();
}
else if(this.nodeType === 'Stage') {
return this;
}
else {
return undefined;
}
@ -3672,6 +3628,7 @@ Kinetic.Layer.prototype = {
clear: function() {
this.getCanvas().clear();
},
// extenders
setVisible: function(visible) {
Kinetic.Node.prototype.setVisible.call(this, visible);
if(visible) {
@ -3681,6 +3638,52 @@ Kinetic.Layer.prototype = {
this.canvas.element.style.display = 'none';
}
},
moveToTop: function() {
Kinetic.Node.prototype.moveToTop.call(this);
var stage = this.getStage();
if(stage) {
stage.content.removeChild(this.canvas.element);
stage.content.appendChild(this.canvas.element);
}
},
moveUp: function() {
if(Kinetic.Node.prototype.moveUp.call(this)) {
var stage = this.getStage();
if(stage) {
stage.content.removeChild(this.canvas.element);
if(this.index < stage.getChildren().length - 1) {
stage.content.insertBefore(this.canvas.element, stage.getChildren()[this.index + 1].canvas.element);
}
else {
stage.content.appendChild(this.canvas.element);
}
}
}
},
moveDown: function() {
if(Kinetic.Node.prototype.moveDown.call(this)) {
var stage = this.getStage();
if(stage) {
var children = stage.getChildren();
stage.content.removeChild(this.canvas.element);
stage.content.insertBefore(this.canvas.element, children[this.index + 1].canvas.element);
}
}
},
moveToBottom: function() {
if(Kinetic.Node.prototype.moveToBottom.call(this)) {
var stage = this.getStage();
if(stage) {
var children = stage.getChildren();
stage.content.removeChild(this.canvas.element);
stage.content.insertBefore(this.canvas.element, children[1].canvas.element);
}
}
},
getLayer: function() {
return this;
},
/**
* Creates a composite data URL. If MIME type is not
* specified, then "image/png" will result. For "image/jpeg", specify a quality
@ -3926,6 +3929,26 @@ Kinetic.Shape.prototype = {
}
}
},
_getFillType: function(fill) {
if(!fill) {
return undefined;
}
else if(Kinetic.Type._isString(fill)) {
return 'COLOR';
}
else if(fill.image) {
return 'PATTERN';
}
else if(fill.start && fill.end && !fill.start.radius && !fill.end.radius) {
return 'LINEAR_GRADIENT';
}
else if(fill.start && fill.end && Kinetic.Type._isNumber(fill.start.radius) && Kinetic.Type._isNumber(fill.end.radius)) {
return 'RADIAL_GRADIENT';
}
else {
return 'UNKNOWN';
}
},
/**
* helper method to fill the shape with a color, linear gradient,
* radial gradient, or pattern, and also apply shadows if needed
@ -3934,7 +3957,8 @@ Kinetic.Shape.prototype = {
* */
fill: function(context) {
var appliedShadow = false;
var fill = this.attrs.fill;
var fill = this.getFill();
var fillType = this._getFillType(fill);
if(fill) {
context.save();
if(this.attrs.shadow && !this.appliedShadow) {
@ -3943,53 +3967,52 @@ Kinetic.Shape.prototype = {
var s = fill.start;
var e = fill.end;
var f = null;
// color fill
if(Kinetic.Type._isString(fill)) {
context.fillStyle = fill;
context.fill(context);
}
// pattern
else if(fill.image) {
var repeat = !fill.repeat ? 'repeat' : fill.repeat;
if(fill.scale) {
context.scale(fill.scale.x, fill.scale.y);
}
if(fill.offset) {
context.translate(fill.offset.x, fill.offset.y);
}
switch(fillType) {
case 'COLOR':
context.fillStyle = fill;
context.fill(context);
break;
case 'PATTERN':
var repeat = !fill.repeat ? 'repeat' : fill.repeat;
if(fill.scale) {
context.scale(fill.scale.x, fill.scale.y);
}
if(fill.offset) {
context.translate(fill.offset.x, fill.offset.y);
}
context.fillStyle = context.createPattern(fill.image, repeat);
context.fill(context);
}
// linear gradient
else if(!s.radius && !e.radius) {
var grd = context.createLinearGradient(s.x, s.y, e.x, e.y);
var colorStops = fill.colorStops;
context.fillStyle = context.createPattern(fill.image, repeat);
context.fill(context);
break;
case 'LINEAR_GRADIENT':
var grd = context.createLinearGradient(s.x, s.y, e.x, e.y);
var colorStops = fill.colorStops;
// build color stops
for(var n = 0; n < colorStops.length; n += 2) {
grd.addColorStop(colorStops[n], colorStops[n + 1]);
}
context.fillStyle = grd;
context.fill(context);
}
// radial gradient
else if((s.radius || s.radius === 0) && (e.radius || e.radius === 0)) {
var grd = context.createRadialGradient(s.x, s.y, s.radius, e.x, e.y, e.radius);
var colorStops = fill.colorStops;
// build color stops
for(var n = 0; n < colorStops.length; n += 2) {
grd.addColorStop(colorStops[n], colorStops[n + 1]);
}
context.fillStyle = grd;
context.fill(context);
// build color stops
for(var n = 0; n < colorStops.length; n += 2) {
grd.addColorStop(colorStops[n], colorStops[n + 1]);
}
context.fillStyle = grd;
context.fill(context);
}
else {
context.fillStyle = 'black';
context.fill(context);
break;
case 'RADIAL_GRADIENT':
var grd = context.createRadialGradient(s.x, s.y, s.radius, e.x, e.y, e.radius);
var colorStops = fill.colorStops;
// build color stops
for(var n = 0; n < colorStops.length; n += 2) {
grd.addColorStop(colorStops[n], colorStops[n + 1]);
}
context.fillStyle = grd;
context.fill(context);
break;
default:
context.fillStyle = 'black';
context.fill(context);
break;
}
context.restore();
}
@ -4112,26 +4135,27 @@ Kinetic.Shape.prototype = {
* @methodOf Kinetic.Shape.prototype
* @param {String|Object} fill
*/
setFill: function(config) {
var fill;
setFill: function(fill) {
var oldFill = this.getFill();
var fillType = this._getFillType(fill);
var oldFillType = this._getFillType(oldFill);
var newOrOldFillIsColor = fillType === 'COLOR' || oldFillType === 'COLOR';
var changedFillType = fillType === oldFillType || fillType === 'UNKNOWN';
if(Kinetic.Type._isString(config)) {
fill = config;
// if fill.offset is defined, normalize the xy value
if(fill.offset !== undefined) {
fill.offset = Kinetic.Type._getXY(fill.offset);
}
// if not a string, config should be an object
else {
if(config.offset !== undefined) {
config.offset = Kinetic.Type._getXY(config.offset);
}
var oldFill = this.getFill();
if(Kinetic.Type._isObject(oldFill)) {
fill = Kinetic.Type._merge(config, oldFill);
}
else {
fill = config;
}
/*
* merge fill objects if neither the new or old fill
* is type is COLOR, and if if the fill type has not changed. Otherwise,
* overwrite the fill entirely
*/
if(!newOrOldFillIsColor && changedFillType) {
fill = Kinetic.Type._merge(fill, oldFill);
}
this.setAttr('fill', fill);
},
/**

File diff suppressed because one or more lines are too long

View File

@ -139,6 +139,7 @@ Kinetic.Layer.prototype = {
clear: function() {
this.getCanvas().clear();
},
// extenders
setVisible: function(visible) {
Kinetic.Node.prototype.setVisible.call(this, visible);
if(visible) {
@ -148,6 +149,52 @@ Kinetic.Layer.prototype = {
this.canvas.element.style.display = 'none';
}
},
moveToTop: function() {
Kinetic.Node.prototype.moveToTop.call(this);
var stage = this.getStage();
if(stage) {
stage.content.removeChild(this.canvas.element);
stage.content.appendChild(this.canvas.element);
}
},
moveUp: function() {
if(Kinetic.Node.prototype.moveUp.call(this)) {
var stage = this.getStage();
if(stage) {
stage.content.removeChild(this.canvas.element);
if(this.index < stage.getChildren().length - 1) {
stage.content.insertBefore(this.canvas.element, stage.getChildren()[this.index + 1].canvas.element);
}
else {
stage.content.appendChild(this.canvas.element);
}
}
}
},
moveDown: function() {
if(Kinetic.Node.prototype.moveDown.call(this)) {
var stage = this.getStage();
if(stage) {
var children = stage.getChildren();
stage.content.removeChild(this.canvas.element);
stage.content.insertBefore(this.canvas.element, children[this.index + 1].canvas.element);
}
}
},
moveToBottom: function() {
if(Kinetic.Node.prototype.moveToBottom.call(this)) {
var stage = this.getStage();
if(stage) {
var children = stage.getChildren();
stage.content.removeChild(this.canvas.element);
stage.content.insertBefore(this.canvas.element, children[1].canvas.element);
}
}
},
getLayer: function() {
return this;
},
/**
* Creates a composite data URL. If MIME type is not
* specified, then "image/png" will result. For "image/jpeg", specify a quality

View File

@ -436,14 +436,7 @@ Kinetic.Node.prototype = {
this.parent.children.splice(index, 1);
this.parent.children.push(this);
this.parent._setChildrenIndices();
if(this.nodeType === 'Layer') {
var stage = this.getStage();
if(stage) {
stage.content.removeChild(this.canvas.element);
stage.content.appendChild(this.canvas.element);
}
}
return true;
},
/**
* move node up
@ -456,20 +449,7 @@ Kinetic.Node.prototype = {
this.parent.children.splice(index, 1);
this.parent.children.splice(index + 1, 0, this);
this.parent._setChildrenIndices();
if(this.nodeType === 'Layer') {
var stage = this.getStage();
if(stage) {
stage.content.removeChild(this.canvas.element);
if(this.index < stage.getChildren().length - 1) {
stage.content.insertBefore(this.canvas.element, stage.getChildren()[this.index + 1].canvas.element);
}
else {
stage.content.appendChild(this.canvas.element);
}
}
}
return true;
}
},
/**
@ -483,15 +463,7 @@ Kinetic.Node.prototype = {
this.parent.children.splice(index, 1);
this.parent.children.splice(index - 1, 0, this);
this.parent._setChildrenIndices();
if(this.nodeType === 'Layer') {
var stage = this.getStage();
if(stage) {
var children = stage.getChildren();
stage.content.removeChild(this.canvas.element);
stage.content.insertBefore(this.canvas.element, children[this.index + 1].canvas.element);
}
}
return true;
}
},
/**
@ -505,15 +477,7 @@ Kinetic.Node.prototype = {
this.parent.children.splice(index, 1);
this.parent.children.unshift(this);
this.parent._setChildrenIndices();
if(this.nodeType === 'Layer') {
var stage = this.getStage();
if(stage) {
var children = stage.getChildren();
stage.content.removeChild(this.canvas.element);
stage.content.insertBefore(this.canvas.element, children[1].canvas.element);
}
}
return true;
}
},
/**
@ -584,12 +548,7 @@ Kinetic.Node.prototype = {
* @methodOf Kinetic.Node.prototype
*/
getLayer: function() {
if(this.nodeType === 'Layer') {
return this;
}
else {
return this.getParent().getLayer();
}
return this.getParent().getLayer();
},
/**
* get stage that contains the node
@ -597,12 +556,9 @@ Kinetic.Node.prototype = {
* @methodOf Kinetic.Node.prototype
*/
getStage: function() {
if(this.nodeType !== 'Stage' && this.getParent()) {
if(this.getParent()) {
return this.getParent().getStage();
}
else if(this.nodeType === 'Stage') {
return this;
}
else {
return undefined;
}

View File

@ -127,6 +127,26 @@ Kinetic.Shape.prototype = {
}
}
},
_getFillType: function(fill) {
if(!fill) {
return undefined;
}
else if(Kinetic.Type._isString(fill)) {
return 'COLOR';
}
else if(fill.image) {
return 'PATTERN';
}
else if(fill.start && fill.end && !fill.start.radius && !fill.end.radius) {
return 'LINEAR_GRADIENT';
}
else if(fill.start && fill.end && Kinetic.Type._isNumber(fill.start.radius) && Kinetic.Type._isNumber(fill.end.radius)) {
return 'RADIAL_GRADIENT';
}
else {
return 'UNKNOWN';
}
},
/**
* helper method to fill the shape with a color, linear gradient,
* radial gradient, or pattern, and also apply shadows if needed
@ -135,7 +155,8 @@ Kinetic.Shape.prototype = {
* */
fill: function(context) {
var appliedShadow = false;
var fill = this.attrs.fill;
var fill = this.getFill();
var fillType = this._getFillType(fill);
if(fill) {
context.save();
if(this.attrs.shadow && !this.appliedShadow) {
@ -144,53 +165,52 @@ Kinetic.Shape.prototype = {
var s = fill.start;
var e = fill.end;
var f = null;
// color fill
if(Kinetic.Type._isString(fill)) {
context.fillStyle = fill;
context.fill(context);
}
// pattern
else if(fill.image) {
var repeat = !fill.repeat ? 'repeat' : fill.repeat;
if(fill.scale) {
context.scale(fill.scale.x, fill.scale.y);
}
if(fill.offset) {
context.translate(fill.offset.x, fill.offset.y);
}
switch(fillType) {
case 'COLOR':
context.fillStyle = fill;
context.fill(context);
break;
case 'PATTERN':
var repeat = !fill.repeat ? 'repeat' : fill.repeat;
if(fill.scale) {
context.scale(fill.scale.x, fill.scale.y);
}
if(fill.offset) {
context.translate(fill.offset.x, fill.offset.y);
}
context.fillStyle = context.createPattern(fill.image, repeat);
context.fill(context);
}
// linear gradient
else if(!s.radius && !e.radius) {
var grd = context.createLinearGradient(s.x, s.y, e.x, e.y);
var colorStops = fill.colorStops;
context.fillStyle = context.createPattern(fill.image, repeat);
context.fill(context);
break;
case 'LINEAR_GRADIENT':
var grd = context.createLinearGradient(s.x, s.y, e.x, e.y);
var colorStops = fill.colorStops;
// build color stops
for(var n = 0; n < colorStops.length; n += 2) {
grd.addColorStop(colorStops[n], colorStops[n + 1]);
}
context.fillStyle = grd;
context.fill(context);
}
// radial gradient
else if((s.radius || s.radius === 0) && (e.radius || e.radius === 0)) {
var grd = context.createRadialGradient(s.x, s.y, s.radius, e.x, e.y, e.radius);
var colorStops = fill.colorStops;
// build color stops
for(var n = 0; n < colorStops.length; n += 2) {
grd.addColorStop(colorStops[n], colorStops[n + 1]);
}
context.fillStyle = grd;
context.fill(context);
// build color stops
for(var n = 0; n < colorStops.length; n += 2) {
grd.addColorStop(colorStops[n], colorStops[n + 1]);
}
context.fillStyle = grd;
context.fill(context);
}
else {
context.fillStyle = 'black';
context.fill(context);
break;
case 'RADIAL_GRADIENT':
var grd = context.createRadialGradient(s.x, s.y, s.radius, e.x, e.y, e.radius);
var colorStops = fill.colorStops;
// build color stops
for(var n = 0; n < colorStops.length; n += 2) {
grd.addColorStop(colorStops[n], colorStops[n + 1]);
}
context.fillStyle = grd;
context.fill(context);
break;
default:
context.fillStyle = 'black';
context.fill(context);
break;
}
context.restore();
}
@ -313,26 +333,27 @@ Kinetic.Shape.prototype = {
* @methodOf Kinetic.Shape.prototype
* @param {String|Object} fill
*/
setFill: function(config) {
var fill;
setFill: function(fill) {
var oldFill = this.getFill();
var fillType = this._getFillType(fill);
var oldFillType = this._getFillType(oldFill);
var newOrOldFillIsColor = fillType === 'COLOR' || oldFillType === 'COLOR';
var changedFillType = fillType === oldFillType || fillType === 'UNKNOWN';
if(Kinetic.Type._isString(config)) {
fill = config;
// if fill.offset is defined, normalize the xy value
if(fill.offset !== undefined) {
fill.offset = Kinetic.Type._getXY(fill.offset);
}
// if not a string, config should be an object
else {
if(config.offset !== undefined) {
config.offset = Kinetic.Type._getXY(config.offset);
}
var oldFill = this.getFill();
if(Kinetic.Type._isObject(oldFill)) {
fill = Kinetic.Type._merge(config, oldFill);
}
else {
fill = config;
}
/*
* merge fill objects if neither the new or old fill
* is type is COLOR, and if if the fill type has not changed. Otherwise,
* overwrite the fill entirely
*/
if(!newOrOldFillIsColor && changedFillType) {
fill = Kinetic.Type._merge(fill, oldFill);
}
this.setAttr('fill', fill);
},
/**

View File

@ -1786,7 +1786,7 @@ Test.prototype.tests = {
};
imageObj.src = '../assets/darth-vader.jpg';
},
'SHAPE - set image fill to color then image': function(containerId) {
'SHAPE - set image fill to color then image then linear gradient then back to image': function(containerId) {
var imageObj = new Image();
imageObj.onload = function() {
var stage = new Kinetic.Stage({
@ -1817,7 +1817,27 @@ Test.prototype.tests = {
test(circle.getFill().repeat === 'no-repeat', 'circle fill repeat should be no-repeat');
test(circle.getFill().offset.x === -200, 'circle fill offset x should be -200');
test(circle.getFill().offset.y === -70, 'circle fill offset y should be -70');
circle.setFill({
start: {
x: -35,
y: -35
},
end: {
x: 35,
y: 35
},
colorStops: [0, 'red', 1, 'blue']
});
test(circle.getFill().image === undefined, 'circle fill image should be undefined');
circle.setFill({
image: imageObj,
repeat: 'no-repeat',
offset: [-200, -70]
});
layer.draw();
};
imageObj.src = '../assets/darth-vader.jpg';
@ -4607,6 +4627,15 @@ Test.prototype.tests = {
layer.draw();
},
'STAGE - test stage.getStage()': function(containerId) {
var stage = new Kinetic.Stage({
container: containerId,
width: 578,
height: 200
});
console.log(stage.getStage());
},
'LAYERING - move blue layer on top of green layer with moveToTop': function(containerId) {
var stage = new Kinetic.Stage({
container: containerId,