How to add a background image to an SVG element - svg

I'm using this code to create a compass needle on an HTML page (instead of the range input i'm using data derived form a separate software). However, I'd like to add a compass face image behind it. Any ideas how I do that? Thanks (The code is from another thread by #Coderino Javarino) Perhaps you can help if you see this?
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body {
margin: 0;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
</style>
</head>
<body>
<input type="range" min="0" max="360" value="0" id="slider" oninput="updateAngle(this.value)">
<script>
// Feel free to change or delete any of the code you see in this editor!
var svg = d3.select("body").append("svg")
.attr("width", 200)
.attr("height", 200)
.attr('viewBox', '-50 -50 100 100')
var path_d = "M 0,0 L 0,-10 L 50,0 L 0,10 Z";
function updateAngle(value) {
var angle = parseInt(value);
var data = [{
angle: angle,
color: 'black'
}, {
angle: (180 + angle) % 360,
color: 'red'
}];
paths = svg.selectAll('path')
.data(data);
paths.enter()
.append('path')
.attr('d', path_d)
.merge(paths)
.style('fill', d => d.color)
.attr('transform', d => `rotate(${d.angle})`);
paths.exit().remove();
}
updateAngle(0);
</script>
</body>

Related

Erasing Lines on Fabric JS

I am using FabricJS to draw and erase lines on top of an image. I made 2 layers for the canvas, with the bottom layer as the background image and the top layer for sketching. Whenever I erase the markings, if I use freeDrawingBrush.color =white, or any basic color, it gets erased. However, if I use transparent, 'rgba(0,0,0,0)', as the color of the freeDrawingBrush, the markings are not erased.
How can I erase the marking on the top layer with a transparent as the background of the path created as I erase?
<div style="position: relative;">
<canvas id="my-canvas" width="800" height="400" style="position: absolute; left: 0; top: 0; z-index: 1;background-color:rgba(0,0,0,0)"> </canvas>
<canvas id="layer3" width="800" height="400" style="position: absolute; left: 0; top: 0; z-index: 0;background-image:url(http://gallery.nanfa.org/d/52271-3/DSC_7537.jpg);"></canvas>
</div>
<script>
canvas = window._canvas = new fabric.Canvas('layer1');
canvas.isDrawingMode= 1;
canvas.freeDrawingBrush.width = 10;
canvas.renderAll();
//eraser function
function eraser(){
canvas.freeDrawingBrush.color = "white"; // if "rgba(0,0,0,0)", not work
canvas.on('path:created', function (opt) {
opt.path.globalCompositeOperation = 'destination-out';
canvas.renderAll();
});
}
//drawing function
function draw(){
canvas.freeDrawingBrush.color = "black";
canvas.on('path:created', function (opt) {
opt.path.globalCompositeOperation = 'source-over';
canvas.renderAll();
});
}
</script>
Im using fabricjs on html https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.min.js
Any help will be very much appreciated. Thanks in advance!

How do I scale the scene to fullscreen?

I'm currently learning Phaser 3. However, all the documentation I can find is about Phaser2.
When you create a game you have to set the width and height in the config:
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
};
How can I scale the scene to fullscreen?
UPDATE
Phaser 3.16 is released on now (Feb, 2019), which has inbuilt Scale Manager. It provide various methods to scale your game. Check it out before trying the code below.
Phaser.Scale Docs
Notes on Scale Manager
Old Answer
You can resize the canvas element using resize function mentioned in code snippet and execute that function before starting game and whenever screen is resized. This way you can maintain the aspect ratio of 800:600(4:3) and fit the canvas element to full-screen according to screen ratio.
Run code snippet in Full Page Mode and resize your browser to see how canvas element is resized. Size of blue rectangle is the size of your canvas(game).
var game;
var gameWidth = 800;
var gameHeight = 600;
window.onload = function() {
var config = {
type: Phaser.CANVAS,
width: gameWidth,
height: gameHeight,
scene: [intro]
};
game = new Phaser.Game(config);
resize();
window.addEventListener("resize", resize, false);
};
function resize() {
var canvas = document.querySelector("canvas");
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var windowRatio = windowWidth / windowHeight;
var gameRatio = game.config.width / game.config.height;
if (windowRatio < gameRatio) {
canvas.style.width = windowWidth + "px";
canvas.style.height = (windowWidth / gameRatio) + "px";
} else {
canvas.style.width = (windowHeight * gameRatio) + "px";
canvas.style.height = windowHeight + "px";
}
}
var intro = new Phaser.Scene('intro');
intro.create = function() {
var rect = new Phaser.Geom.Rectangle(0, 0, 800, 600);
var graphics = this.add.graphics({
fillStyle: {
color: 0x0000ff
}
});
graphics.fillRectShape(rect);
};
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
body {
background: #000000;
padding: 0px;
margin: 0px;
}
canvas {
display: block;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
<script src="https://cdn.jsdelivr.net/npm/phaser#3.6.0/dist/phaser.min.js"></script>
</head>
<body>
</body>
</html>
You should check out this post. It explains this code in detail.
css style (in index.html) should be as simple as
body { margin:0; padding:0; overflow:hidden }
body>canvas { width:100%!important; height:100%!important;
position:fixed; top:0; left:0 }
!important suffix is needed to override the dynamic html style
for example
<canvas width="800" height="600"
style="width: 681.778px; height: 511.333px;
margin-left: 0px; margin-top: 0px;"></canvas>
phaser config in index.js
const config = {
parent: "phaser-example",
type: Phaser.AUTO,
width: 800,
height: 600,
scene: {
preload: preload,
create: create
},
// https://rexrainbow.github.io/phaser3-rex-notes/docs/site/scalemanager/
scale: {
// ignore aspect ratio:
mode: Phaser.Scale.RESIZE,
// keep aspect ratio:
//mode: Phaser.Scale.FIT,
//mode: Phaser.Scale.ENVELOP, // larger than Scale.FIT
//mode: Phaser.Scale.HEIGHT_CONTROLS_WIDTH, // auto width
//mode: Phaser.Scale.WIDTH_CONTROLS_HEIGHT, // auto height
autoCenter: Phaser.Scale.NO_CENTER,
//autoCenter: Phaser.Scale.CENTER_BOTH,
//autoCenter: Phaser.Scale.CENTER_HORIZONTALLY,
//autoCenter: Phaser.Scale.CENTER_VERTICALLY,
},
autoRound: false,
};

Creating clickable legends with D3

I'm trying to create a multi-line chart with D3, but I'm stuck on toggling the visibility of lines off. So far, there is only one line, whilst I try to figure it all out (still a bit of a beginner with this), but I can't get the legend to appear, so I can't test if it'll actually get rid of the line too. Here is the JavaScript code:
var BlackBird = [{
"population": "100",
"year": "1970"
}, {
"population": "100.8",
"year": "1971"
}, {
"population": "103.5",
"year": "1972"
}, {
"population": "95.6",
"year": "1973"
}, {
"population": "101.7",
"year": "1974"
}, {
"population": "102",
"year": "1975"
}
];
var vis = d3.select("#visualisation"),
WIDTH = 1110,
HEIGHT = 580,
MARGINS = {
top: 30,
right: 20,
bottom: 20,
left: 50
},
xScale = d3.scale.linear()
.range([MARGINS.left, WIDTH - MARGINS.right])
.domain([1970,2008]),
yScale = d3.scale.linear()
.range([HEIGHT - MARGINS.top, MARGINS.bottom])
.domain([0,300]),
xAxis = d3.svg.axis()
.scale(xScale)
.ticks(25)
.tickFormat(d3.format('0f')),
yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(12);
vis.append("svg:g")
.attr("class", "axis")
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
.call(xAxis);
vis.append("svg:g")
.attr("class", "axis")
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis);
var lineGen = d3.svg.line()
.x(function(d) {
return xScale(d.year);
})
.y(function(d) {
return yScale(d.population);
})
.interpolate("basis");
vis.append('path')
.attr('d', lineGen(BlackBird))
.attr('stroke-width', 5)
.attr('fill', 'none')
.attr('opacity', '0.2')
.attr("id", "aline");
vis.append("text")
.attr("x", WIDTH + MARGINS.left +10)
.attr("y", 10)
.attr("class", "legend")
.style("fill", "steelblue")
.on("click", function(){
var active = aline.active ? false : true,
newOpacity = active ? 0 : 1;
d3.select("#aline").attr("opacity", newOpacity);
aline.active = active;
})
.text("Blue Line");
HTML:
<!DOCTYPE html> <html lang= "en"> <head> <meta charset="UTF-8"> <title>D3 Birds</title> <link rel="stylesheet" href="D3Bird2.css"> </head> <body> <svg id="visualisation" width="1140" height="600"></svg> <div id ="BlaBird"> <img src="Blackbird.png" alt="A Blackbird" class= "Birdie"> </div> <script src="d3.min.js" charset="utf-8"> </script> <script src="script2.js" charset="utf-8"></script> </body> </html>
CSS:
.axis path {
fill: none;
stroke: #777;
shape-rendering: crispEdges;
}
.axis text {
font-family: Lato;
font-size: 13px;
}
#aline {
stroke: #000;
opacity: 0.5;
transition: 0.5s;
}
#aline: hover {
opacity: 1;
transition: 0.5s;
}
.Birdie {
transition: 0.5s;
opacity: 0.5;
}
#BlaBird {
position: absolute;
left: 1150px;
top: 30px;
}
.legend {
font-size: 16px;
font-weight: bold;
text-anchor: start;
}
First, you didn't include your HTML markup, but I'm assuming #visualisation is an SVG element. Make sure you've assigned it height and width attributes.
Second, you don't assign a stroke color to your line. I'm assuming you do this in CSS somewhere.
Third, after fixing your variable names, this line:
.attr("x", width + margin.left +10)
is the problem. This pushes the text element outside of it's SVG.
Here's an example where I've fixed some of this up.
EDITS
New problem after looking at your CSS. You are setting the attribute opacity in code, the CSS sets the style opacity. When both are set the browser will use the style. So change your click handler to:
.on("click", function() {
var active = aline.active ? false : true,
newOpacity = active ? 0 : 1;
d3.select("#aline").style("opacity", newOpacity); //<-- set style, not attr
aline.active = active;
})
Example updated.

