PaperJS updated centre not redrawing - javascript

I am using Paper.js to draw a circle on screen.
I update the centre position in update but the screen doesn't display draw the circle with the updated position.
class Ball{
this.graphics = new Path.Circle({
center: [200,200],
radius: 20,
fillColor: 'blue'
});
}
update(){
//test
this.graphics.center = [100,100]
}
}
var ball = new Ball();
//update
view.onFrame = function(event) {
ball.update();
}
The circle is always drawn on 200,200 no matter what values I update this.graphics.centre with.
I have also tried adding view.draw(); in view.onFrame() after ball.update() but it didn't change anything.
I have made sure the rest of the code is working since if I instead create a new Path.Circle() in ball.update() it draws a new circle on the correct position.

Related

Three.js: Add Image to Texture Bottom in 6 Cube Panorama as a Hotspot

I am using this panorama as a base for my project. Now I want to add a small image (circle) to the bottom of one chosen texture as if this is a hotspot on the panorama floor that will respond to user click. Please see the image below with 2 circles on the floor:
I tried the following code to add image to one of 6 textures in panorama:
var loader = new THREE.TextureLoader();
loader.load('img/test-circle-sample.png', function ( texture ) {
var geometry = new THREE.PlaneGeometry( 1, 1 );
var material = new THREE.MeshBasicMaterial( { map : texture, opacity : 1, side : THREE.DoubleSide, transparent : true } );
var sprite = new THREE.Mesh( geometry, material );
scene.add(sprite);
});
While it seems to actually load the image, the circle is far from looking like on the picture above. It is very wide, even though its size is 256 pixels and is positioned around the camera - you can see it on very top, bottom, sides, but not in front of you as a small circle. I played around with these settings but they did not work well:
sprite.position.set(0,-360,0);
sprite.rotateOnAxis( new THREE.Vector3( 1, 0, 0 ), THREE.Math.degToRad(90) );
sprite.scale.set( 1, 1, 1 );
I need help with positioning the image in front of camera for any chosen side (or angle) and keep it stuck to the floor, so dragging camera would adjust how this image looks (skewed effect based on angle).
Update: I created this Plunker but image now not seen at all.
http://plnkr.co/edit/KS6dVMn5AIEaXr143Jv3?p=preview
I am not sure I understand your question - as I understand, you want the hot spot to be placed below the camera (ie at the viewers feet)? If so, it seems you're transforming the hot spot incorrectly, which may be the reason it appears warped.
I took a copy of your live demo at http://plnkr.co/edit/KS6dVMn5AIEaXr143Jv3?p=preview and made some alterations to get the hot spot to display correctly.
Try and update the way you transform and rotate your hot spot, as shown in the following code:
function addHotSpot(scene){
THREE.ImageUtils.crossOrigin = '';
var loader = new THREE.TextureLoader();
loader.load('https://i.imgur.com/vU163P4.png', function ( texture ) {
var geometry = new THREE.PlaneGeometry( 1, 1 );
var material = new THREE.MeshBasicMaterial( {
map:texture,
opacity : 1,
side : THREE.DoubleSide,
transparent : false // Note, I also set this to false.
} );
var sprite = new THREE.Mesh( geometry, material );
// Offset the hotspot so it is below the view origin [Updated]
sprite.position.set(0,-5,5);
// Compute the rotation for the hotspot, 90deg around the x-axis
var rotation = new THREE.Matrix4()
.makeRotationAxis(new THREE.Vector3(1,0,0), 1.57);
// Apply rotation to the hotspot so it "sits flat below the camera"
sprite.rotation.setFromRotationMatrix(rotation);
scene.add(sprite);
});
}

Stroke appears bigger and bigger each time circle icon scale is reduced

