I want to write Bitmap eraser on easelJS. I think, i'm on half of my road to do this....
Here is demo:
http://jsfiddle.net/bordeux/g2Lwvsuv/2/
and my code:
var example = function() {
this.constructor.apply(this, arguments);
};
example.prototype.constructor = function() {
this.$canvas = $("canvas");
this.container = {};
this.objects = {};
this.resizeEvents = [];
this.prepareCanvas();
this.refreshSize();
this.bindEvents();
};
example.prototype.bindEvents = function() {
var self = this;
$(window).resize(function(){
self.refreshSize();
});
};
example.prototype.refreshSize = function() {
this.stage.canvas.width = window.innerWidth;
this.stage.canvas.height = window.innerHeight;
this.resizeEvents.forEach(function(item) {
item();
});
};
example.prototype.getObject = function(name) {
return this.objects[name];
};
example.prototype.setObject = function(name, obj) {
this.objects[name] = obj;
return obj;
};
example.prototype.addResizeEvent = function(foo) {
this.resizeEvents.push(foo);
return this;
};
example.prototype.initCursor = function() {
var self = this;
var size = 50;
/**
* Circle cursor
*/
var circle = new createjs.Shape();
circle.graphics.setStrokeStyle(2).beginStroke("#171717").drawCircle(0, 0, size);
/**
* Hit area
*/
var hit = new createjs.Shape();
hit.graphics.beginFill("#000").drawCircle(0, 0, size);
circle.hitArea = hit;
var container = this.getContainer("cursor");
container.addChild(circle);
this.stage.on("stagemousemove", function(evt) {
circle.setTransform(evt.stageX, evt.stageY);
this.setChildIndex( container, this.getNumChildren()-1);
});
var drawing = this.setObject("image.mask", new createjs.Shape());
drawing.visible = false;
var lastPoint = new createjs.Point();
container.addChild(drawing);
circle.on("mousedown", function(event) {
lastPoint.x = event.stageX;
lastPoint.y = event.stageY;
});
circle.on("pressmove", function(event) {
drawing.graphics
.setStrokeStyle(100, "round", "round")
.beginStroke("rgba(255, 255, 255, 0.2)")
.beginRadialGradientFill(
["rgba(0,0,0,0)", "rgba(0,0,0,1)"],
[0.1, 1],
50, 50, 0,
50, 50, 50
)
.moveTo(lastPoint.x, lastPoint.y)
.lt(event.stageX, event.stageY);
lastPoint.x = event.stageX;
lastPoint.y = event.stageY;
self.updateCache();
});
circle.on("pressup", function(event) {
self.updateCache();
});
};
example.prototype.updateCache = function(update) {
(update === undefined) && (update = false);
var drawingCanvas = this.getObject("image.mask");
var image = this.getObject("image");
if (update) {
drawingCanvas.updateCache();
} else {
drawingCanvas.cache(0, 0, image.image.naturalWidth, image.image.naturalHeight);
}
image.filters = [
new createjs.AlphaMaskFilter(drawingCanvas.cacheCanvas)
];
if (update) {
image.updateCache(0, 0, image.image.naturalWidth, image.image.naturalHeight);
} else {
image.cache(0, 0, image.image.naturalWidth, image.image.naturalHeight);
}
};
example.prototype.prepareCanvas = function() {
this.stage = new createjs.Stage(this.$canvas[0]);
createjs.Ticker.setFPS(60);
createjs.Ticker.addEventListener("tick", this.stage);
this.initCursor();
this.loadImage();
};
/**
* Get container. If not exist, this function create new one
* #param {String} name
* #returns {createjs.Container}
*/
example.prototype.getContainer = function(name) {
if(this.container[name]){
return this.container[name];
}
this.container[name] = new createjs.Container();
this.stage.addChild(this.container[name]);
return this.container[name];
};
example.prototype.loadImage = function() {
var self = this;
var url = "https://upload.wikimedia.org/wikipedia/commons/thumb/a/aa/Logo_Google_2013_Official.svg/1280px-Logo_Google_2013_Official.svg.png";
var background = this.setObject("image.background", new createjs.Shape());
this.getContainer("image").addChild(background);
var image = null;
return utils.image(url).then(function(img){
image = img;
self.getContainer("image").addChild(self.setObject(
"image",
new createjs.Bitmap(img)
));
self.updateCache(false);
return utils.image("http://i.imgur.com/JKaeYwv.png");
}).then(function(imgBackground){
background
.graphics
.beginBitmapFill(imgBackground,'repeat')
.drawRect(0,0, image.naturalWidth, image.naturalHeight);
});
};
utils = {};
utils.image = function(url){
var deferred = Q.defer();
//deferred.resolve(text);
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function(){
deferred.resolve(this);
};
img.onerror = function(){
deferred.reject(arguments);
};
img.src = url;
return deferred.promise;
};
$(function(){
var test = new example();
});
But when i draw something on my canvas, my path of draw showing image behind mask... This is opposed result what i want.
I want remove part of image (like eraser in Photoshop). I don't know what i should do next...
Thanks
You can use compositeOperation in conjunction with layers or caching to "erase" content. For example, if you use updateCache("source-over"), that will draw the current visual content over the existing cache (normal compositing). However, if you use updateCache("destination-out"), that will essentially punch out the current content from the existing cache, which gives you an eraser effect.
Here's a simple example of this in action: http://jsfiddle.net/17xec9y5/4
Related
I am erasing the canvas drawing 1 time then Undo works fine, but when I erase more than 1 time then the Undo work as a line stroke, it works for the last step to erase but other are working as line stroke please see below code:
function Sketchpad(config) {
// Enforces the context for all functions
for (var key in this.constructor.prototype) {
this[key] = this[key].bind(this);
}
// Warn the user if no DOM element was selected
if (!config.hasOwnProperty('element')) {
console.error('SKETCHPAD ERROR: No element selected');
return;
}
this.element = config.element;
// Width can be defined on the HTML or programatically
this._width = config.width || $(this.element).attr('data-width') || 0;
this._height = config.height || $(this.element).attr('data-height') || 0;
// Pen attributes
this.color = config.color || $(this.element).attr('data-color') || '#000000';
this.penSize = config.penSize || $(this.element).attr('data-penSize') || 5;
// ReadOnly sketchpads may not be modified
this.readOnly = config.readOnly ||
$(this.element).attr('data-readOnly') ||
false;
if (!this.readOnly) {
$(this.element).css({cursor: 'crosshair'});
}
// Stroke control variables
this.strokes = config.strokes || [];
console.log(this.strokes)
this._currentStroke = {
color: null,
size: null,
lines: [],
};
// Undo History
this.undoHistory = (!bErasing) ? (config.undoHistory || []) : [];
// Animation function calls
this.animateIds = [];
// Set sketching state
this._sketching = false;
// Setup canvas sketching listeners
this.reset();
}
//
// Private API
//
Sketchpad.prototype._cursorPosition = function(event) {
return {
x: event.pageX - $(this.canvas).offset().left,
y: event.pageY - $(this.canvas).offset().top,
};
};
Sketchpad.prototype._draw = function(start, end, color, size) {
this._stroke(start, end, color, size, 'source-over');
};
Sketchpad.prototype._erase = function(start, end, color, size) {
this._stroke(start, end, color, size, 'destination-out');
};
Sketchpad.prototype._stroke = function(start, end, color, size) {
this.context.save();
if(bErasing){
this.context.globalCompositeOperation = "destination-out";
}else{
this.context.globalCompositeOperation = "source-over";
}
// if(size === 7 || size === 13){
// console.log(size)
// this.context.lineJoin = 'square';
// this.context.lineCap = 'square';
// }
// else{
this.context.lineJoin = 'round';
this.context.lineCap = 'round';
// }
this.context.strokeStyle = color;
this.context.lineWidth = size;
// switch(size){
// case 2:
// this.context.globalAlpha = 1;
// break;
// case 7:
// this.context.globalAlpha = 0.7;
// break;
// case 13:
// this.context.globalAlpha = 0.4;
// break;
// default:
// this.context.globalAlpha = 0.2;
// }
this.context.beginPath();
this.context.moveTo(start.x, start.y);
this.context.lineTo(end.x, end.y);
this.context.closePath();
this.context.stroke();
this.context.restore();
};
//
// Callback Handlers
//
Sketchpad.prototype._mouseDown = function(event) {
this._lastPosition = this._cursorPosition(event);
this._currentStroke.color = this.color;
this._currentStroke.size = this.penSize;
this._currentStroke.lines = [];
// console.log(this._currentStroke.lines)
this._sketching = true;
this.canvas.addEventListener('mousemove', this._mouseMove);
};
Sketchpad.prototype._mouseUp = function(event) {
if (this._sketching) {
this.strokes.push($.extend(true, {}, this._currentStroke));
this._sketching = false;
}
this.canvas.removeEventListener('mousemove', this._mouseMove);
};
Sketchpad.prototype._mouseMove = function(event) {
var currentPosition = this._cursorPosition(event);
this._draw(this._lastPosition, currentPosition, this.color, this.penSize);
this._currentStroke.lines.push({
start: $.extend(true, {}, this._lastPosition),
end: $.extend(true, {}, currentPosition),
});
this._lastPosition = currentPosition;
};
Sketchpad.prototype._touchStart = function(event) {
event.preventDefault();
if (this._sketching) {
return;
}
this._lastPosition = this._cursorPosition(event.changedTouches[0]);
this._currentStroke.color = this.color;
this._currentStroke.size = this.penSize;
this._currentStroke.lines = [];
this._sketching = true;
this.canvas.addEventListener('touchmove', this._touchMove, false);
};
Sketchpad.prototype._touchEnd = function(event) {
event.preventDefault();
if (this._sketching) {
this.strokes.push($.extend(true, {}, this._currentStroke));
this._sketching = false;
}
this.canvas.removeEventListener('touchmove', this._touchMove);
};
Sketchpad.prototype._touchCancel = function(event) {
event.preventDefault();
if (this._sketching) {
this.strokes.push($.extend(true, {}, this._currentStroke));
this._sketching = false;
}
this.canvas.removeEventListener('touchmove', this._touchMove);
};
Sketchpad.prototype._touchLeave = function(event) {
event.preventDefault();
if (this._sketching) {
this.strokes.push($.extend(true, {}, this._currentStroke));
this._sketching = false;
}
this.canvas.removeEventListener('touchmove', this._touchMove);
};
Sketchpad.prototype._touchMove = function(event) {
event.preventDefault();
var currentPosition = this._cursorPosition(event.changedTouches[0]);
this._draw(this._lastPosition, currentPosition, this.color, this.penSize);
this._currentStroke.lines.push({
start: $.extend(true, {}, this._lastPosition),
end: $.extend(true, {}, currentPosition),
});
this._lastPosition = currentPosition;
};
//
// Public API
//
Sketchpad.prototype.reset = function() {
// Set attributes
this.canvas = $(this.element)[0];
this.canvas.width = this._width;
this.canvas.height = this._height;
this.context = this.canvas.getContext('2d');
// Setup event listeners
this.redraw(this.strokes);
if (this.readOnly) {
return;
}
// Mouse
this.canvas.addEventListener('mousedown', this._mouseDown);
this.canvas.addEventListener('mouseout', this._mouseUp);
this.canvas.addEventListener('mouseup', this._mouseUp);
// Touch
this.canvas.addEventListener('touchstart', this._touchStart);
this.canvas.addEventListener('touchend', this._touchEnd);
this.canvas.addEventListener('touchcancel', this._touchCancel);
this.canvas.addEventListener('touchleave', this._touchLeave);
};
Sketchpad.prototype.drawStroke = function(stroke) {
for (var j = 0; j < stroke.lines.length; j++) {
var line = stroke.lines[j];
this._draw(line.start, line.end, stroke.color, stroke.size);
}
};
Sketchpad.prototype.erase = function() {
// this._erase(line.start, line.end, stroke.color, stroke.size);
};
Sketchpad.prototype.redraw = function(strokes) {
for (var i = 0; i < strokes.length; i++) {
this.drawStroke(strokes[i]);
}
};
Sketchpad.prototype.toObject = function() {
return {
width: this.canvas.width,
height: this.canvas.height,
strokes: this.strokes,
undoHistory: this.undoHistory,
};
};
Sketchpad.prototype.toJSON = function() {
return JSON.stringify(this.toObject());
};
Sketchpad.prototype.animate = function(ms, loop, loopDelay) {
this.clear();
var delay = ms;
var callback = null;
for (var i = 0; i < this.strokes.length; i++) {
var stroke = this.strokes[i];
for (var j = 0; j < stroke.lines.length; j++) {
var line = stroke.lines[j];
callback = this._draw.bind(this, line.start, line.end,
stroke.color, stroke.size);
this.animateIds.push(setTimeout(callback, delay));
delay += ms;
}
}
if (loop) {
loopDelay = loopDelay || 0;
callback = this.animate.bind(this, ms, loop, loopDelay);
this.animateIds.push(setTimeout(callback, delay + loopDelay));
}
};
Sketchpad.prototype.cancelAnimation = function() {
for (var i = 0; i < this.animateIds.length; i++) {
clearTimeout(this.animateIds[i]);
}
};
Sketchpad.prototype.clear = function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
};
Sketchpad.prototype.undo = function() {
this.clear();
var stroke = this.strokes.pop();
if (stroke) {
this.undoHistory.push(stroke);
this.redraw(this.strokes);
}
};
Sketchpad.prototype.redo = function() {
var stroke = this.undoHistory.pop();
if (stroke) {
this.strokes.push(stroke);
this.drawStroke(stroke);
}
};
and also having issue while trying the change the texture of brushes according to the pen size.
eraser is working fine and undo is also working fine the only issue is while we erase more than once, then try to undo then last erase is return to real drawing, but other previous works like as the line stroke and display the drawing as per eraser mouse move in canvas.
This is my my function to call above methods:
var x = "#CB7342",
y = 2;
var bErasing = false;
var canvas, canvasWidth, canvasHeight;
var ctx;
var lastPt=null;
var pathsry = [];
var points = [];
var state;
var colour;
// past states
function ySize(size) {
y = size;
sketchpad.penSize = y;
}
var sketchpad;
function undo(){
bErasing = false;
sketchpad.undo();
if($('#erase').hasClass('active')){
bErasing = true;
}
}
function init() {
canvas = document.getElementById('sheet');
ctx = canvas.getContext('2d');
var canvasOffset = $('#sheet').offset();
var parent = canvas.parentNode;
canvas.width = parent.clientWidth;
canvas.height = parent.clientHeight;
// alert(bErasing)
sketchpad = new Sketchpad({
element: '#sheet',
width: canvas.width,
height: canvas.height,
color: null,
penSize: 2,
globalAlpha: 0.1
});
}
$(document).on('click', "#erase", function () {
bErasing = true;
});
I am trying to change this paperscript:
<script type="text/paperscript" canvas="canvas-1">
tool.minDistance = 10;
tool.maxDistance = 45;
var path;
function onMouseDown(event) {
path = new Path();
path.fillColor = new Color({ hue: Math.random() * 360, saturation: 1, brightness: 1 });
path.add(event.point);
}
function onMouseDrag(event) {
var step = event.delta / 2;
step.angle += 90;
var top = event.middlePoint + step;
var bottom = event.middlePoint - step;
path.add(top);
path.insert(0, bottom);
path.smooth();
}
function onMouseUp(event) {
path.add(event.point);
path.closed = true;
path.smooth();
}
</script>
to a stand alone javascript like:
paper.install(window);
window.onload = function() {
paper.setup('myCanvas');
tool.minDistance = 10;
tool.maxDistance = 45;
var path;
function onMouseDown(event) {
path = new Path();
path.fillColor = {
hue: Math.random() * 360,
saturation: 1,
brightness: 1
};
path.add(event.point);
}
function onMouseDrag(event) {
var step = event.delta / 2;
step.angle += 90;
var top = event.middlePoint + step;
var bottom = event.middlePoint - step;
path.add(top);
path.insert(0, bottom);
path.smooth();
}
function onMouseUp(event) {
path.add(event.point);
path.closed = true;
path.smooth();
}
}
it give me an error:
TypeError: undefined is not an object (evaluating 'tool.minDistance =
10')
What is tool here? I understand that I might need to declare it before I can use it. Any idea how to resolve this?
You need to make the global scope as outlined in the documentation :
paper.install(window);
Then get on with global defs. :
window.onload = function() {
// Get a reference to the canvas object
paper.setup('myCanvas');
// In your case create tools
var tool = new Tool();
tool.minDistance = 10;
tool.maxDistance = 45;
Then continue as usual, this will set up your tools.. More can be found here.
Incidentally you've actually already done this correctly for Path(), so the same applies to Tool()
When I use Paper.js directly in javascript I prefer to create paper object this way:
var canvas = document.getElementById('canvas-line');
paper.setup(canvas);
// and then if you want to create some Paper.js object prefix it's name with paper
var myPath = new paper.Path();
If you want to use tool you need to decelerate it with new paper.Tool();
For example if you want to check whether path was clicked:
var tool1 = new paper.Tool();
var handle;
var myPath;
myPath.fullySelected = true;
tool1.onMouseDown = function(event) {
handle = null;
// Do a hit test on path for handles:
var hitResult = myPath.hitTest(event.point, {
handles: true,
fill: true,
stroke: true,
segments: true,
tolerance: 2
});
if (hitResult) {
if (hitResult.type == 'handle-in') {
handle = hitResult.segment.handleIn;
} else if (hitResult.type == 'segment') {
handle = hitResult.segment.point;
} else if (hitResult.type == 'handle-out') {
handle = hitResult.segment.handleOut;
}
}
}
You can find more informations about tools in here http://paperjs.org/reference/tool/
I need to allow user to rotate bitmap features on map with OpenLayers.Control.ModifyFeature or another way as it work for Polygons or other geometry objects, except Point, but only for Point I can set "externalGraphic" with my bitmap. Example of ModifyFeature to rotation as I expected here: ModifyFeature example
When I add Vector with Point geometry and activate ModifyFeature there is no rotation tool showing - only drag-drop. I know what is a point, but I need to have tool for rotate bitmap features. It may be image on any another geometry object, but with custom image.
After long research I found an example in gis.stackexchange.com, and fix it.
Here is a code which works for me:
OpenLayers.Control.RotateGraphicFeature = OpenLayers.Class(OpenLayers.Control.ModifyFeature, {
rotateHandleStyle: null,
initialize: function(layer, options) {
OpenLayers.Control.ModifyFeature.prototype.initialize.apply(this, arguments);
this.mode = OpenLayers.Control.ModifyFeature.ROTATE; // This control can only be used to rotate the feature
this.geometryTypes = ['OpenLayers.Geometry.Point'] // This control can only be used to rotate point because the 'exteralGraphic' is a point style property
var init_style = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style.select);
this.rotateHandleStyle = OpenLayers.Util.extend(init_style, {
externalGraphic: "./static/resources/images/cross.png",
graphicWidth: 12,
graphicHeight: 12,
fillOpacity: 1
});
},
resetVertices: function() {
// You need to set yours renderIntent or use "vertex"
if (this.feature && this.feature.renderIntent == "vertex") {
var vertex = this.feature;
this.feature = this.backup_feature;
this.layer.destroyFeatures([this.radiusHandle], {silent: true});
this.collectRadiusHandle();
return;
}
if (this.dragControl.feature) {
this.dragControl.outFeature(this.dragControl.feature);
}
if (this.vertices.length > 0) {
this.layer.removeFeatures(this.vertices, {silent: true});
this.vertices = [];
}
if (this.virtualVertices.length > 0) {
this.layer.removeFeatures(this.virtualVertices, {silent: true});
this.virtualVertices = [];
}
if (this.dragHandle) {
this.layer.destroyFeatures([this.dragHandle], {silent: true});
this.dragHandle = null;
}
if (this.radiusHandle) {
this.layer.destroyFeatures([this.radiusHandle], {silent: true});
this.radiusHandle = null;
}
if (this.feature && this.feature.geometry &&
this.feature.geometry.CLASS_NAME != "OpenLayers.Geometry.Point") {
if ((this.mode & OpenLayers.Control.ModifyFeature.DRAG)) {
this.collectDragHandle();
}
if ((this.mode & (OpenLayers.Control.ModifyFeature.ROTATE |
OpenLayers.Control.ModifyFeature.RESIZE))) {
this.collectRadiusHandle();
}
if (this.mode & OpenLayers.Control.ModifyFeature.RESHAPE) {
if (!(this.mode & OpenLayers.Control.ModifyFeature.RESIZE)) {
this.collectVertices();
}
}
}
this.collectRadiusHandle();
},
collectRadiusHandle: function() {
var scope = this,
feature = this.feature,
geometry = this.feature.geometry || this.backup_feature.geometry,
centroid = geometry.getCentroid().transform(this.WGS84_google_mercator, this.WGS84),
lon = centroid.x, lat = centroid.y;
if (this.feature.geometry) {
this.backup_feature = this.feature;
} else {
this.feature.geometry = this.backup_feature.geometry;
}
var originGeometry = new OpenLayers.Geometry.Point(lon, lat);
// radius geometry position.
var pixel_dis_x = 10,
pixel_dis_y = -10;
var rotationFeatureGeometry = new OpenLayers.Geometry.Point(lon+pixel_dis_x, lat+pixel_dis_y);
var rotationFeature = new OpenLayers.Feature.Vector(rotationFeatureGeometry, null, this.rotateHandleStyle);
var resize = (this.mode & OpenLayers.Control.ModifyFeature.RESIZE);
var reshape = (this.mode & OpenLayers.Control.ModifyFeature.RESHAPE);
var rotate = (this.mode & OpenLayers.Control.ModifyFeature.ROTATE);
rotationFeatureGeometry.move = function(x, y) {
OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
var dx1 = this.x - originGeometry.x;
var dy1 = this.y - originGeometry.y;
var dx0 = dx1 - x;
var dy0 = dy1 - y;
if (rotate) {
var a0 = Math.atan2(dy0, dx0);
var a1 = Math.atan2(dy1, dx1);
var angle = a1 - a0;
angle *= 180 / Math.PI;
var old_angle = feature.attributes.angle;
var new_angle = old_angle - angle;
feature.attributes.angle = new_angle;
// redraw the feature
scope.feature.layer.redraw.call(scope.feature.layer);
}
};
rotationFeature._sketch = true;
this.radiusHandle = rotationFeature;
this.radiusHandle.renderIntent = this.vertexRenderIntent;
this.layer.addFeatures([this.radiusHandle], {silent: true});
},
CLASS_NAME: "OpenLayers.Control.RotateGraphicFeature"
});
Style of your Vector may be as:
new OpenLayers.StyleMap({
"default": new OpenLayers.Style({
externalGraphic: "link/to/icon",
graphicHeight: "32px",
graphicWidth: "25px",
fillOpacity: 1,
rotation: "${angle}",
graphicZIndex: 1
})
})
UPD: I fixed it for OpenLayers 2.13.1
OpenLayers.Control.RotateGraphicFeature = OpenLayers.Class(OpenLayers.Control.ModifyFeature, {
rotateHandleStyle: null,
initialize: function (layer, options) {
OpenLayers.Control.ModifyFeature.prototype.initialize.apply(this, arguments);
this.mode = OpenLayers.Control.ModifyFeature.ROTATE; // This control can only be used to rotate the feature
this.geometryTypes = ['OpenLayers.Geometry.Point'] // This control can only be used to rotate point because the 'exteralGraphic' is a point style property
var init_style = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style.select);
this.rotateHandleStyle = OpenLayers.Util.extend(init_style, {
externalGraphic: "./static/resources/images/cross.png",
graphicWidth: 12,
graphicHeight: 12,
fillOpacity: 1
});
},
resetVertices: function () {
// You need to set yours renderIntent or use "vertex"
if (this.feature && this.feature.renderIntent == "vertex") {
var vertex = this.feature;
this.feature = this.backup_feature;
if (this.dragControl.feature) {
this.dragControl.outFeature(this.dragControl.feature);
}
this.layer.destroyFeatures([this.radiusHandle], {silent: true});
delete this.radiusHandle;
this.collectRadiusHandle();
return;
}
if (this.vertices.length > 0) {
this.layer.removeFeatures(this.vertices, {silent: true});
this.vertices = [];
}
if (this.virtualVertices.length > 0) {
this.layer.removeFeatures(this.virtualVertices, {silent: true});
this.virtualVertices = [];
}
if (this.dragHandle) {
this.layer.destroyFeatures([this.dragHandle], {silent: true});
this.dragHandle = null;
}
if (this.radiusHandle) {
this.layer.destroyFeatures([this.radiusHandle], {silent: true});
this.radiusHandle = null;
}
if (this.feature && this.feature.geometry &&
this.feature.geometry.CLASS_NAME != "OpenLayers.Geometry.Point") {
if ((this.mode & OpenLayers.Control.ModifyFeature.DRAG)) {
this.collectDragHandle();
}
if ((this.mode & (OpenLayers.Control.ModifyFeature.ROTATE |
OpenLayers.Control.ModifyFeature.RESIZE))) {
this.collectRadiusHandle();
}
if (this.mode & OpenLayers.Control.ModifyFeature.RESHAPE) {
if (!(this.mode & OpenLayers.Control.ModifyFeature.RESIZE)) {
this.collectVertices();
}
}
}
this.collectRadiusHandle();
},
collectRadiusHandle: function () {
var scope = this,
feature = this.feature,
data = feature.attributes,
geometry = this.feature.geometry || this.backup_feature.geometry,
center = this.feature.geometry.bounds.getCenterLonLat();
centroid = geometry.getCentroid().transform(this.WGS84_google_mercator, this.WGS84),
lon = centroid.x, lat = centroid.y;
if (data.type && Tms.settings.roadObjectTypeSettings[data.type].NoAzimuth) {
return;
}
if (this.feature.geometry) {
this.backup_feature = this.feature;
} else {
this.feature.geometry = this.backup_feature.geometry;
}
var originGeometry = new OpenLayers.Geometry.Point(lon, lat);
var center_px = this.map.getPixelFromLonLat(center);
// you can change this two values to get best radius geometry position.
var pixel_dis_x = 20,
pixel_dis_y = 20;
var radius_px = center_px.add(pixel_dis_x, pixel_dis_y);
var rotation_lonlat = this.map.getLonLatFromPixel(radius_px);
var rotationFeatureGeometry = new OpenLayers.Geometry.Point(
rotation_lonlat.lon, rotation_lonlat.lat
);
var rotationFeature = new OpenLayers.Feature.Vector(rotationFeatureGeometry, null, this.rotateHandleStyle);
var resize = (this.mode & OpenLayers.Control.ModifyFeature.RESIZE);
var reshape = (this.mode & OpenLayers.Control.ModifyFeature.RESHAPE);
var rotate = (this.mode & OpenLayers.Control.ModifyFeature.ROTATE);
rotationFeatureGeometry.move = function(x, y) {
OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
var dx1 = this.x - originGeometry.x;
var dy1 = this.y - originGeometry.y;
var dx0 = dx1 - x;
var dy0 = dy1 - y;
if (rotate) {
var a0 = Math.atan2(dy0, dx0);
var a1 = Math.atan2(dy1, dx1);
var angle = a1 - a0;
angle *= 180 / Math.PI;
var old_angle = feature.attributes.angle;
var new_angle = old_angle - angle;
feature.attributes.angle = new_angle;
// redraw the feature
scope.feature.layer.redraw.call(scope.feature.layer);
}
};
rotationFeature._sketch = true;
this.radiusHandle = rotationFeature;
this.radiusHandle.renderIntent = this.vertexRenderIntent;
this.layer.addFeatures([this.radiusHandle], {silent: true});
},
CLASS_NAME: "OpenLayers.Control.RotateGraphicFeature"
});
I want to set a new position of body on BeginContact event but it's still not functional. It's writed in JavaSript with drawing to canvas but it doesn't matter for Box2d. In HTML file in body is only empty canvas, nothing else. Here is my code:
In the beginning of JS file are only declarated some variables.
Vec2 = Box2D.Common.Math.b2Vec2;
BodyDef = Box2D.Dynamics.b2BodyDef;
Body = Box2D.Dynamics.b2Body;
FixtureDef = Box2D.Dynamics.b2FixtureDef;
Fixture = Box2D.Dynamics.b2Fixture;
World = Box2D.Dynamics.b2World;
PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;
DebugDraw = Box2D.Dynamics.b2DebugDraw;
var player;
It's followed by a setup function which is called in the beginning.
function setup()
{
canvas = document.getElementById("collisionCanvas");
context = canvas.getContext('2d');
document.getElementsByTagName('body')[0].style.backgroundColor = "black";
canvas.style.backgroundColor = "white";
canvas.width = 320;
canvas.height = 320;
world = new World(new Vec2(0, 10), false);
//Point of the problem!!!
//setting contact listener
var listener = new Box2D.Dynamics.b2ContactListener;
listener.BeginContact = function(contact)
{
var body1 = contact.GetFixtureA().GetBody();
var body2 = contact.GetFixtureB().GetBody();
if(body1.GetUserData().type == "player")
{
body1.SetPosition({x:5, y:5});
}
else
{
body2.SetPosition({x:5, y:5});
}
}
world.SetContactListener(listener);
var fixDef = new FixtureDef;
fixDef.density = 1.0;
fixDef.friction = 0.5;
fixDef.restitution = 0.2;
var bodyDef = new BodyDef;
//creating ground
bodyDef.type = Body.b2_staticBody;
bodyDef.position.x = convertPixelsToMeters(160);
bodyDef.position.y = convertPixelsToMeters(320-32/2);
bodyDef.userData = {type: "static"};
fixDef.shape = new PolygonShape;
fixDef.shape.SetAsBox(convertPixelsToMeters(canvas.width/2), convertPixelsToMeters(32/2));
world.CreateBody(bodyDef).CreateFixture(fixDef);
//creating player
bodyDef.type = Body.b2_dynamicBody;
bodyDef.fixedRotation = true;
bodyDef.position.x = convertPixelsToMeters(160);
bodyDef.position.y = convertPixelsToMeters(160);
bodyDef.userData = {type: "player"};
fixDef.shape = new PolygonShape;
fixDef.shape.SetAsBox(convertPixelsToMeters(16), convertPixelsToMeters(16));
player = world.CreateBody(bodyDef);
player.CreateFixture(fixDef);
//setup debug draw
var debugDraw = new DebugDraw();
debugDraw.SetSprite(document.getElementById("collisionCanvas").getContext("2d"));
debugDraw.SetDrawScale(32.0);
debugDraw.SetFillAlpha(0.3);
debugDraw.SetLineThickness(1.0);
debugDraw.SetFlags(DebugDraw.e_shapeBit | DebugDraw.e_jointBit);
world.SetDebugDraw(debugDraw);
window.setInterval(update, 1000 / 60);
}
And in the end are only update function, one helping function and that's it.
function update()
{
world.Step(
1 / 60 //frame-rate
, 10 //velocity iterations
, 10 //position iterations
);
world.DrawDebugData();
world.ClearForces();
}
function convertPixelsToMeters(x)
{
return x*0.03125;
}
$(function(){
setup();
})
Important is only the middle code where is BeginContact event where is calling the SetPosition function which doesn't work.
I tried change position in other places, for example on KeyDown event and there it was correct, so it's for me understandable why it doesn't work.
In the b2Contactlistner method we can not change any prperty or position.
You can take any boolean variable and make it true when in beign contact and if change the position of body according to boolean variable.
as in your code.......
var bodyyy;
var boolennn
listener.BeginContact = function(contact)
{
var body1 = contact.GetFixtureA().GetBody();
var body2 = contact.GetFixtureB().GetBody();
if(body1.GetUserData().type == "player")
{
//body1.SetPosition({x:5, y:5});
bodyyy = body1;
booleannn = true;
}
else
{
// body2.SetPosition({x:5, y:5});
bodyyy = body2;
boolennn = true;
}
}
Now In your Update method
if(booleann)
{
bodyyy.SetPosition({x:5, y:5})
}
SORRY I Donot know syntax of java script
not sure what I'm doing wrong here but some select mouse events (drag/drop, onclick and onpress) do not work. onDoubleClick works however. This is what I'm doing.
.js file
var b2Vec2 = Box2D.Common.Math.b2Vec2;
var b2DebugDraw = Box2D.Dynamics.b2DebugDraw;
var b2BodyDef = Box2D.Dynamics.b2BodyDef;
var b2Body = Box2D.Dynamics.b2Body;
var b2FixtureDef = Box2D.Dynamics.b2FixtureDef;
var b2Fixture = Box2D.Dynamics.b2Fixture;
var b2World = Box2D.Dynamics.b2World;
var b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;
var b2CircleShape = Box2D.Collision.Shapes.b2CircleShape;
var b2DebugDraw = Box2D.Dynamics.b2DebugDraw;
var b2AABB = Box2D.Collision.b2AABB;
var b2ContactListener = Box2D.Dynamics.b2ContactListener;
window.onblur = function(){ Ticker.setPaused(true); PAUSED = true; console.log("paused"); }
window.onfocus = function(){ Ticker.setPaused(false); PAUSED = false; console.log("unpaused"); }
var PAUSED = false;
var Type = {
WALL : 1,
BOULDER : 2
};
var CategoryBits = {
WALL : 0x0001,
BOULDER : 0x0002
};
function Boundary(density, restitution, friction, angularDamping, linearDamping, position, size, scale, categoryBits, maskBits, type, world){
var boundaryFixture = new b2FixtureDef;
boundaryFixture.density = density;
boundaryFixture.restitution = restitution;
boundaryFixture.friction = friction;
boundaryFixture.filter.categoryBits = categoryBits;
boundaryFixture.filter.maskBits = maskBits;
boundaryFixture.shape = new b2PolygonShape;
boundaryFixture.shape.SetAsBox(size.length/scale, size.height/scale);
var boundaryBodyDef = new b2BodyDef;
boundaryBodyDef.type = b2Body.b2_staticBody;
boundaryBodyDef.angularDamping = angularDamping;
boundaryBodyDef.linearDamping = linearDamping;
boundaryBodyDef.position.x = position.x/ scale;
boundaryBodyDef.position.y = position.y/scale;
this.boundary = world.CreateBody(boundaryBodyDef);
this.boundary.CreateFixture(boundaryFixture);
this.boundary.SetUserData(this);
this.type = type;
};
function Position(x, y){
this.x = x;
this.y = y;
};
function Size(length, height){
this.length = length;
this.height = height;
};
function Noir(size, scale, step, debug){
this.GRAVITY = new b2Vec2(0, 10/(scale/5));
this.FPS = 30;
this.SCALE = scale;
this.STEP = step;
this.TIMESTEP = 1/this.STEP;
this.DEBUG = debug;
this.LENGTH = size.length;
this.LENGTH_OFFSET = 20;
this.HEIGHT = size.height;
this.HEIGHT_OFFSET = 10;
this.BOUNDARY_WIDTH = 2;
this.VELOCITY_ITERATIONS = 10;
this.POSITION_ITERATIONS = 10;
this.world;
this.contactListener;
this.canvas;
this.debugCanvas;
this.debugDraw;
this.context;
this.debugContext;
this.stage;
this.previousTime = Date.now();
this.game;
};
Noir.prototype.initCanvas = function(){
this.canvas = document.getElementById('canvas');
this.context = canvas.getContext('2d');
this.stage = new Stage(canvas);
this.stage.snapPixelsEnabled = true;
this.stage.mouseEventsEnabled = true;
//this.stage.onDoubleClick = function(event){ console.log("moving.."); }
this.stage.enableMouseOver();
if(this.DEBUG){
this.debugCanvas = document.getElementById('debugCanvas');
this.debugContext = debugCanvas.getContext('2d');
console.log('Debug on');
}
};
Noir.prototype.initDebug = function(){
this.debugDraw = new b2DebugDraw();
this.debugDraw.SetSprite(this.debugContext);
this.debugDraw.SetDrawScale(this.SCALE);
this.debugDraw.SetFillAlpha(0.7);
this.debugDraw.SetLineThickness(1.0);
this.debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
this.world.SetDebugDraw(this.debugDraw);
};
Noir.prototype.setContactListener = function(){
this.contactListener = new b2ContactListener;
this.contactListener.events = this;
this.contactListener.BeginContact = function(contact, manifold){
var bodyAUser = contact.GetFixtureA().GetBody().GetUserData();
var bodyBUser = contact.GetFixtureB().GetBody().GetUserData();
/* console.log(bodyAUser.type + " , " + bodyBUser.type); */
if((bodyAUser.type == Type.BOULDER) && (bodyBUser.type == Type.WALL)){ this.events.boulderWallContact(bodyAUser, bodyBUser); }
else if((bodyAUser.type == Type.WALL) && (bodyBUser.type == Type.BOULDER)){ this.events.boulderWallContact(bodyBUser, bodyAUser); }
}
this.world.SetContactListener(this.contactListener);
};
Noir.prototype.boulderWallContact = function(boulder, wall){ boulder.flagToDestroy(); };
Noir.prototype.initPhysics = function(){
this.lastTimestamp = Date.now();
this.world = new b2World(this.GRAVITY, true);
this.setContactListener();
if(this.DEBUG){ this.initDebug(); console.log('Debug initialized'); }
var floor = new Boundary(1, 1, 0.6, 0.6, 0.6, new Position(-(this.LENGTH_OFFSET/2), (this.HEIGHT+ (this.HEIGHT_OFFSET - (this.HEIGHT_OFFSET - 1)))),
new Size((this.LENGTH + this.LENGTH_OFFSET), this.BOUNDARY_WIDTH), this.SCALE, CategoryBits.WALL, CategoryBits.BOULDER, Type.WALL, this.world);
/* var ceiling = new Boundary(1, 1, 0.6, 0.6, 0.6, new Position(-(this.LENGTH_OFFSET/2), (this.HEIGHT_OFFSET - (this.HEIGHT_OFFSET - 1))),
new Size((this.LENGTH + this.LENGTH_OFFSET), this.BOUNDARY_WIDTH), this.SCALE, CategoryBits.WALL, CategoryBits.BOULDER, Type.WALL, this.world); */
var leftFixture = new Boundary(1,1, 0.6, 0.6, 0.6, new Position(-(this.BOUNDARY_WIDTH - (this.BOUNDARY_WIDTH - 1)), -(this.LENGTH_OFFSET/2)),
new Size(this.BOUNDARY_WIDTH, (this.HEIGHT + this.HEIGHT_OFFSET)), this. SCALE, CategoryBits.WALL, CategoryBits.BOULDER, Type.WALL, this.world);
var rightFixture = new Boundary(1,1, 0.6, 0.6, 0.6, new Position((this.LENGTH + (this.LENGTH_OFFSET - (this.LENGTH_OFFSET - 1))), -(this.LENGTH_OFFSET/2)),
new Size(this.BOUNDARY_WIDTH, (this.HEIGHT+ this.HEIGHT_OFFSET)), this.SCALE, CategoryBits.WALL, CategoryBits.BOULDER, Type.WALL, this.world);
};
Noir.prototype.tick = function(){
this.updatePhysics();
this.stage.update();
};
Noir.prototype.initTicker = function(){
Ticker.setFPS(this.FPS);
Ticker.useRAF = true;
Ticker.addListener(this, true);
};
Noir.prototype.init = function(){
this.initCanvas();
this.initTicker();
this.initPhysics();
this.initGame(this.stage, this.world);
var debug = document.getElementById('debug');
};
Noir.prototype.initOnLoadDocument = function(){
console.log('running');
if(document.loaded){ this.init(); }
else{
if(window.addEventListener){ window.addEventListener('load', this.init(), false); }
else { window.attachEvent('onLoad', this.init); }
}
}
Noir.prototype.updatePhysics = function(){
/* remove flagged objects for destruction */
/* update non-flagged objects */
if(!PAUSED){
this.updateGame();
this.world.Step(this.TIMESTEP, this.VELOCITY_ITERATIONS, this.POSITION_ITERATIONS);
this.world.ClearForces();
if(this.DEBUG){
this.world.m_debugDraw.m_sprite.graphics.clear();
this.world.DrawDebugData();
}
}
};
Noir.prototype.initGame = function(){
this.game = new Game(this.stage, this.SCALE, this.world);
this.game.start();
};
Noir.prototype.updateGame = function(){ this.game.update(); }
function Actor(density, restitution, friction, angularDamping, linearDamping, path, position, size, stage, scale, categoryBits, maskBits, type, world){
this.skin = new Bitmap(path);
this.skin.x = position.x;
this.skin.y = position.y;
this.skin.regX = (size.length/2);
this.skin.regY = (size.height/2);
this.skin.snapToPixel = true;
this.skin.mouseEnabled = false;
stage.addChild(this.skin);
var actorFixture = new b2FixtureDef;
actorFixture.density = density;
actorFixture.restitution = restitution;
actorFixture.friction = friction;
actorFixture.filter.categoryBits = categoryBits;
actorFixture.filter.maskBits = maskBits;
actorFixture.shape = new b2PolygonShape;
actorFixture.shape.SetAsBox((size.length/2)/scale, (size.height/2)/scale);
var actorBodyDef = new b2BodyDef;
actorBodyDef.type = b2Body.b2_dynamicBody;
actorBodyDef.angularDamping = angularDamping;
actorBodyDef.linearDamping = linearDamping;
actorBodyDef.position.x = this.skin.x/scale;
actorBodyDef.position.y = this.skin.y/scale;
this.body = world.CreateBody(actorBodyDef);
this.body.CreateFixture(actorFixture);
this.body.SetUserData(this);
this.type = type;
this.destroy = false;
};
Actor.prototype.flagToDestroy = function(){ this.destroy = true; };
Actor.prototype.remove = function(game){
game.stage.removeChild(this.skin);
game.world.DestroyBody(this.body);
game.actors.splice(game.actors.indexOf(this),1);
};
Actor.prototype.update = function(scale){
this.skin.rotation = this.body.GetAngle() * (180/Math.PI);
this.skin.x = this.body.GetWorldCenter().x * scale;
this.skin.y = this.body.GetWorldCenter().y * scale;
};
function Icon(path, position, size, stage){
this.skin = new Bitmap(path);
this.skin.x = position.x;
this.skin.y = position.y;
this.skin.regX = (size.length/2);
this.skin.regY = (size.height/2);
stage.addChild(this.skin);
//this.skin.onDoubleClick = function(event){ alert("click click"); }
this.skin.onClick = function(event){ alert("click"); }
this.skin.onPress = function(event){ console.log("pressing"); }
};
function Game(stage, scale, world){
this.scale = scale;
this.stage = stage;
this.world = world;
this.boulderSpawnDelayCounter = 0;
this.actors = [];
this.icon;
};
Game.prototype.start = function(){
var position = new Position(400, 200);
var size = new Size(50, 50);
console.log(this);
this.icon = new Icon("images/bird.png", position, size, this.stage);
};
Game.prototype.controlledSpawn = function(stage, scale, world){
var spawnInterval = (50 + Math.round(Math.random() * 10));
this.boulderSpawnDelayCounter++;
if(this.boulderSpawnDelayCounter % spawnInterval === 0){
this.boulderSpawnDelayCounter = 0;
this.boulderSpawn();
}
};
Game.prototype.boulderSpawn = function(stage, scale, world){
var position = new Position((100 + Math.round(Math.random() * 250)), -20);
var size = new Size(50, 50);
this.actors.push(new Actor(0.2, 0.6, 0.3, 0.3, 0.3, "images/bird.png", position, size, this.stage, this.scale, CategoryBits.BOULDER, CategoryBits.WALL, Type.BOULDER, this.world));
};
Game.prototype.update = function(){
this.controlledSpawn();
for(idx = 0; idx < this.actors.length; ++idx){
if(this.actors[idx].destroy == true){ this.actors[idx].remove(this); }}
for(idx = 0; idx < this.actors.length; ++idx){ this.actors[idx].update(this.scale); }
};
.html file
<!doctype html>
<html xmlns:og="http://ogp.me/ns#">
<head>
<meta charset="utf-8">
<title>Noir test</title>
<link href="css/style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<canvas width="500" height="500" id="canvas"></canvas>
<canvas width="500" height="500" id="debugCanvas"></canvas>
<script> var createjs = window </script>
<script type="text/javascript" src="libs/easeljs-0.5.0.min.js"></script>
<script type="text/javascript" src="libs/Box2dWeb-2.1.a.3.min.js"></script>
<script type="text/javascript" src="js/noir.js"></script>
<script> var noir = new Noir(new Size(500, 500), 30, 20, false); noir.initOnLoadDocument()</script>
</body>
</html>
I'm working with this on a local server so the server security issue triggering this similar behaviour for remote servers doesn't apply (I think). Guys, I'm stumped here. Your help will be very much appreciated. Thanks.
Without seeing your CSS, I would guess that your debug canvas is layered overtop of your main canvas. If this is the case, the debug canvas will be the target for any mouse events, preventing your main canvas (and the related Stage) from receiving them.
Due to a bug (recently fixed in the NEXT version), EaselJS subscribes to double click events on the window, instead of on the canvas, which is likely why onDoubleClick is working for you.
Also, it might be worth checking out the newer version of EaselJS. v0.7.0 includes a great new event model, and v0.7.1 will be out shortly with the fix for double click.