kinetic javascript get value on click

I have an array of points(pair of x,y) and I draw circles by these points
for (var i = 0; i < points.length;i++){
var circle = new Kinetic.Circle({
x: points[i].x,
y: points[i].y,
radius: 7,
fill: "green",
stroke: "black",
name:i,
strokeWidth: 2
});
circle.on("click", function() {
alert(name); //here I want to get name of circle
});
layer.add(circle);
}
I added new attribute name to each circle, like ID and I want to alert name of circle when mouse is clicked at it.
I am not sure that adding new attribute name to circle is correct.
So,how to add new attribute "name" to circle so that when clicking at circle it alerts its value of name?
Try this below code
<!DOCTYPE HTML>
<html>
<head>
<style>
body
{
margin: 0px;
padding: 0px;
}
</style>
</head>
<body onload="displaycircle()">
<div id="container">
</div>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.0.0.js"></script>
<script>
function displaycircle() {
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
for (var i = 0; i < 10; i++) {
var circle = new Kinetic.Circle({
x: Math.random() * stage.getWidth(),
y: Math.random() * stage.getHeight(),
radius: 30,
fill: "green",
stroke: "black",
name: i,
strokeWidth: 2,
draggable: true
});
layer.add(circle);
stage.add(layer);
circle.on("click", function() {
alert(this.attrs.name); //here you can get name of circle
});
}
}
</script>
</body>
</html>