I create a new map with zoom equals 4:
map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: new google.maps.LatLng(39.9526, -98.5795),
mapType: 'terrain'
});
I listen for the zoom_changed event so that I can redraw my markers with a new scale:
google.maps.event.addListener(map, 'zoom_changed', function () {
var zoom = map.getZoom();
$log.debug("zoom: " + zoom);
and I create my new icon here:
var greenMarkerIcon = {
path: google.maps.SymbolPath.CIRCLE,
fillOpacity: 1,
fillColor: "green",
strokeWeight: 1,
scale: map.getZoom()
}
When I zoom in, everything looks lovely. The icon grows bigger in scale as I drill down. Zooming out is where the problem is:
Click here for image of icon after reducing scale
The border of the circle becomes bigger and bigger. I've added a debug statement for the icon.strokeWeight property and it remains 1 the entire time. I'm blowing away all of my old markers and redrawing them again, so I don't know why the single marker strokeWeight is appearing bigger.
Any ideas?
I am assuming that you want to change marker icon scale on map zoom and the marker should be smaller/bigger without changing the stroke. Then you need to change only icon scale and set it to the marker:
google.maps.event.addListener(map, 'zoom_changed', function () {
var zoom = map.getZoom();
console.log("zoom: " + zoom);
greenMarkerIcon.scale = (zoom + 1) * scale; // +1 is for avoiding zoom=0, scale is initial scale of icon
marker.setIcon(greenMarkerIcon);
});
check this example: http://jsfiddle.net/dUMFW/108/
The answer provided is correct.
I found out what I was doing wrong. I was creating a new marker each time the user clicked a zoom button. Markers should be created only once and the associated icon should be changed on zoom.
Thanks.

Paper.js eraser tool made using layers and blendMode

I am making simple drawing app using Paper.js and Node.js. There are 2 layers:
- bottom layer with images
- top layer for drawing.
Layer with images is background to drawing layer.
I want to make a simple eraser tool which will erase drawing on a path. I'm trying to do it adding second path in my top layer which has blendMode set to "destination-out".
drawingLayer.activate();
path = new Path();
path.strokeColor = 'black';
path.strokeWidth = 5;
if (mode == "erase") {
path.strokeWidth = 15;
path.blendMode = 'destination-out';
}
My problem is that this "destination-out" path erases not only everything on top layer (drawing layer) but also everything on the bottom layer (images). Of course I want images to stay untouched by eraser. When I set some background in css for my page it is not erased by the eraser path.
Do you know a way to make eraser to modify one top layer while not modyfing bottom layer?
The solution is to activate the layer you want to erase in just before using the eraser tool, like this:
var firstLayer = paper.project.activeLayer; //This one is used to erase
var shapesLayer = new Layer(); // We don't want to erase on this one
so basically, when eraser tool is selected I do
firstLayer.activate();
Then when I want to draw shapes just activate the 'shapesLayer' the same way. This avoids the tool (the one used for erasing) touch anything from 'shapesLayer'
In order to do this, you have to encapsulate your drawings items and your eraser items into a group which has the blend mode source-over.
This way, the background items won't be affected by the eraser items destination-out blend mode.
Here's a simple sketch demonstrating this.
const backgroundCircle = new Path.Circle({
center: view.center,
radius: 50,
fillColor: 'orange'
});
const foregroundCircle = new Path.Circle({
center: view.center + 20,
radius: 50,
fillColor: 'blue'
});
const eraserCircle = new Path.Circle({
center: view.center + [10, 0],
radius: 50,
fillColor: 'black',
blendMode: 'destination-out'
});
const foreground = new Group({
children: [foregroundCircle, eraserCircle],
blendMode:'source-over'
});

In kinetic.js Issue with rotating a kinetic.group

I am using kinetic js. I am adding image, lines, etc to a kinetic.group and trying to rotate the group and it is getting rotated correctly. But after rotating the group, if I try to draw a line it is not correctly drawing on the present mouse position. It is drawing as it was before rotating.
The problem may be that if I rotate the group, the stage co-ordinates are not getting rotated it seems. What should I do to prevent this?
reference code---
var rootGroup = new Kinetic.Group({
x: stage.getWidth()/3,
y: stage.getWidth()/6,
draggable: true,
offset: [images.darthVader.width/2, images.darthVader.height/2]
});
rootGroup.add(line);
rootGroup.setRotationDeg(rootGroup.getRotationDeg()+90);
IN THIS WAY I AM DRAWING THE LINE.
var activeline = new Kinetic.Line({
points: [{x:0,y:0}],
stroke: "blue",
strokeWidth: 3,
lineCap: "round",
lineJoin: "round",
});
var mousePos = stage.getMousePosition();
points.push({
x: mousePos.x,
y: mousePos.y
});
activeline.setPoints(points);
rootGroup.add(activeline);
I'm not familiar with KineticJS, but it seems that you have to reset the transformation matrix back to its default state. OpenGL has the glLoadIdentity() method. Search for a similiar method on KineticJS.
See this tutorial
http://www.html5canvastutorials.com/advanced/html5-canvas-reset-transform-tutorial/
This should get you fairly close: http://jsfiddle.net/k4qB8/24/
// This rotates that added active line along with your group.
// This makes the draw direction correct
activeline.setRotationDeg(0-rootGroup.getRotationDeg());

Dynamic rectangles in Google Maps

First I'm pretty new to Javascript, so sorry if my question comes across poorly.
I'm creating an application in Flash to help users calculate their electrical costs. Then I'm taking this figure and write it to an xml file.
Now I'm looking to open a webpage and show a google map, and there is a rectangle drawn over the map which is generated dynamically from the number generated earlier and stored in the xml file.
I'm completely lost as to places to turn on how to achieve this. I've gotten my map on to my page, and it scales 100% as I want it to, but I can't figure out the dynamic rectangle part at all. Any ideas or pointers in the right direction greatly appreciated.
In this latest version, the XML file
<countries>
<country name="USA" lat="40.0" lng="-100.0" width="30.0"/>
<country name="France" lat="46.6" lng="2.7" width="10"/>
<country name="Germany" lat="51.1" lng="10.1" width="20"/>
</countries>
is loaded as soon as the map tiles finish loading. I could not get the getProjection to be called correctly if I did not wait for tile loading to finish. The docs state that getting the projection needs the map to be initialized, and recommends listening for projection_changed. Both ways work yet I still feel listening to tiles_loaded is safer and if something goes wrong with the xml loading it will get called again if the map is zoomed or panned a noticeable amount.
var map;
var xmlLoaded = false;
function initialize() {
var mapOptions = { center: new google.maps.LatLng(30.0, 0.0), zoom: 2,
mapTypeId: google.maps.MapTypeId.ROADMAP };
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
google.maps.event.addListener(map, 'tilesloaded', loadData);
}
function loadData() {
if(!xmlLoaded) {
$.ajax({
type: "GET",
url: "co2data.xml",
dataType: "xml",
success: function(xml) {
var countries = xml.documentElement.getElementsByTagName("country");
for(var i = 0, country; country = countries[i]; i++) {
var name = country.getAttribute("name");
var lat = parseFloat(country.getAttribute("lat"));
var lng = parseFloat(country.getAttribute("lng"));
var point = map.getProjection().fromLatLngToPoint(new google.maps.LatLng(lat,lng));
// width is really an arbitrary unit, relative to CO2 tonnage.
// equals the side of the drawn square.
// it is measured in google maps points units.
var width = parseFloat(country.getAttribute("width"));
makeCO2Rect(name, point, width);
}
xmlLoaded = true;
}
});
}
}
The rectangle is defined by width in points (the whole world is 256x256 points), so some conversion is needed when assigning their centers to the more conventional LatLng.
function rectParamsToBounds(point, width) {
var ctrX = point.x;
var ctrY = point.y;
var swX = ctrX - (width/2);
var swY = ctrY - (width/2);
var neX = ctrX + (width/2);
var neY = ctrY + (width/2);
return new google.maps.LatLngBounds(
map.getProjection().fromPointToLatLng(new google.maps.Point(swX, swY)),
map.getProjection().fromPointToLatLng(new google.maps.Point(neX, neY)));
}
Finally, a rectangle is created with a country name that goes into a MarkerWithLabel (using v1.1.5 here, you can hotlink to http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerwithlabel/1.1.5/src/markerwithlabel_packed.js though I prefer saving a local copy)
Since dragging a rectangle appears impossible, a marker in its center works as a handle. When it's dragged, the associated rectangle moves with it.
function makeCO2Rect(name, point, width) {
var rect = new google.maps.Rectangle({
map: map,
bounds: rectParamsToBounds(point, width)
});
var marker = new MarkerWithLabel({
map: map,
position: map.getProjection().fromPointToLatLng(new google.maps.Point(point.x, point.y)),
draggable: true,
raiseOnDrag: false,
labelContent: name,
labelAnchor: new google.maps.Point(30, 0),
labelClass: "labels", // the CSS class for the label
labelStyle: {opacity: 1.0}
});
google.maps.event.addListener(marker, 'drag', function(event) {
var newLatLng = event.latLng;
var newPoint = map.getProjection().fromLatLngToPoint(newLatLng);
rect.setBounds(rectParamsToBounds(newPoint, width));
});
}
google.maps.event.addDomListener(window, 'load', initialize);
Styling the labels need to be done both in the .labels CSS class and the constructor, and rectangles have options like stroke color, thickness, opacity, and fill color.
If you just want to place a rectangular shape on the map, you can create a google.maps.Rectangleapi-doc. If you want to create a rectangular label on the map, you may be more interested in the InfoBox Utility Librarywiki-page.

Categories

Resources