module.exports = function (canvas) {
/**
* create an environment for canvas drawing
*/
if (!canvas) {
canvas = document.createElement('canvas');
}
var context2d = canvas.getContext('2d');
var context = context2d;
var app = new ApplicationPrototype();
var keyGenerator= ((function () {
var i = 0;
return function () {
i++;
return i.toString(36) + '_' + Math.floor(Math.random() * 1000000000).toString(36);
};
})());
var config = {
debug : false
};
var resource = {
/**
* set of canvas paths
* @type {Array}
*/
paths : [],
animationStatus : false,
animationRequest: false
};
app.bind("debug", function (status) {
if (typeof(status) !== "undefined") {
config.debug = !!status;
}
return config.debug;
})
app.bind("context", function () {
return context;
}, "");
app.bind("paths", function () {
return resource.paths;
}, "");
app.bind("createPath", function (conf) {
/**
* createPath - create a generic path object
* @return {pathObject}
*/
var path = new ApplicationPrototype();
var config = {
id : keyGenerator(),
isReady : true,
groups : [],
coords : [],
vars : {},
operations : []
};
((function () {
var i;
for (i in conf) {
config[i] = conf[i];
}
})());
if (!Array.isArray(config.operations)) config.operations = [];
config.operations = config.operations.map(function (operation) {
if (!operation) return null;
if (typeof(operation) !== "object") return null;
if (!operation.operation) return null;
if (typeof(operation.group) !== "string") operation.group = "";
operation.id = operation.id || keyGenerator();
return operation;
}).filter(function (operation) {
return !!operation;
});
path.bind("app", function () {
return app;
}, "");
path.bind("config", function () {
return config;
}, "");
path.bind("vars", function () {
return config.vars;
}, "");
path.bind("groups", function () {
return config.groups;
}, "");
path.bind("operationsRemoveByGroup", function (group) {
config.operations = config.operations.filter(function (operation) {
return operation.group !== group;
});
return config.operations;
}, "");
path.bind("operationsRemoveById", function (key) {
config.operations = config.operations.filter(function (operation) {
return operation.id !== key;
});
return config.operations;
}, "");
path.bind("operationsRemoveByKey", function (key) {
console.warn("path.operationsRemoveByKey is deprecated from 2016.10.05");
return path.operationsRemoveById(key);
});
path.bind("operationById", function (id) {
return config.operations.filter(function (operation) {
return operation.id === id;
})[0];
}, "");
path.bind("operationsByGroup", function (group) {
return config.operations.filter(function (operation) {
return operation.group === group;
});
}, "");
path.bind("operations", function (operation, params, key, group) {
var i;
var index = false;
for (i=0;i<config.operations.length;i++) {
if (config.operations[i].id === key) {
index = i;
}
}
if (index !== false) {
config.operations[index].operation = operation || config.operations[index].operation;
config.operations[index].params = params || config.operations[index].params;
config.operations[index].group = group || config.operations[index].group;
return path;
} else {
config.operations.push({
operation : operation,
params : (params || []),
id : key || keyGenerator(),
group : group || ""
});
return path;
}
return config.operations;
}, "");
path.bind("coords", function (x,y) {
if (typeof(x) === "number" && typeof(y) === "number") {
var status = false;
config.coords.forEach(function (coords) {
if (coords.length === 4) {
if (
x >= coords[0]
&&
x <= coords[2] + 0.00000001
&&
y >= coords[1]
&&
y <= coords[3] + 0.00000001
) {
status = true;
}
}
});
return status;
}
return config.coords;
}, "");
path.bind("group", function (name, val) {
if (typeof(val) === "undefined") {
return config.groups.indexOf(name) !== -1;
} else {
if (val) {
if (config.groups.indexOf(name) === -1) {
config.groups.push(name);
}
} else {
if (config.groups.indexOf(name) !== -1) {
config.groups = config.groups.filter(function (group) {
return group !== name;
});
}
}
return path;
}
}, "");
path.bind("isReady", function (bool) {
if (typeof(bool) !== "undefined") {
config.isReady = !!bool;
}
return config.isReady;
}, "on");
path.bind("render", function () {
var context = app.context();
context.save();
var er;
config.operations.forEach(function (operation) {
try {
var params = typeof(operation.params) === "function" ? (
operation.params(path, operation, app)
) : operation.params;
if (typeof(operation.operation) === "function") {
if (app.debug()) {
console.log("Operation: operations[" + operation.id + "](", (
typeof(operation.params) === "function" ? (
"@Function"
) : ""
), params + ")");
}
operation.operation.apply(
path,
params || []
);
} else if (typeof(context[operation.operation]) === "function") {
if (app.debug()) {
console.log("Operation: Context." + operation.operation + "(", (
typeof(operation.params) === "function" ? (
"@Function"
) : ""
), params, ")");
}
context[operation.operation].apply(
context,
params || []
);
} else {
if (app.debug()) {
console.log("Operation: Context." + operation.operation + " = ", (
typeof(operation.params) === "function" ? (
"@Function"
) : ""
), params);
}
context[operation.operation] = params;
}
} catch (er) {
console.error(er);
}
});
context.restore();
});
app.emit("path-created", [path]);
return path;
});
app.bind("path", function (conf) {
var path = app.createPath(conf);
resource.paths.push(path);
return path;
}, "");
app.bind("pathById", function (id) {
return resource.paths.filter(function (path) {
return path.config().id === id;
})[0];
}, "");
app.bind("group", function (name) {
return resource.paths.filter(function (path) {
return path.groups().indexOf(name) !== -1;
});
}, "");
app.bind("imageSmoothingEnabled", function (bool) {
if (typeof(bool) !== "undefined") {
config.smoothing = !!bool;
var context = app.context();
context.imageSmoothingEnabled = config.smoothing;
context.mozImageSmoothingEnabled = config.smoothing;
context.webkitImageSmoothingEnabled = config.smoothing;
context.msImageSmoothingEnabled = config.smoothing;
}
return config.smoothing;
}, "on");
// TODO
// ctx.fillStyle = "rgb(200,0,0)";
// // sets the color to fill in the rectangle with
// ctx.fillRect(10, 10, 55, 50);
// // draws the rectangle at position 10, 10 with a width of 55 and a height of 50
// CanvasRenderingContext2D.clearRect()
// CanvasRenderingContext2D.fillRect()
// CanvasRenderingContext2D.strokeRect()
// CanvasRenderingContext2D.fillText()
// CanvasRenderingContext2D.strokeText()
// CanvasRenderingContext2D.measureText()
// createCircle
app.bind("canvas", function () {
return canvas;
}, "");
app.bind("render", function () {
resource.paths.forEach(function (path) {
if (path.isReady()) {
path.render();
}
});
});
app.bind("animate", function (state) {
if (typeof(state) === "undefined") {
resource.animationStatus = true;
app.animate(true);
} else if (state === true) {
app.render();
resource.animationRequest = requestAnimationFrame(function () {
if (resource.animationStatus !== false) {
app.animate(true);
}
});
} else if (state === false) {
var er;
try {
cancelAnimationFrame(resource.animationRequest);
} catch (er) {
console.error(er);
}
resource.animationStatus = false;
}
});
return app;
};