Drawing a diffrent node shape on dracula graph? - javascript

am very new to raphael js so and kind of in a hurry to find how how i can draw a poly shape with dracula graph. This will have to go in a costum renderer such as:
var render = function(r, n) {
/* the Raphael set is obligatory, containing all you want to display */
var set = r.set().push(
/* custom objects go here */
r.rect(n.point[0]-30, n.point[1]-13, 62, 86)
.attr({"fill": "#fa8", "stroke-width": 2, r : "9px"}))
.push(r.text(n.point[0], n.point[1] + 30, n.label)
.attr({"font-size":"20px"}));
/* custom tooltip attached to the set */
set.items.forEach(
function(el) {
el.tooltip(r.set().push(r.rect(0, 0, 30, 30)
.attr({"fill": "#fec", "stroke-width": 1, r : "9px"})))});
return set;
};
If anybody has dealt with such would love the help.

This solved! Found it on Raphael js by chris wilson
var paper = Raphael(0, 0, 500, 500);
function NGon(x, y, N, side, angle) {
paper.circle(x, y, 3).attr("fill", "black");
var path = "",
c, temp_x, temp_y, theta;
for (c = 0; c <= N; c += 1) {
theta = (c + 0.5) / N * 2 * Math.PI;
temp_x = x + Math.cos(theta) * side;
temp_y = y + Math.sin(theta) * side;
path += (c === 0 ? "M" : "L") + temp_x + "," + temp_y;
}
return path;
}
paper.path(NGon(050, 50, 8, 40));

Related

Is it possible to make canvas with background with lines or canvas that isn't a rectangle?