Cutting out a fat stroke

I want to draw this:
Two lines following a along a beizer path with equal distance. The fat lines are what I want, the small dotted one is the guiding path.
The image above is done by first stroking the path with width 30, and then with width 25 in the same color as the background. This works OK sometimes, but not if the background isn't plain colored.
I want something like 'clip' with a shape. And I would prefer to do it using standard graphic libraries. Even better the tools that come in most 2d graphics canvases.
Notes:
I'm using HTML canvas, but I don't think that's important to the problem.
I can translate the path up and down, but that won't give me the same distance to the center everywhere.
Maybe it could be done with a gradient stroke, but I'm not sure how those work.
I can think of a way to do this in HTML5 Canvas.
What you want to do is draw a curve - on an in-memory, temporary canvas - and then draw the same curve with less thickness and with the globalCompositeOperation set to destination-out on that same canvas.
That will get you the shape you want, essentially 2 lines with transparency between them.
Then you draw that canvas onto the real canvas that has whatever on it (complex background, etc).
Here's an example:
http://jsfiddle.net/at3zR/
The following should better illustrate what I meant. There is a simple algorithm that needs to be added to adjust the offset depending on where the control points are located in relation to each other. If I get more time, and remember, I'll add it.
bezier.js
/*
*
* This code was Shamlessly stolen from:
* Canvas curves example
*
* By Craig Buckler, http://twitter.com/craigbuckler
* of OptimalWorks.net http://optimalworks.net/
* for SitePoint.com http://sitepoint.com/
*
* Refer to:
* http://blogs.sitepoint.com/html5-canvas-draw-quadratic-curves/
* http://blogs.sitepoint.com/html5-canvas-draw-bezier-curves/
*
* This code can be used without restriction.
*/
(function() {
var canvas, ctx, code, point, style, drag = null, dPoint;
// define initial points
function Init(quadratic) {
point = {
p1: { x:100, y:250 },
p2: { x:400, y:250 }
};
if (quadratic) {
point.cp1 = { x: 250, y: 100 };
}
else {
point.cp1 = { x: 150, y: 100 };
point.cp2 = { x: 350, y: 100 };
}
// default styles
style = {
//#333
curve: { width: 2, color: "#C11" },
cpline: { width: 1, color: "#C11" },
point: { radius: 10, width: 2, color: "#900", fill: "rgba(200,200,200,0.5)", arc1: 0, arc2: 2 * Math.PI }
}
// line style defaults
ctx.lineCap = "round";
ctx.lineJoin = "round";
// event handlers
canvas.onmousedown = DragStart;
canvas.onmousemove = Dragging;
canvas.onmouseup = canvas.onmouseout = DragEnd;
DrawCanvas();
}
function controlLine(offset) {
// curve
ctx.lineWidth = style.curve.width;
ctx.strokeStyle = style.curve.color;
ctx.beginPath();
ctx.moveTo(point.p1.x+offset, point.p1.y+offset);
ctx.bezierCurveTo(point.cp1.x+offset, point.cp1.y+offset, point.cp2.x+offset, point.cp2.y+offset, point.p2.x+offset, point.p2.y+offset);
ctx.stroke();
}
function controlPoints(/*hidden*/) {
// control point tethers
ctx.lineWidth = style.cpline.width;
ctx.strokeStyle = style.cpline.color;
ctx.beginPath();
ctx.moveTo(point.p1.x, point.p1.y);
ctx.lineTo(point.cp1.x, point.cp1.y);
ctx.moveTo(point.p2.x, point.p2.y);
ctx.lineTo(point.cp2.x, point.cp2.y);
ctx.stroke();
// control points
for (var p in point) {
ctx.lineWidth = style.point.width;
ctx.strokeStyle = style.point.color;
ctx.fillStyle = style.point.fill;
ctx.beginPath();
ctx.arc(point[p].x, point[p].y, style.point.radius, style.point.arc1, style.point.arc2, true);
ctx.fill();
ctx.stroke();
}
}
// draw canvas
function DrawCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
controlLine(-10);
controlLine(+10);
controlPoints();
}
// start dragging
function DragStart(e) {
e = MousePos(e);
var dx, dy;
for (var p in point) {
dx = point[p].x - e.x;
dy = point[p].y - e.y;
if ((dx * dx) + (dy * dy) < style.point.radius * style.point.radius) {
drag = p;
dPoint = e;
canvas.style.cursor = "move";
return;
}
}
}
// dragging
function Dragging(e) {
if (drag) {
e = MousePos(e);
point[drag].x += e.x - dPoint.x;
point[drag].y += e.y - dPoint.y;
dPoint = e;
DrawCanvas();
}
}
// end dragging
function DragEnd(e) {
drag = null;
canvas.style.cursor = "default";
DrawCanvas();
}
// event parser
function MousePos(event) {
event = (event ? event : window.event);
return {
x: event.pageX - canvas.offsetLeft,
y: event.pageY - canvas.offsetTop
}
}
// start
canvas = document.getElementById("canvas");
code = document.getElementById("code");
if (canvas.getContext) {
ctx = canvas.getContext("2d");
Init(canvas.className == "quadratic");
}
})();
bezier.html
<!--
bezier.html
Copyright 2012 DT <dtyree#inkcogito>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>untitled</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<meta name="generator" content="Geany 0.21" />
<meta charset="UTF-8" />
<title>Bézier Example</title>
</head>
<link rel="stylesheet" type="text/css" media="all" href="styles.css" />
<body>
<h1>Canvas Bézier Curve Example</h1>
<canvas id="canvas" height="500" width="500" class="bezier"></canvas>
<pre id="code">code</pre>
<p>This demonstration shows how parallel bézier curves can be drawn on a canvas element. Drag the line ends or the control points to change the curve.</p>
<script type="text/javascript" src="bezier.js"></script>
</body>
</html>
styles.css
/* CSS */
body
{
font-family: arial, helvetica, sans-serif;
font-size: 85%;
margin: 10px 15px;
color: #333;
background-color: #ddd;
}
h1
{
font-size: 1.6em;
font-weight: normal;
margin: 0 0 0.3em 0;
}
h2
{
font-size: 1.4em;
font-weight: normal;
margin: 1.5em 0 0 0;
}
p
{
margin: 1em 0;
}
#canvas
{
display: inline;
float: left;
margin: 0 10px 10px 0;
background-color: #fff;
}

Resources