Hi,
i have a european raphael map.Now I would like to plot points on
certain cities in the map.i tried by converting latitude n longitude
to plot points in it.But unfortunately it is plotting somewhere
else.is it like we should have world map to plot points??here is my
code.
script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var rsr = Raphael('map', '631', '686');
var attr = {
fill: "#C0C0C0",
stroke: "#666",
"stroke-width": 1,
"stroke-linejoin": "round"
};
var world = {};
world.Portugal = rsr.path("56,0.133-1.32,0.527c-0.661,1.321-0.264,2.906- 0.925,4.228c-0.528,1.057-3.698,5.415-3.434,6.868c0.132,0.526,1.056-0.529,1.584-0.529c0.792-0.132,1.585,0.133,2.377,0c0.396,0,0.792-0.396,1.188-0.264
c2.113,0.527,8.981,5.019,9.906,4.887c0.396,0,4.49-1.981,4.754-2.113C57.876,621.536,58.537,621.536,59.197,621.536L59.197,621.536
z").attr(attr);
world.Spain = rsr.path(" M194.57,552.728c0.924,0.396,1.981,0.63.434,4.754c-,0,0.792,0 c0.661,0.133,1.453,0.133,1.849,0.528c0.66,0.528,0.264,1.717,0.924,2.113v0.132C190.74,552.066,190.476,553.916,194.57,552.728
L194.57,552.728z").attr(attr);
var current = null;
for(var country in world) {
(function (st, country) {
country = country.toLowerCase();
st[0].style.cursor = "pointer";
st[0].onmouseover = function () {
st.animate({fill:"#808080", stroke: "#ccc"}, 500);
};
st[0].onmouseout = function () {
st.animate({fill: "#C0C0C0", stroke: "#666"}, 500);
st.toFront();
R.safari();
};
st[0].onclick = function () {
st.toFront();
st.animate({
fill: '#808080',
transform: 's1.5 '
}, 1000);
};
})(world[country], country);
}
});
var cities = {};//here i define the cities with lat n long but both draws in thesame point all time
cities.rome = plot(55.70466,13.19101,1);
cities.copenhagen = plot(55.676097,12.568337,1);
var city_attr = {
fill:"#FF7F50",
stroke:"#666",
opacity: .3
};
function plot(lat,lon,size) {
size = size * .5 + 4;
return rsr.circle(lon2x(lon),lat2y(lat),size).attr(city_attr);
}
function lon2x(lon) {
var xfactor = 1.5255;
var xoffset = 263.58;
var x = (lon * xfactor) + xoffset;
return x; } function lat2y(lat) {
var yfactor = -1.5255;
var yoffset = 130.5;
var y = (lat * yfactor) + yoffset;
return y; }
});
var myMarker = rsr.ellipse(513.859,35.333, 7, 7).attr({
stroke: "none",
opacity: .7,
fill: "#f00"
});
The coordinates in which the map is coded seem rather arbitrary. If that is so, there is no [easy] way to determine the mapping automatically. I would suggest taking a bounding box of the vector image in it's own coordinate system and a corresponding bounding box in lat/long coordinates on a regular map and deriving the mapping from that, at least as a first approximation.
Related
I am trying to display percentage value inside doughnut chart. To my feature work properly i need to have access to chart instance inside callback. I don't know how to do that?
I handled that using Chart.pluginService beforeDraw event but it doesn't work as I expected.
Is there any way to move code from beforeDraw event inside tooltip callback ?
This is my code
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
var precentage = dataFromDoughnutChart;
localStorage.setItem("per", precentage.toString());
return precentage + "%";
}
}
}
Chart.pluginService.register({
beforeDraw: function (chart) {
var value = "";
var x = localStorage.getItem("per");
if (x != null)
value = x + "%";
var width = chart.chart.width,
height = chart.chart.height,
ctx = chart.chart.ctx;
ctx.restore();
var fontSize = (height / 100).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";
var text = value,
textX = Math.round((width - ctx.measureText(text).width) / 2),
textY = height / 2;
ctx.fillText(text, textX, textY);
ctx.save();
},
afterEvent: function (chart, event) {
if (event.type == "mouseout") {
localStorage.removeItem("per");
}
}
});
I think the best approach to solving your problem is to actually use custom tooltips instead of attempting a plugin. Here is a working solution that I modified from one of the chart.js sample pages in their repo.
First define a container for the custom tooltip in yout HTML.
<div id="chartjs-tooltip"></div>
Then use the below custom tooltip function. You might have to tweak the centerX calculation for your needs. This function basically calculates the percentage value of the currently active slice (by dividing the datapoint by the total value of datapoints), places it in the custom tooltip div, and positions the div in the center of the doughnut.
Chart.defaults.global.tooltips.custom = function(tooltip) {
// Tooltip Element
var tooltipEl = document.getElementById('chartjs-tooltip');
// Hide if no tooltip
if (tooltip.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
// Set Text
if (tooltip.body) {
var total = 0;
// get the value of the datapoint
var value = this._data.datasets[tooltip.dataPoints[0].datasetIndex].data[tooltip.dataPoints[0].index].toLocaleString();
// calculate value of all datapoints
this._data.datasets[tooltip.dataPoints[0].datasetIndex].data.forEach(function(e) {
total += e;
});
// calculate percentage and set tooltip value
tooltipEl.innerHTML = '<h1>' + (value / total * 100) + '%</h1>';
}
// calculate position of tooltip
var centerX = (this._chartInstance.chartArea.left + this._chartInstance.chartArea.right) / 2;
var centerY = ((this._chartInstance.chartArea.top + this._chartInstance.chartArea.bottom) / 2);
// Display, position, and set styles for font
tooltipEl.style.opacity = 1;
tooltipEl.style.left = centerX + 'px';
tooltipEl.style.top = centerY + 'px';
tooltipEl.style.fontFamily = tooltip._fontFamily;
tooltipEl.style.fontSize = tooltip.fontSize;
tooltipEl.style.fontStyle = tooltip._fontStyle;
tooltipEl.style.padding = tooltip.yPadding + 'px ' + tooltip.xPadding + 'px';
};
Here is the full end-to-end working example via codepen:
Chart.js Doughnut Center Percentage
I have been trying to create a custom brush paint with an image file using fabric JS . I have tried using the fabric.PatternBrush but this is not the exact thing that I was looking for because this creates a background pattern kind of paint and what I am trying to do is repeat the image wherever the mouse is dragged.
Can anyone please direct me towards the right way? It will be fine for me to switch to any other drawing library that does what I am looking for.
I found a solution to this problem. We can create a custom brush using fabric.BaseBrush as follows:
fabric.SprayBrush = fabric.util.createClass(fabric.BaseBrush, {
opacity: .2,
width: 30,
_baseWidth: 5,
_drips: [],
_dripThreshold: 15,
_inkAmount: 0,
_interval: 20,
_lastPoint: null,
_point: null,
_strokeId: 0,
brush: null,
brushCol : '/static/img/creation_room/textures/texture2.png',
initialize: function(canvas, opt) {
var context = this;
opt = opt || {};
this.canvas = canvas;
this.width = opt.width || canvas.freeDrawingBrush.width;
this.opacity = opt.opacity || canvas.contextTop.globalAlpha;
this.color = opt.color || canvas.freeDrawingBrush.color;
this.canvas.contextTop.lineJoin = "round";
this.canvas.contextTop.lineCap = "round";
this._reset();
fabric.Image.fromURL(this.brushCol, function(brush) {
console.log(brush);
context.brush = brush;
context.brush.filters = [];
context.changeColor(context.color || this.color);
}, { crossOrigin: "anonymous" });
},
changeColor: function(color) {
this.color = color;
this.brush.filters[0] = new fabric.Image.filters.Tint({ color: color });
this.brush.applyFilters(this.canvas.renderAll.bind(this.canvas));
},
changeOpacity: function(value) {
this.opacity = value;
this.canvas.contextTop.globalAlpha = value;
},
onMouseDown: function(pointer) {
this._point = new fabric.Point(pointer.x, pointer.y);
this._lastPoint = this._point;
this.size = this.width + this._baseWidth;
this._strokeId = +new Date();
this._inkAmount = 0;
this.changeColor(this.color);
this._render();
},
onMouseMove: function(pointer) {
this._lastPoint = this._point;
this._point = new fabric.Point(pointer.x, pointer.y);
},
onMouseUp: function(pointer) {
},
_render: function() {
var context = this;
setTimeout(draw, this._interval);
function draw() {
var point, distance, angle, amount, x, y;
point = new fabric.Point(context._point.x || 0, context._point.y || 0);
distance = point.distanceFrom(context._lastPoint);
angle = point.angleBetween(context._lastPoint);
amount = (100 / context.size) / (Math.pow(distance, 2) + 1);
context._inkAmount += amount;
context._inkAmount = Math.max(context._inkAmount - distance / 10, 0);
if (context._inkAmount > context._dripThreshold) {
context._drips.push(new fabric.Drip(context.canvas.contextTop, point, context._inkAmount / 2, context.color, context._strokeId));
context._inkAmount = 0;
}
x = context._lastPoint.x + Math.sin(angle) - context.size / 2;
y = context._lastPoint.y + Math.cos(angle) - context.size / 2;
context.canvas.contextTop.drawImage(context.brush._element, x, y, context.size, context.size);
if (context.canvas._isCurrentlyDrawing) {
setTimeout(draw, context._interval);
} else {
context._reset();
}
}
},
_reset: function() {
this._drips.length = 0;
this._point = null;
this._lastPoint = null;
}
});
Now, we just need to use this brush in the canvas.
var canvas = new fabric.Canvas('canvas');
canvas.freeDrawingBrush = new fabric.SprayBrush(canvas, { width: 70,opacity: 0.6, color: "transparent" });
I am building a site which requires a physics engine.
Having worked with a number of SPA apps i feel pretty confident with.
Unfortunately I am having trouble applying collision detection & walls to a physics simulation that famous has created.
You can see the editable example here.
https://staging.famous.org/examples/index.html?block=gravity3d&detail=false&header=false
What I would like to know is it possible to add collisions to the particles? I have tried this but it appears the collisions are not setup correctly. I was hoping someone has managed to do it successfully.
Thanks!
var FamousEngine = famous.core.FamousEngine;
var Camera = famous.components.Camera;
var DOMElement = famous.domRenderables.DOMElement;
var Gravity3D = famous.physics.Gravity3D;
var Gravity1D = famous.physics.Gravity1D;
var MountPoint = famous.components.MountPoint;
var PhysicsEngine = famous.physics.PhysicsEngine;
var Physics = famous.physics;
var Wall = famous.physics.Wall;
var Position = famous.components.Position;
var Size = famous.components.Size;
var Sphere = famous.physics.Sphere;
var Vec3 = famous.math.Vec3;
var Collision = famous.physics.Collision;
function Demo() {
this.scene = FamousEngine.createScene('#socialInteractive');
this.camera = new Camera(this.scene);
this.camera.setDepth(1000);
this.simulation = new PhysicsEngine();
this.items = [];
this.collision = new Collision();
var Wall = famous.physics.Wall;
var rightWall = new Wall({
direction: Wall.LEFT
}); // bodies coming from the left will collide with the wall
rightWall.setPosition(1000, 0, 0);
var ceiling = new Wall({
normal: [0, 1, 0],
distance: 300,
restitution: 0
});
var floor = new Wall({
normal: [0, -1, 0],
distance: 300,
restitution: 0
});
var left = new Wall({
normal: [1, 0, 0],
distance: 350,
restitution: 0
});
var right = new Wall({
normal: [-1, 0, 0],
distance: 350,
restitution: 0
});
var node = this.scene.addChild();
var position = new Position(node);
// this.simulation.attach([right, left, floor, ceiling])
// this.items.push([ceiling,position]);
for (var i = 0; i < 10; i++) {
var node = this.scene.addChild();
var size = new Size(node).setMode(1, 1);
var position = new Position(node);
if (i === 0) {
createLogo.call(this, node, size, position);
}
if (i !== 0) {
node.id = i;
createSatellites.call(this, node, size, position);
}
}
FamousEngine.requestUpdateOnNextTick(this);
console.log(this.collision)
for (var i = 0; i < this.collision.length; i++) {
this.simulation.attach(collision, balls, balls[i]);
}
this.simulation.addConstraint(this.collision);
}
Demo.prototype.onUpdate = function(time) {
this.simulation.update(time);
this.collision.update(time, 60);
if (this.items.length > 0) {
for (var i = 0; i < this.items.length; i++) {
var itemPosition = this.simulation.getTransform(this.items[i][0]).position;
this.items[i][1].set(itemPosition[0], itemPosition[1], 0);
}
}
FamousEngine.requestUpdateOnNextTick(this);
};
function createLogo(node, size, position) {
size.setAbsolute(50, 50);
var mp = new MountPoint(node).set(0.5, 0.5);
var el = new DOMElement(node, {
tagName: 'img',
attributes: {
src: './images/famous-logo.svg'
}
});
var sphere = new Sphere({
radius: 100,
mass: 10000,
restrictions: ['xy'],
position: new Vec3(window.innerWidth / 2, window.innerHeight / 2, 5)
});
this.gravity = new Gravity3D(sphere);
this.simulation.add(sphere, this.gravity);
this.items.push([sphere, position]);
}
function createSatellites(node, size, position, i) {
size.setAbsolute(20, 20);
var radius = 200;
var x = Math.floor(Math.random() * radius * 2) - radius;
var y = (Math.round(Math.random()) * 2 - 1) * Math.sqrt(radius * radius - x * x);
var color = 'rgb(' + Math.abs(x) + ',' + Math.abs(Math.round(y)) + ',' + (255 - node.id) + ')';
var el = new DOMElement(node, {
properties: {
'background-color': color,
'border-radius': '50%'
}
});
var satellite = new Sphere({
radius: 20,
mass: 5,
position: new Vec3(x + window.innerWidth / 2, y + window.innerHeight / 2, 0)
});
satellite.setVelocity(-y / Math.PI, -x / Math.PI / 2, y / 2);
this.gravity.addTarget(satellite);
this.simulation.add(satellite);
this.items.push([satellite, position]);
this.collision.addTarget(satellite);
}
// Boilerplate
FamousEngine.init();
// App Code
var demo = new Demo();
Thanks for your help Talves, I think i found a solution that works with physics Spring instead of gravity3d. This also has the 4 walls included which seems to work well.
var famous = famous;
var FamousEngine = famous.core.FamousEngine;
var Camera = famous.components.Camera;
var DOMElement = famous.domRenderables.DOMElement;
var Gravity3D = famous.physics.Gravity3D;
var MountPoint = famous.components.MountPoint;
var PhysicsEngine = famous.physics.PhysicsEngine;
var Position = famous.components.Position;
var Size = famous.components.Size;
var Wall = famous.physics.Wall;
var Sphere = famous.physics.Sphere;
var Vec3 = famous.math.Vec3;
var math = famous.math;
var physics = famous.physics;
var collision = famous.physics.Collision;
var gestures = famous.components.GestureHandler;
var Spring = famous.physics.Spring;
console.log(famous)
var anchor = new Vec3(window.innerWidth / 2, window.innerHeight / 2, 0);
//Create Walls
var rightWall = new Wall({
direction: Wall.LEFT
}).setPosition(window.innerWidth - 20, 0, 0);
var leftWall = new Wall({
direction: Wall.RIGHT
}).setPosition(window.innerWidth + 20, 0, 0);
var topWall = new Wall({
direction: Wall.DOWN
}).setPosition(0, 20, 0);
var bottomWall = new Wall({
direction: Wall.UP
}).setPosition(0, window.innerHeight - 20, 0);
function Demo() {
this.scene = FamousEngine.createScene('body');
this.camera = new Camera(this.scene);
this.camera.setDepth(1000);
this.collision = new collision([rightWall, leftWall, topWall, bottomWall]);
this.simulation = new PhysicsEngine();
this.simulation.setOrigin(0.5, 0.5);
this.simulation.addConstraint(this.collision);
this.items = [];
this.walls = [];
//Create Items
for (var i = 0; i < 30; i++) {
var node = this.scene.addChild();
node.setMountPoint(0.5, 0.5);
var size = new Size(node).setMode(1, 1);
var position = new Position(node);
if (i === 0) {
createLogo.call(this, node, size, position);
}
if (i !== 0) {
node.id = i;
createSatellites.call(this, node, size, position);
}
}
//Create Walls
var node = this.scene.addChild();
createWalls(node);
FamousEngine.requestUpdateOnNextTick(this);
Demo.prototype.onUpdate = function(time) {
this.simulation.update(time);
//Postition walls
var wallPosition = topWall.getPosition();
node.setPosition(wallPosition.x, wallPosition.y);
//Position elements
if (this.items.length > 0) {
for (var i = 0; i < this.items.length; i++) {
var itemPosition = this.simulation.getTransform(this.items[i][0]).position;
this.items[i][1].set(itemPosition[0], itemPosition[1], 0);
}
}
FamousEngine.requestUpdateOnNextTick(this);
};
}
function createWalls(wallNode) {
wallNode.setSizeMode('absolute', 'absolute', 'absolute').setAbsoluteSize(window.innerWidth, 10, 0);
var wallDOMElement = new DOMElement(wallNode, {
tagName: 'div'
}).setProperty('background-color', 'lightblue');
}
function createLogo(node, size, position) {
size.setAbsolute(50, 50);
var mp = new MountPoint(node).set(0.5, 0.5);
var el = new DOMElement(node, {
tagName: 'img',
attributes: {
src: './images/famous_logo.png'
}
});
var sphere = new Sphere({
radius: 100,
mass: 10000,
restrictions: ['xy'],
position: new Vec3(window.innerWidth / 2, window.innerHeight / 2, 5)
});
// this.gravity = new Gravity3D(sphere);
// this.simulation.add(sphere, this.gravity);
this.simulation.add(sphere);
this.items.push([sphere, position]);
}
function createSatellites(node, size, position, i) {
size.setAbsolute(50, 50);
var radius = 100;
var x = Math.floor(Math.random() * radius * 2) - radius;
var y = (Math.round(Math.random()) * 2 - 1) * Math.sqrt(radius * radius - x * x);
var color = 'rgb(' + Math.abs(x) + ',' + Math.abs(Math.round(y)) + ',' + (255 - node.id) + ')';
var el = new DOMElement(node, {
properties: {
'background-color': color,
'border-radius': '50%'
}
});
var satellite = new Sphere({
radius: 25,
mass: 10,
position: new Vec3(x + window.innerWidth / 2, y + window.innerHeight / 2, 0)
});
// Attach the box to the anchor with a `Spring` force
var spring = new Spring(null, satellite, {
stiffness: 95,
period: 0.6,
dampingRatio: 1.0,
anchor: anchor
});
//console.log(color);
// satellite.setVelocity(-y / Math.PI, -x / Math.PI / 2, y / 2);
satellite.setVelocity(0.5, 0.5, 0);
// this.gravity.addTarget(satellite);
this.simulation.add(satellite, spring);
this.items.push([satellite, position]);
this.collision.addTarget(satellite);
}
// Boilerplate
FamousEngine.init();
// App Code
var demo = new Demo();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Famous :: Seed Project</title>
<link rel="icon" href="favicon.ico?v=1" type="image/x-icon">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html, body {
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
}
body {
position: absolute;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
-webkit-perspective: 0;
perspective: none;
overflow: hidden;
}
</style>
</head>
<body>
<script src="http://code.famo.us/famous/0.6.2/famous.min.js"></script>
</body>
</html>
So I tried to use translate and call the drag event on the set when certain elements in the set have the drag event intiated on them. But it's a little slow. Does anyone know how to optimize to make it faster?
Here's the function im using
function dragsymbolsoncanvas(foo){//foo is the set passed.
function dragger(){
this.dx = this.dy = 0;
};
function mover(s){
return function(dx, dy){
(s||this).translate(dx-this.dx,dy-this.dy);
this.dx = dx;
this.dy = dy;
}
};
foo.forEach(function(herp){//set.forEach function from raphaeljs
if(herp.data("candrag")=="true"){
foo.drag(mover(foo), dragger);
}
});
};
Is there a way to make this faster without drawing an invisible element over the pieces that I want to make draggable and attaching the handlers to those?
var position;
var rect = paper.rect(20, 20, 40, 40).attr({
cursor: "move",
fill: "#f00",
stroke: "#000"
});
t = paper.text(70,70, 'test').attr({
"font-size":16,
"font-family":
"Arial, Helvetica, sans-serif"
});
var st = paper.set();
st.push(rect, t);
rect.mySet = st;
rect.drag(onMove, onStart, onEnd);
onStart = function () {
positions = new Array();
this.mySet.forEach(function(e) {
var ox = e.attr("x");
var oy = e.attr("y");
positions.push([e, ox, oy]);
});
}
onMove = function (dx, dy) {
for (var i = 0; i < positions.length; i++) {//you can use foreach but I want to show that is a simple array
positions[i][0].attr({x: positions[i][1] + dx, y: positions[i][2] + dy});
}
}
onEnd = function() {}
. I am very new to raphael.js.I have done a europe map using t.I'm
able to change color while mouseover.But I just want to zoom the
particular country while t s clicked.It must be like zoom t the
clicked country with some specific points n the country
script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var rsr = Raphael('map', '631', '686');
var attr = {
fill: "#C0C0C0",
stroke: "#666",
"stroke-width": 1,
"stroke-linejoin": "round"
};
var world = {};
world.Portugal = rsr.path("56,0.133-1.32,0.527c-0.661,1.321-0.264,2.906-0.925,4.228c-0.528,1.057-3.698,5.415-3.434,6.868
c0.132,0.526,1.056-0.529,1.584-0.529c0.792-0.132,1.585,0.133,2.377,0c0.396,0,0.792-0.396,1.188-0.264
c2.113,0.527,8.981,5.019,9.906,4.887c0.396,0,4.49-1.981,4.754-2.113C57.876,621.536,58.537,621.536,59.197,621.536L59.197,621.536
z").attr(attr);;
world.Spain = rsr.path(" M194.57,552.728c0.924,0.396,1.981,0.63.434,4.754c-,0,0.792,0
c0.661,0.133,1.453,0.133,1.849,0.528c0.66,0.528,0.264,1.717,0.924,2.113v0.132C190.74,552.066,190.476,553.916,194.57,552.728
L194.57,552.728z").attr(attr);
var current = null;
for(var country in world) {
(function (st, country) {
country = country.toLowerCase();
st[0].style.cursor = "pointer";
st[0].onmouseover = function () {
st.animate({fill:"#808080", stroke: "#ccc"}, 500);
};
st[0].onmouseout = function () {
st.animate({fill: "#C0C0C0", stroke: "#666"}, 500);
st.toFront();
R.safari();
};
st[0].onclick = function () {
st.animate({width: "500px"}, 'slow');//THS DOES NOT WORk
};
})(world[country], country);
}
});
can anyone help me how to do ths???please
..
You are trying to set the 'width' attribute which the path, in fact, does not possess. The way to go is to set the 'transform' attribute as here. You might also have to set the scaling origin, since the path you are scaling is not centered at zero (cf. Raphael center of scale in transform method).