I'm trying to make this one https://massmoca.org/event/walldrawing340/
in Javascript code, using p5.js, but I have no clue how to fill these shapes with lines. Is there any other possibility, like making canvas that is circle or something like that, or I just have to make each shape seperately?
For now I was doing shape by shape, but making triangle and trapezoid is rough...
var sketch = function (p) {
with(p) {
let h,
w,
space;
p.setup = function() {
createCanvas(900, 400);
h = height / 2;
w = width / 3;
space = 10;
noLoop();
};
p.draw = function() {
drawBackground('red', 'blue', 0, 0);
shape('Circle', 'red', 'blue', 0, 0);
drawBackground('yellow', 'red', w, 0);
shape('Square', 'yellow', 'red', w, 0);
drawBackground('blue', 'yellow', 2 * w, 0);
shape('Triangle', 'blue', 'red', 2 * w, 0)
drawBackground('red', 'yellow', 0, h);
shape('Rectangle', 'red', 'blue', 0, h)
drawBackground('yellow', 'blue', w, h);
shape('Trapezoid', 'yellow', 'red', w, h);
drawBackground('blue', 'red', 2 * w, h);
};
function drawBackground(bColor, lColor, x, y) {
fill(bColor)
noStroke();
rect(x, y, w, h)
stroke(lColor);
strokeWeight(1);
for (let i = 0; i < h / space; i++) {
line(0 + x, i * space + y + 10, w + x, i * space + y + 10);
}
}
function shape(shape, bColor, lColor, x, y) {
fill(bColor)
noStroke();
let w1;
switch (shape) {
case 'Circle':
circle(x + w / 2, y + h / 2, h - space * 6);
stroke(lColor);
strokeWeight(1);
for (let i = 0; i < w / space; i++) {
for (let j = 0; j < h; j++) {
pX = i * space + x;
pY = 0 + y + j;
if (pow(x + w / 2 - pX, 2)
+ pow(pY - (y + h / 2), 2) <= pow(h - space * 6 * 2 - 10, 2)) {
point(pX, pY);
}
}
}
break;
case 'Square':
w1 = w - (h - space * 6);
rect(x + w1 / 2, y + space * 3, h - space * 6, h - space * 6);
stroke(lColor);
strokeWeight(1);
for (let i = 0; i < 15; i++) {
for (let j = 0; j < h - space * 6; j++) {
point(x + w1 / 2 + i * space, y + space * 3 + j)
}
}
break;
case 'Triangle':
w1 = w - (h - space * 6);
triangle(x + w1 / 2, h - space * 3 + y, x + w / 2, y + space * 3, x + w1 / 2 + h - space * 6, h - space * 3 + y)
for (let i = 0; i < w / space; i++) {
for (let j = 0; j < h; j++) {
pX = i * space + x;
pY = 0 + y + j;
if (pow(x + w / 2 - pX, 2)
+ pow(pY - (y + h / 2), 2) <= pow(h - space * 6 * 2 - 10, 2)) {
point(pX, pY);
}
}
}
break;
case 'Rectangle':
w1 = w - (h - space * 6) / 2;
rect(x + w1 / 2, y + space * 3, (h - space * 6) / 2, h - space * 6)
break;
case 'Trapezoid':
w1 = w - (h - space * 6);
quad(x + w1 / 2, h - space * 3 + y, x + w1 / 2 + (h - space * 6) / 4, y + space * 3, x + w1 / 4 + h - space * 6, y + space * 3, x + w1 / 2 + h - space * 6, h - space * 3 + y)
break;
case 'Parallelogram':
w1 = w - (h - space * 6);
quad(x + w1 / 4, h - space * 3 + y, x + w1 / 2, y + space * 3, x + w1 / 2 + h - space * 6, y + space * 3, x + w1 / 4 + h - space * 6, h - space * 3 + y)
break;
break;
}
}
}
};
let node = document.createElement('div');
window.document.getElementById('p5-container').appendChild(node);
new p5(sketch, node);
body {
background-color:#efefef;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
<div id="p5-container"></div>
No messages, everything is working, I just want to know if I have to do so much arduous job...
If you don't need actual line coordinates (for plotting for example), I'd just make most out of createGraphics() to easily render shapes and lines into (taking advantage of the fact that get() returns a p5.Image) and p5.Image's mask() function.
Here's a basic example:
function setup() {
createCanvas(600, 300);
let w = 300;
let h = 150;
let spacing = 12;
let strokeWidth = 1;
const BLUE = color('#005398');
const YELLOW = color('#f9db44');
const RED = color('#dc1215');
bg = getLinesRect(w, h, RED, BLUE, spacing, strokeWidth, true);
fg = getLinesRect(w, h, RED, YELLOW, spacing, strokeWidth, false);
mask = getCircleMask(w, h, w * 0.5, h * 0.5, 100, 0);
image(bg, 0, 0);
image(fg, w, 0);
// render opaque mask (for visualisation only), mask() requires alpha channel
image(getCircleMask(w, h, w * 0.5, h * 0.5, 100, 255),0, h);
// apply mask
fg.mask(mask);
// render bg + masked fg
image(bg, w, h);
image(fg, w, h);
// text labels
noStroke();
fill(255);
text("bg layer", 9, 12);
text("fg layer", w + 9, 12);
text("mask", 9, h + 12);
text("bg + masked fg", w + 9, h + 12);
}
function getLinesRect(w, h, bg, fg, spacing, strokeWidth, isHorizontal){
let rect = createGraphics(w, h);
rect.background(bg);
rect.stroke(fg);
rect.strokeWeight(strokeWidth);
if(isHorizontal){
for(let y = 0 ; y < h; y += spacing){
rect.line(0, y + strokeWidth, w, y + strokeWidth);
}
}else{
for(let x = 0 ; x < w; x += spacing){
rect.line(x + strokeWidth, 0, x + strokeWidth, h);
}
}
// convert from p5.Graphics to p5.Image
return rect.get();
}
function getCircleMask(w, h, cx, cy, cs, opacity){
let mask = createGraphics(w, h);
// make background transparent (alpha is used for masking)
mask.background(0, opacity);
mask.noStroke();
mask.fill(255);
mask.circle(cx, cy, cs);
// convert p5.Graphics to p5.Image
return mask.get();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>
You can apply the same logic for the rest of the shapes:
function setup() {
createCanvas(1620, 590);
let compWidth = 500;
let compHeight = 250;
let compSpacing= 30;
let lineWeight = 1.5;
let lineSpacing = 12;
const BLUE = color('#005398');
const YELLOW = color('#f9db44');
const RED = color('#dc1215');
// yellow square
circleMask = getCircleMask(compWidth, compHeight, compWidth * 0.5, compHeight * 0.5, 210);
redCircle = getComposition(compWidth, compHeight, RED,
BLUE,
YELLOW,
lineSpacing, lineWeight, circleMask);
// red box
boxMask = getRectMask(compWidth, compHeight, (compWidth - 100) * 0.5, 20, 100, 210);
redBox = getComposition(compWidth, compHeight, RED,
YELLOW,
BLUE,
lineSpacing, lineWeight, boxMask);
// yellow square
squareMask = getRectMask(compWidth, compHeight, 144, 20, 210, 210);
yellowSquare = getComposition(compWidth, compHeight, YELLOW,
RED,
BLUE,
lineSpacing, lineWeight, squareMask);
// yellow trapeze
trapezeMask = getQuadMask(compWidth, compHeight, 200, 25, 200 + 115, 25,
150 + 220, 220, 150, 220);
yellowTrapeze = getComposition(compWidth, compHeight, YELLOW,
BLUE,
RED,
lineSpacing, lineWeight, trapezeMask);
// blue triangle
triangleMask = getTriangleMask(compWidth, compHeight, compWidth * 0.5, 25,
150 + 220, 220, 150, 220);
blueTriangle = getComposition(compWidth, compHeight, BLUE,
YELLOW,
RED,
lineSpacing, lineWeight, triangleMask);
// blue parallelogram
parallelogramMask = getQuadMask(compWidth, compHeight, 200, 25, 200 + 145, 25,
150 + 145, 220, 150, 220);
blueParallelogram = getComposition(compWidth, compHeight, BLUE,
RED,
YELLOW,
lineSpacing, lineWeight, parallelogramMask);
// render compositions
image(redCircle, compSpacing, compSpacing);
image(redBox, compSpacing, compSpacing + (compHeight + compSpacing));
image(yellowSquare, compSpacing + (compWidth + compSpacing), compSpacing);
image(yellowTrapeze, compSpacing + (compWidth + compSpacing), compSpacing + (compHeight + compSpacing));
image(blueTriangle, compSpacing + (compWidth + compSpacing) * 2, compSpacing);
image(blueParallelogram, compSpacing + (compWidth + compSpacing) * 2, compSpacing + (compHeight + compSpacing));
}
function getComposition(w, h, bgFill, bgStroke, fgStroke, spacing, strokeWidth, mask){
let comp = createGraphics(w, h);
bg = getLinesRect(w, h, bgFill, bgStroke, spacing, strokeWidth, true);
fg = getLinesRect(w, h, bgFill, fgStroke, spacing, strokeWidth, false);
// apply mask
fg.mask(mask);
// render to final output
comp.image(bg, 0, 0);
comp.image(fg, 0, 0);
return comp;
}
function getRectMask(w, h, rx, ry, rw, rh){
let mask = createGraphics(w, h);
// make background transparent (alpha is used for masking)
mask.background(0,0);
mask.noStroke();
mask.fill(255);
mask.rect(rx, ry, rw, rh);
// convert p5.Graphics to p5.Image
return mask.get();
}
function getCircleMask(w, h, cx, cy, cs){
let mask = createGraphics(w, h);
// make background transparent (alpha is used for masking)
mask.background(0,0);
mask.noStroke();
mask.fill(255);
mask.circle(cx, cy, cs);
// convert p5.Graphics to p5.Image
return mask.get();
}
function getQuadMask(w, h, x1, y1, x2, y2, x3, y3, x4, y4){
let mask = createGraphics(w, h);
// make background transparent (alpha is used for masking)
mask.background(0,0);
mask.noStroke();
mask.fill(255);
mask.quad(x1, y1, x2, y2, x3, y3, x4, y4);
// convert p5.Graphics to p5.Image
return mask.get();
}
function getTriangleMask(w, h, x1, y1, x2, y2, x3, y3){
let mask = createGraphics(w, h);
// make background transparent (alpha is used for masking)
mask.background(0,0);
mask.noStroke();
mask.fill(255);
mask.triangle(x1, y1, x2, y2, x3, y3);
// convert p5.Graphics to p5.Image
return mask.get();
}
function getLinesRect(w, h, bg, fg, spacing, strokeWidth, isHorizontal){
let rect = createGraphics(w, h);
rect.background(bg);
rect.stroke(fg);
rect.strokeWeight(strokeWidth);
if(isHorizontal){
for(let y = 0 ; y < h; y += spacing){
rect.line(0, y + strokeWidth, w, y + strokeWidth);
}
}else{
for(let x = 0 ; x < w; x += spacing){
rect.line(x + strokeWidth, 0, x + strokeWidth, h);
}
}
// convert from p5.Graphics to p5.Image
return rect.get();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>
Probably both rectangles and the triangle could've been drawn using getQuadMask() making good use of coordinates.
Note that I've just eye balled the shapes a bit so they're not going to be perfect, but it should be easy to tweak. Bare in mind the placement of the mask will have an effect of on how the vertical lines will align.
There are probably other ways to get the same visual effect.
For example, using texture() and textureWrap(REPEAT) with beginShape()/endShape(), using pixels for each line and checking intersections before changing direction and colours, etc.
In terms of generating lines for plotting I would start with horizontal lines, doing line to convex polygon intersection to determine where to stop the horizontal lines and start vertical lines. #AgniusVasiliauskas's answer(+1) is good for that approach.
Freya Holmér has a pretty nice visual explanation for the test.
You need linear algebra stuff, basically noticing how vertical line starting/ending Y coordinate changes in relation to line's X coordinate. And of course a lot of experimenting until you get something usable. Something like :
var w = 600
h = 600
sp = 15
var slides = [fcircle, fsquare, ftriangle, ftrapezoid, fparallelogram];
var active = 0;
var ms;
function blines(){
stroke(0);
for (var i=0; i < h; i+=sp) {
line(0,i,w,i);
}
}
function vertlines(calcline) {
for (var x=w/2-w/4+sp; x < w/2+w/4; x+=sp) {
var pnts = calcline(x);
line(pnts[0],pnts[1],pnts[2],pnts[3]);
}
}
function fcircle() {
// cut background
noStroke();
circle(w/2, h/2, w/2);
stroke('red');
// draw figure lines
let calc = function (x){
var sx = x-w/2;
var sy = h/2;
var ey = h/2;
sy += 137*sin(2.5+x/135);
ey -= 137*sin(2.5+x/135);
return [x,sy,x,ey];
}
vertlines(calc);
}
function fsquare() {
// cut background
noStroke();
quad(w/2-w/4, h/2-h/4, w/2+w/4, h/2-h/4,
w/2+w/4, h/2+h/4, w/2-w/4, h/2+h/4);
stroke('red');
// draw figure lines
let calc = function (x){
return [x,h/2-h/4,x,h/2+h/4];
}
vertlines(calc);
}
function ftriangle() {
// cut background
noStroke();
quad(w/2, h/2-h/4, w/2+w/4, h/2+h/4,
w/2-w/4, h/2+h/4, w/2, h/2-h/4);
stroke('red');
// draw figure lines
let calc = function (x){
var inpx = x > w/2 ? w-x : x;
var ys = h/2+h/4;
ys += -(0.3*inpx*log(inpx)-220);
return [x,ys,x,h/2+h/4];
}
vertlines(calc);
}
function ftrapezoid() {
// cut background
noStroke();
quad(w/2-w/10, h/2-h/4, w/2+w/10, h/2-h/4,
w/2+w/4, h/2+h/4, w/2-w/4, h/2+h/4);
stroke('red');
// draw figure lines
let calc = function (x){
var inpx = x > w/2 ? w-x : x;
var ys = h/2+h/4;
ys += -(0.55*inpx*log(inpx)-420);
if (x >= w/2-w/10 && x <= w/2+w/10) {
ys=h/2-h/4;
}
return [x,ys,x,h/2+h/4];
}
vertlines(calc);
}
function fparallelogram() {
// cut background
noStroke();
quad(w/2-w/10, h/2-h/4, w/2+w/7, h/2-h/4,
w/2, h/2+h/4, w/2-w/4, h/2+h/4);
stroke('red');
// draw figure lines
let calc = function (x){
// guard condition
if (x > w/2+w/7)
return [0,0,0,0];
var inpx = x > w/2 ? w-x : x;
var ys = h/2+h/4;
ys += -(0.55*inpx*log(inpx)-420);
var ye=h/2+h/4
if (x >= w/2-w/10) {
ys=h/2-h/4;
}
if (x > w/2) {
ye = h/2+h/4;
ye += 0.50*inpx*log(inpx)-870;
}
return [x,ys,x,ye];
}
vertlines(calc);
}
function setup() {
ms = millis();
createCanvas(w, h);
}
function draw() {
if (millis() - ms > 2000) {
ms = millis();
active++;
if (active > slides.length-1)
active = 0;
}
background('#D6EAF8');
fill('#D6EAF8');
blines();
slides[active]();
}
Slideshow DEMO
I have a way to do some of the shapes, but I am not sure about others. One way you could do it is if you know where every point on the outline of the shape is, you could just use a for loop and connect every other point from the top and bottom using the line or rect function. This would be relatively easy with shapes like squares and parallelograms, but I am not sure what functions could be used to get this for the points of a circle or trapezoid.
See more here: https://www.openprocessing.org/sketch/745383

SVG - Calculate dynamic text coord

I'm currently working on a SVG "pie" which would allow users to have an overview of all categories of the website in a coloured wheel.
For now i'm able to draw the pie with eventlistener on differents shapes.
var svg = document.getElementById('categSVG');
var startAngle = -89.999;
var nbCateg = 6;
var svgMiddleX = svg.width / 2;
var svgMiddleY = svg.height / 2;
var segmentWidth = 100;
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}
function describeArc(x, y, radius, startAngle, endAngle) {
var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);
var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
var d = [
"M", start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
];
return d.join(" ");
}
function pathGen(nSegment) {
var newPath;
for (var i = 1; i <= nSegment; i++) {
//Adding path
newPath = document.createElementNS('http://www.w3.org/2000/svg', "path");
newPath.setAttribute("id", "arc" + i);
newPath.setAttribute("stroke", '#' + (Math.random() * 0xFFFFFF << 0).toString(16));
newPath.setAttribute("d", describeArc(150, 150, 100, startAngle, 270));
newPath.setAttribute("stroke-width", segmentWidth);
svg.appendChild(newPath);
startAngle += 360 / nbCateg;
}
}
function init() {
pathGen(nbCateg);
var elem;
for (var i = 1; i <= nbCateg; i++) {
document.getElementById("arc" + i).addEventListener("click", function() {
console.log('I would redirect to ' + this.id); //will change
});
}
}
init();
svg {
height: 1000px;
width: 1000px;
}
path {
fill: none;
}
<svg id="categSVG"></svg>
But i can't find a way to display text (html ID in this case) in the middle of the pie part.
So that's my question, how can I calculate X and Y coords to place a text in the middle of each shape ?
To note that number of parts can vary.
Here's my fiddle
(I'm using random colors for tests)
Thank you.
After many tries, I finally found a solution :
Firstly, I included svg.js :
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.4/svg.js"></script>
After that, I added this after "svg.appendChild(newPath)" :
bbox = SVG.adopt(newPath).bbox();
x=bbox.cx;
y=bbox.cy;
text.setAttributeNS(null,"x",""+x);
text.setAttributeNS(null,"y",""+y);
text.setAttributeNS(null,"font-size","30");
svg.appendChild(text);
This solution uses a BBOX to calculate center x and y of a path entity, after that you can easily param your text (don't forget to append a Node to set the text).
Hope it will help someone.

Calculate the mid point of latitude and longitude co-ordinates

Does anyone know the best way to go about getting the mid-point of a pair of latitude and longitude points?
I mm using d3.js to draw points on a map and need to draw a curved line between two points, so I need to create a mid point to draw a curve in the lines.
Please see image below for a better understanding of what I am trying to do:
Apologies for the long script - it just seemed fun to draw stuff :-). I've marked off sections that are not required
// your latitude / longitude
var co2 = [70, 48];
var co1 = [-70, -28];
// NOT REQUIRED
var ctx = document.getElementById("myChart").getContext("2d");
function drawPoint(color, point) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(point.x, point.y, 5, 0, 2 * Math.PI, false);
ctx.fill();
}
function drawCircle(point, r) {
ctx.strokeStyle = 'gray';
ctx.setLineDash([5, 5]);
ctx.beginPath();
ctx.arc(point.x, point.y, r, 0, 2 * Math.PI, false);
ctx.stroke();
}
// REQUIRED
// convert to cartesian
var projection = d3.geo.equirectangular()
var cot1 = projection(co1);
var cot2 = projection(co2);
var p0 = { x: cot1[0], y: cot1[1] };
var p1 = { x: cot2[0], y: cot2[1] };
// NOT REQUIRED
drawPoint('green', p0);
drawPoint('green', p1);
// REQUIRED
function dfn(p0, p1) {
return Math.pow(Math.pow(p0.x - p1.x, 2) + Math.pow(p0.y - p1.y, 2), 0.5);
}
// from http://math.stackexchange.com/a/87374
var d = dfn(p0, p1);
var m = {
x: (p0.x + p1.x) / 2,
y: (p0.y + p1.y) / 2,
}
var u = (p1.x - p0.x) / d
var v = (p1.y - p0.y) / d;
// increase 1, if you want a larger curvature
var r = d * 1;
var h = Math.pow(Math.pow(r, 2) - Math.pow(d, 2) / 4, 0.5);
// 2 possible centers
var c1 = {
x: m.x - h * v,
y: m.y + h * u
}
var c2 = {
x: m.x + h * v,
y: m.y - h * u
}
// NOT REQUIRED
drawPoint('gray', c1)
drawPoint('gray', c2)
drawCircle(c1, r)
drawCircle(c2, r)
// REQUIRED
// from http://math.stackexchange.com/a/919423
function mfn(p0, p1, c) {
// the -c1 is for moving the center to 0 and back again
var mt1 = {
x: r * (p0.x + p1.x - c.x * 2) / Math.pow(Math.pow(p0.x + p1.x - c.x * 2, 2) + Math.pow(p0.y + p1.y - c.y * 2, 2), 0.5)
};
mt1.y = (p0.y + p1.y - c.y * 2) / (p0.x + p1.x - c.x * 2) * mt1.x;
var ma = {
x: mt1.x + c.x,
y: mt1.y + c.y,
}
var mb = {
x: -mt1.x + c.x,
y: -mt1.y + c.y,
}
return (dfn(ma, p0) < dfn(mb, p0)) ? ma : mb;
}
var m1 = mfn(p0, p1, c1);
var m2 = mfn(p0, p1, c2);
var mo1 = projection.invert([m1.x, m1.y]);
var mo2 = projection.invert([m2.x, m2.y]);
// NOT REQUIRED
drawPoint('blue', m1);
drawPoint('blue', m2);
// your final output (in lat long)
console.log(mo1);
console.log(mo2);
Fiddle - https://jsfiddle.net/srjuc2gd/
And here's just the relevant portion (most of it is just copy-pasta from the beginning of this answer)
var Q31428016 = (function () {
// adjust curvature
var CURVATURE = 1;
// project to convert from lat / long to cartesian
var projection = d3.geo.equirectangular();
// distance between p0 and p1
function dfn(p0, p1) {
return Math.pow(Math.pow(p0.x - p1.x, 2) + Math.pow(p0.y - p1.y, 2), 0.5);
}
// mid point between p0 and p1
function cfn(p0, p1) {
return {
x: (p0.x + p1.x) / 2,
y: (p0.y + p1.y) / 2,
}
}
// get arc midpoint given end points, center and radius - http://math.stackexchange.com/a/919423
function mfn(p0, p1, c, r) {
var m = cfn(p0, p1);
// the -c1 is for moving the center to 0 and back again
var mt1 = {
x: r * (m.x - c.x) / Math.pow(Math.pow(m.x - c.x, 2) + Math.pow(m.y - c.y, 2), 0.5)
};
mt1.y = (m.y - c.y) / (m.x - c.x) * mt1.x;
var ma = {
x: mt1.x + c.x,
y: mt1.y + c.y,
}
var mb = {
x: -mt1.x + c.x,
y: -mt1.y + c.y,
}
return (dfn(ma, p0) < dfn(mb, p0)) ? ma : mb;
}
var Q31428016 = {};
Q31428016.convert = function (co1, co2) {
// convert to cartesian
var cot1 = projection(co1);
var cot2 = projection(co2);
var p0 = { x: cot1[0], y: cot1[1] };
var p1 = { x: cot2[0], y: cot2[1] };
// get center - http://math.stackexchange.com/a/87374
var d = dfn(p0, p1);
var m = cfn(p0, p1);
var u = (p1.x - p0.x) / d
var v = (p1.y - p0.y) / d;
var r = d * CURVATURE;
var h = Math.pow(Math.pow(r, 2) - Math.pow(d, 2) / 4, 0.5);
// 2 possible centers
var c1 = {
x: m.x - h * v,
y: m.y + h * u
}
var c2 = {
x: m.x + h * v,
y: m.y - h * u
}
// get arc midpoints
var m1 = mfn(p0, p1, c1, r);
var m2 = mfn(p0, p1, c2, r);
// convert back to lat / long
var mo1 = projection.invert([m1.x, m1.y]);
var mo2 = projection.invert([m2.x, m2.y]);
return [mo1, mo2]
}
return Q31428016;
})();
// your latitude / longitude
var co1 = [-70, -28];
var co2 = [70, 48];
var mo = Q31428016.convert(co1, co2)
// your output
console.log(mo[0]);
console.log(mo[1]);
For the accurate side:
You may use the Esri web API. Nothing beats decades of experience implementing the hard side of projection systems and datums... Athough the ArcGIS for Server line is a commercial product, the JS API is free, and here there's a pure JS function that does just what you want : geometryEngine.densify ; that function requires an interval parameter, that you can, in your case, get by dividing by two the results of geometryEngine.geodesicLength
That'll need you to get acquainted with the Polyline class in a very basic way, such as var mySegment = new Polyline([[50,3], [55,8]]); and probably nothing further.
For the visual side :
Your segment has two middles ? You may also be interested in geometryEngine.offset ; first offset the original segment once in each direction, then get the center point for each of the resulting segments.
For the practical side :
Given the short distances involved, provided you're not dealing with a weird place that'd be too close to the poles, I'd simply go with an arithmetic average of X and Y, and then add/subtract a rotated vector to offset your two "middles". Doing it this way would be both lighter on the machine (no libs to load from a CDN), easier on you, and as long as the purpose of it is a nice display, the result will be more than good enough.
(added as per comment : a sample)
// Your known starting points, and a k factor of your choice.
var a = {x:3, y:50};
var b = {x:8, y:55};
var k = 0.2;
// Intermediate values
var vab = {x:b.x-a.x, y:b.y-a.y};
var v_rotated = {x:-k*vab.y, y:k*vab.x};
var middle = {x:a.x+vab.x/2, y:a.y+vab.y/2};
// Your two resulting points
var result_i = {x: middle.x + v_rotated.x, y: middle.y + v_rotated.y};
var result_j = {x: middle.x - v_rotated.x, y: middle.y - v_rotated.y};
Check this question, you can use it to find the middle of your coordination on google map. I customized it to use with d3js.
Hope this help you.
In D3
function midpoint (lat1, lng1, lat2, lng2) {
lat1= deg2rad(lat1);
lng1= deg2rad(lng1);
lat2= deg2rad(lat2);
lng2= deg2rad(lng2);
dlng = lng2 - lng1;
Bx = Math.cos(lat2) * Math.cos(dlng);
By = Math.cos(lat2) * Math.sin(dlng);
lat3 = Math.atan2( Math.sin(lat1)+Math.sin(lat2),
Math.sqrt((Math.cos(lat1)+Bx)*(Math.cos(lat1)+Bx) + By*By ));
lng3 = lng1 + Math.atan2(By, (Math.cos(lat1) + Bx));
return (lat3*180)/Math.PI .' '. (lng3*180)/Math.PI;
}
function deg2rad (degrees) {
return degrees * Math.PI / 180;
};
Update 1
If you try to draw curve line, you should create a path with coordination such as :
var lat1=53.507651,lng1=10.046997,lat2=52.234528,lng2=10.695190;
var svg=d3.select("body").append("svg").attr({width:700 , height:600});
svg.append("path").attr("d", function (d) {
var dC="M "+lat1+","+lng1+ " A " + midpoint (lat1, lng1, lat2, lng2)
+ " 0 1,0 " +lat2 +" , "+lng2 +"Z";
return dC;
})
.style("fill","none").style("stroke" ,"steelblue");
You need to create your curve line as you want in d3.
JsFiddle here.
I always use geo-lib
and works

how to create bezier curve in JavaScript?

I am trying to create a bezier curve using JavaScript on a HTML5 canvas. Below is the code that I have written us in the drawbeziercurve function. The result is that, I only get the four points, but cant get the bezier curve to appear. Any help guys?
function drawBezierCurve() {
"use strict";
var t, i, x, y, x0, x1, x2, x3;
// for (t = 1; t <= nSteps; t++) {
//t = 1/nSteps
q0 = CalculateBezierPoint(0, x0, x1, x2, x3);
for(i = 0; i <= nSteps; i++)
{
t = i / nSteps;
q1 = CalculateBezierPoint(t, x0, x1, x2, x3);
DrawLine(q0, q1);
q0 = q1;
}
//[x] = (1-t)³x0 + 3(1-t)²tx1+3(1-t)t²x2+t³x3
//[y] = (1-t)³y0 + 3(1-t)²ty1+3(1-t)t²y2+t³y3
procedure draw_bezier(A, v1, v2, D)
B = A + v1
C = D + v2
//loop t from 0 to 1 in steps of .01
for(t=0; t <=1; t+ 0.1){
a = t
b = 1 - t
point = A*b³ + 3*B*b²*a + 3C*b*a2 + D*a³
//drawpixel (point)
drawLine(arrayX[0], arrayY[0], (arrayX[0] + arrayX[1] + arrayX[2] + arrayX[3]) / 4,
(arrayY[0] + arrayY[1] + arrayY[2] + arrayY[3]) / 4, 'blue');
//end of loop
}
end of draw_bezier
/* drawLine(arrayX[0], arrayY[0], (arrayX[0] + arrayX[1] + arrayX[2] + arrayX[3]) / 4,
(arrayY[0] + arrayY[1] + arrayY[2] + arrayY[3]) / 4, 'blue');
drawLine((arrayX[0] + arrayX[1] + arrayX[2] + arrayX[3]) / 4,
(arrayY[0] + arrayY[1] + arrayY[2] + arrayY[3]) / 4, arrayX[3], arrayY[3], 'blue'); */
}
// points array
Do draw a poly-line (a line consisting of many points) on a canvas, do something like this:
var canvas = document.querySelector('canvas'),
ctx = canvas.getContext('2d');
ctx.lineWidth = 1.5;
ctx.strokeStyle = 'red';
ctx.beginPath();
for (var i = 0; i < 100; i++)
{
var x = Math.random() * 100,
y = Math.random() * 100;
ctx.lineTo(x, y);
}
ctx.stroke();
You can use something similar, however instead of choosing random x and y values, use your own logic.
Here's a working example on jsFiddle.

circle with conical gradient

is possible to create a circle with raphael with conical gradient?
Something like colorwheel of http://raphaeljs.com/picker/ but with customized colors
ex: "from red to orange to yellow to green to yellow to orange to red)"
Yes it is, try this function (I statred from Raphael's Colorpicker code, made it stand-alone and added the gradation between specific colors instead of just increasing the hue along the disc):
var paper = Raphael('paper', 800, 600);
var wheel = function (x, y, r, colors) {
var pi = Math.PI;
var nbColors = colors.length;
// Formatting every color to its RGB values
for (var i = 0 ; i < nbColors ; i++)
{
colors[i] = Raphael.getRGB(colors[i]);
}
// Initialize segments
var segments = pi * r * 2 / Math.min(r / 8, 4);
var a = pi / 2 - pi * 2 / segments * 1.5;
var path = ["M", x, y - r, "A", r, r, 0, 0, 1, r * Math.cos(a) + x, y - r * Math.sin(a), "L", x, y, "z"].join();
// Draw segments
for (var i = 0 ; i < segments ; i++)
{
// Between which 2 colors is this segment?
var j = nbColors * i / segments;
var n = Math.floor(j);
var d = j % 1;
var color1 = colors[n];
var color2 = colors[(n + 1) % nbColors];
// Calculate the segment's color from the 2 other
var color =
{ r : Math.round(d * (color2.r - color1.r) + color1.r)
, g : Math.round(d * (color2.g - color1.g) + color1.g)
, b : Math.round(d * (color2.b - color1.b) + color1.b)
}
// Draw the sector
paper.path(path).attr(
{ stroke: 'none'
, fill: 'rgb(' + color.r + ',' + color.g + ',' + color.b + ')'
, rotation: [90 + (360 / segments) * i, x, y]
});
}
// Surrounding circle
return paper.circle(x, y, r).attr(
{ stroke : '#fff'
, 'stroke-width' : Math.round(r * .03)
});
};
You can use it like this, the 4th parameter being an array of colors to use:
wheel (100, 100, 50, ['#F00', '#0FF', '#00F', '#0F0', '#F80']);
wheel (500, 200, 50, ['rgb(255,0,0)', 'hsb(40,100,100)', '#0F00F0']);

Categories