identify dynamically created svg element - javascript

I am trying to manipulate elements inside svg (such as circle or path). I need to create them dynamically and be able to identify them.
I've stolen few functions from some online examples, and came up with following code (it should create circle inside svg on mouse click, and a text tag when the mouse is over the circle). However, it is not working as I expected. When mouse enters the element from left, the elementFromPoint(x, y).id returns valid ID "circle", but when the mouse enters the element from right, it returns it's parent ID "mySVG".
I was not able to find a proper solution anywhere, so any advice is welcomed - indeed, I will try to read the specs for svg and learn JS as best as I can, however, it is still a painful process for me to understand these things. Your time and suggestions are highly appreciated! Thanks. k
JS Fiddle:
https://jsfiddle.net/krisfiddle/2xc3tgdr/6/
The Code
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
body, canvas, svg {position:absolute; margin:0; padding:0; border:none;}
svg {top:0; left:0;}
.circle:hover {opacity:0.5;}
</style>
</head>
<body>
<svg id="mySVG" xmlns:xlink="http://www.w3.org/1999/xlink" height="400" width="300" style="border: 1px solid black" onClick="circle()"></svg>
<script>
var w = window.innerWidth;
var h = window.innerHeight;
var x;
var y;
var color = undefined;
function handleMouseMove(event) {
var dot, eventDoc, doc, body, pageX, pageY;
event = event || window.event;
if (event.pageX == null && event.clientX != null) {
eventDoc = (event.target && event.target.ownerDocument) || document;
doc = eventDoc.documentElement;
body = eventDoc.body;
event.pageX = event.clientX +
(doc && doc.scrollLeft || body && body.scrollLeft || 0) -
(doc && doc.clientLeft || body && body.clientLeft || 0);
event.pageY = event.clientY +
(doc && doc.scrollTop || body && body.scrollTop || 0) -
(doc && doc.clientTop || body && body.clientTop || 0 );
}
x = event.pageX;
y = event.pageY;
}
document.onmousemove = handleMouseMove;
function circle() {
var myCircle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
myCircle.setAttribute('id', 'circleID');
myCircle.setAttribute('class', 'circle');
myCircle.setAttributeNS(null, "cx", x);
myCircle.setAttributeNS(null, "cy", y);
myCircle.setAttributeNS(null, "r", 50);
myCircle.setAttributeNS(null, "fill", "green");
myCircle.setAttributeNS(null, "stroke", "none");
myCircle.setAttributeNS(null, "onmouseover", "getIdXY()");
myCircle.setAttributeNS(null, "onmouseout", "deleteIdXY()");
document.getElementById("mySVG").appendChild(myCircle);
}
function getIdXY() {
var elementMouseIsOver = document.
var idMark = document.createElementNS("http://www.w3.org/2000/svg", "text");
idMark.setAttributeNS(null, "x", x);
idMark.setAttributeNS(null, "y", y);
idMark.setAttributeNS(null, "fill", "red");
idMark.setAttributeNS(null, "id", "text");
document.getElementById("mySVG").appendChild(idMark);
document.getElementById("text").innerHTML = elementMouseIsOver;
}
function deleteIdXY() {
var parent = document.getElementById("mySVG");
var child = document.getElementById("text");
parent.removeChild(child);
}
</script>
</body>
</html>

Well, for the time being, I implemented both sugestions by Robert and Marcin. For some reason the elementFromPoint() seems to be quite difficult for me to handle in this particular implementation, thus I gladly turned to "this obj" method. Indeed, storing coords in global variables and asigning unique ID to elements is a good idea. Thought the code is not very elegant it gave me a good intro into JS and dynamicaly created SVG. Many thans to Marcin and Robert. The result is sutisfactory for my purposes at the moment and can be observed at following fiddle in action:
http://jsfiddle.net/4uu1vbzz/2/
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<svg id="mySVG" xmlns:xlink="http://www.w3.org/1999/xlink" height="400" width="300" style="border: 1px solid black"></svg>
</body>
<script>
var x, y, recentX, recentY; // stores XY mouse coordinations
var circleID = 0; // used as increment to generate unique ID for each circle
var tagID = 0; // used as increment to generate unique ID for each circle's tag
var elementMouseIsOver = ""; // stores ID of the element recently under the pointer
// get mouse coords on mouse move
var mouseMoves = function(e) {
recentX = e.clientX;
recentY = e.clientY;
}
window.onload = function() {this.addEventListener('mousemove', mouseMoves);} //event handler for mousemove coords
//create circle within svg
var draw = function draw(e) {
x = e.clientX;
y = e.clientY;
circleID = circleID + 1; //increment the number for ID
var id = "circle" + circleID; //create string to pass the ID
//place circle with ID into svg
var myCircle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
myCircle.setAttribute('id', id);
myCircle.setAttribute('class', 'circle');
myCircle.setAttributeNS(null, "cx", x);
myCircle.setAttributeNS(null, "cy", y);
myCircle.setAttributeNS(null, "r", 50);
myCircle.setAttributeNS(null, "fill", "green");
myCircle.setAttributeNS(null, "stroke", "none");
myCircle.setAttributeNS(null, "onmouseover", "tagId(this)");
myCircle.setAttributeNS(null, "onmouseout", "deleteTag()");
document.getElementById("mySVG").appendChild(myCircle);
}
document.getElementById("mySVG").addEventListener('click', draw); //event handler for onclick action
//on mouseover get the ID of the element under the pointer and create an tag marking it
function tagId(obj) {
elementMouseIsOver = obj.id;
tagID = tagID + 1;
var id = "tag" + tagID;
var idMark = document.createElementNS("http://www.w3.org/2000/svg", "text");
idMark.setAttributeNS(null, "x", recentX);
idMark.setAttributeNS(null, "y", recentY);
idMark.setAttributeNS(null, "fill", "red");
idMark.setAttributeNS(null, "id", id);
document.getElementById("mySVG").appendChild(idMark);
document.getElementById(id).innerHTML = elementMouseIsOver;
}
//remove the tag when mouse leaves the element
function deleteTag() {
var id = "tag" + tagID;
var parent = document.getElementById("mySVG");
var child = document.getElementById(id);
parent.removeChild(child);
}
</script>
</html>

The problem is that your structure is all wrong.
Get the current coordinates of the click in your click handler, and keep some kind of counter outside of the handler (but accessible to it), which you increment every time you create a circle. That way, you can add that number to circleID.

Related

Why won't my rectangle move when I press the key?

So I'm trying to make a snake game from scratch a practice for making games in javascript. I've made the square inside of my canvas, and now I'm trying to make it move. This is the code I've made for it.
<!DOCTYPE html>
<html>
<body>
<canvas id = "gameCanvas" width="700" height="600" style="border:4px solid black; background-color: yellow"></canvas>
<script type = "text/javascript">
var myCanvas = document.getElementById("gameCanvas");
var ctx = myCanvas.getContext("2d");
this.x = 0;
this.y = 0;
var snake = ctx.fillRect(this.x,this.y,10,10);
myMovement = function(){
var moveUp = event.keyCode;
if(moveUp == 39){
snake = ctx.fillRect(this.x + 1, this.y,10,10);
}
}
</script>
</body>
</html>
Unfortunately, when I press the button, nothing happens. What's wrong with my code.
There are a few problems with your code.
You are using this in a place where it is going to reference the global object (window in this case).
Your myMovement function isn't attached to anything, meaning it isn't setup as a event listener which is needed for it to be called when a key is pressed
Even if your myMovement was setup it didn't have the event object defined as a parameter so your function would have errored out as there wouldn't have been an event object to access
For 1 if you are meaning to you keep track of the x,y you can place them in an object and access them from there:
var rect={
x:0,
y:0
};
//then when needing to use them access them like rect.x, rect.y
//also fillRect doesn't return anything so no need for "var snake = "
ctx.fillRect(rect.x, rect.y, 10, 10);
For 2 and 3 you can use the various key* events for your function. You can attach the function by using addEventListener. Finally define an event parameter for your function so that you actually have an event object to use:
function myMovement(event) {
var moveUp = event.keyCode;
if(moveUp == 39){
//++rect.x adds one and assigns the new value to rect.x
//and again fillRect doesn't return a value so no need for "snake ="
ctx.fillRect(++rect.x, rect.y,10,10);
}
}
window.addEventListner("keydown",myMovement);
Demo
var myCanvas = document.getElementById("gameCanvas");
var ctx = myCanvas.getContext("2d");
var rect = {
x: 0,
y: 0
};
ctx.fillRect(rect.x, rect.y, 10, 10);
window.onkeydown = function(event) {
var moveUp = event.keyCode;
if (moveUp == 39) {
//erase last fill
ctx.clearRect(rect.x, rect.y, 10, 10);
ctx.fillRect(++rect.x, rect.y, 10, 10);
}
}
<canvas id="gameCanvas" width="100%" height="100%" style="border:4px solid black; background-color: yellow"></canvas>
problem findings:
myMovement = function(){
var moveUp = event.keyCode;
if(moveUp == 39){
snake = ctx.fillRect(this.x + 1, this.y,10,10);
}
}
when myMovement will fire it does not know the code, and
//x value just add 1 with previous but not increment gradually, so it should be this.x += 1
ctx.fillRect(this.x + 1, this.y,10,10);
Solution:
window.onkeyup = function(e) {
var key = e.keyCode ? e.keyCode : e.which;
if (key == 39) {
snake = ctx.fillRect(this.x += 1, this.y,10,10);
}
}
you can see here for the keyboard keys value
The onkeyup event occurs when the user releases a key (on the
keyboard).
Actually there are 3 different options to fire key event
onkeydown
onkeypress
onkeyup

Trying to move boxes

I have a random amount of boxes, randomly on a page of random colors. I am trying to be able to get them to move from one place to another.
Essentially, I am not familiar at all with mouse move events so this is quite the challenge. Even though it is quite simple.
Heres the code for the HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Ramdom Boxes</title>
<script src="A2Q1.js"></script>
</head>
<body>
</body>
</html>
Javascript:
window.onload = init;
function init() {
//when page is loaded create a bunch of boxes randomly throughout the page
//get the body element of the document
var body = document.getElementsByTagName("body")[0];
//store width and height of boxes
var boxWidth = 50;
var boxHeight = 50;
//create the random number for the boxes
var randNum = Math.floor(Math.random() * 500 + 1);
//create the boxes
for(var i=0;i<randNum;i++){
//create the random color and random positions
var colour = Math.round(0xffffff * Math.random()).toString(16);
var pos1 = Math.floor(Math.random() * window.innerWidth)
var pos2 = Math.floor(Math.random() * window.innerHeight)
// Define an array of css attributes
var attr =[
// Assign a colour to the box
'background-color:#' + colour,
// Place the box somewhere inside the window
'left:' + pos1 + 'px',
'top:' + pos2 + 'px',
// Set the box size
'width:' + boxWidth + 'px',
'height:' + boxHeight + 'px',
'cursor: pointer;',
'position:absolute;'
];
//join the attributes together
var attributes = attr.join(';');
//create a new div tag
var div = document.createElement("div");
//gives the box a unique id
div.setAttribute("id","box"+i)
//create the design of the box
div.setAttribute("style",attributes);
//add to the body
body.appendChild(div);
}
}
I really have no idea where to start...
Well a start would certainly be getting the mouse position, after that the world is your oyster.
var mousex = 0;
var mousey = 0;
function getXY(e){
if (!e) e = window.event;
if (e)
{
if (e.pageX || e.pageY)
{ // this doesn't work on IE6!! (works on FF,Moz,Opera7)
mousex = e.pageX;
mousey = e.pageY;
go = '[e.pageX]';
if (e.clientX || e.clientY) go += ' [e.clientX] '
}
else if (e.clientX || e.clientY)
{ // works on IE6,FF,Moz,Opera7
mousex = e.clientX + document.body.scrollLeft;
mousey = e.clientY + document.body.scrollTop;
go = '[e.clientX]';
if (e.pageX || e.pageY) go += ' [e.pageX] '
}
}
}
With the mouse info you can then do this in another function.
function moveBoxes(){
document.body.onmousemove = updater; //or some container div!
updater();
}
function updater(e){
getXY(e);
document.getElementById('aboxid').style.left=mousex+'px';
}
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
<head>
<title>MouseDown MouseUp</title>
<meta charset="UTF-8">
<style>
#insideBox{
height: 100px;
width: 100px;
background-color: black;
left:300px;
top:300px;
position:absolute;
}
</style>
<script>
var mouseFire = null;
window.onload = init;
function init(){
var div = document.getElementById("insideBox");
div.addEventListener("mousedown",mouseDrag,false);
}
function mouseDrag(e){
var evt = e || window.event;
mouseFire = evt.target || evt.srcElement;
document.addEventListener("mousemove",mouseMove,false);
document.addEventListener("mouseup",mouseDrop,false);
}
function mouseMove(e){
var evt = e || window.event;
var mouseX = evt.clientX;
var mouseY = evt.clientY;
mouseFire.style.left = mouseX-50+"px";
mouseFire.style.top = mouseY-50+"px";
}
function mouseDrop(e){
mouseFire = null;
document.removeEventListener("mousemove",mouseMove,false);
}
</script>
</head>
<body>
<div id="insideBox"></div>
</body>
</html>

not correctly adding the circle on the correct position in svg with viewbox?

I need to add the circle in the svg dynamically. Here its adding to the svg correctly but not in the correct position.
Here i create on circle inside the svg and get the x and y position by clicking on the svg to add the new circle. Its getting the clientX and clientY position correctly from the screen but the newly adding circle is not correctly adding to the correct position. I need to add the new circle on the svg on the selected position .
Here is the DEMO.
var xpos, ypos;
$("svg").click(function (e) {
xpos = e.clientX;
ypos = e.clientY;
alert(xpos+' '+ypos);
});
$("#create").click(function (e) {
var svgNS = "http://www.w3.org/2000/svg";
var myCircle = document.createElementNS(svgNS, "circle");
myCircle.setAttributeNS(null, "id", "mycircle");
myCircle.setAttributeNS(null, "fill", 'blue');
myCircle.setAttributeNS(null, "cx", xpos);
myCircle.setAttributeNS(null, "cy", ypos);
myCircle.setAttributeNS(null, "r", '6');
myCircle.setAttributeNS(null, "stroke", "none");
var svg = document.querySelector("svg");
svg.appendChild(myCircle);
});
any suggestions should be appreciated.
Something like this should do it.
$("#create").click(function (e) {
var svgNS = "http://www.w3.org/2000/svg";
var myCircle = document.createElementNS(svgNS, "circle");
myCircle.setAttributeNS(null, "id", "mycircle");
myCircle.setAttributeNS(null, "fill", 'blue');
myCircle.setAttributeNS(null, "r", '6');
myCircle.setAttributeNS(null, "stroke", "none");
var svg = document.querySelector("svg");
svg.appendChild(myCircle);
var pt = svg.createSVGPoint();
pt.x = xpos;
pt.y = ypos;
var globalPoint = pt.matrixTransform(myCircle.getScreenCTM().inverse());
var globalToLocal = myCircle.getTransformToElement(svg).inverse();
var inObjectSpace = globalPoint.matrixTransform(globalToLocal);
myCircle.setAttributeNS(null, "cx", inObjectSpace.x);
myCircle.setAttributeNS(null, "cy", inObjectSpace.y);
});
This question has more details. although its solution is not quite right.
The problem is coming from two things:
e.clientX and e.clientY are the position in the page. Hence not totally relevant the inside of the svg. To make that a valuable information, let's use jQuery offset. That gives the following coordinate in pixels:
var offset = $(this).offset();
xpos = e.clientX - offset.left;
ypos = e.clientY - offset.top;
The other problem comes from the way viewport and svg positioning interract. The fact is, with your settings we have a box of 200px*200px in which has the top left corner as the coordinate 0,-100 and the bottom right is 400,300.
To solve your problem, the solution I used is the following: adding a white rectangle in the background (this way the svg is effectively using all the space we're giving it). And use a slight translation to adjust to the svg coordinate, which is
xpos = (e.clientX - offset.left)*2;
ypos = (e.clientY - offset.top)*2 - 100;
See the updated fiddle here

Drawing a rectangle using click, mouse move, and click

I'm trying to draw a rectangle by a user click, mouse move, and click. There are two problems with my code.
Firstly, after one rectangle is drawn it is automatically assumed that another one will be drawn. Secondly, the starting point on the second rectangle is the last click that created the first rectangle.
http://jsbin.com/uqonuw/3/edit
You were close. So, the question isn't really about the "canvas" element in HTML5, but a canvas that is really a div.
http://jsfiddle.net/d9BPz/546/
In order for me to see what your code was trying to accomplish, I had to tidy it up. What needed to happen was tracking of the square element.
We are doing one of two things everytime we click on the canvas. We are either creating a rectangle element, or finishing a rectangle element. So, when we're finished it makes sense to set 'element' (previously named 'd') to null. When creating an element, we have to assign the new DOM element to 'element'.
Everytime the mouse moves, we want to get the mouse position. If the element is in the process of creation (or "not null"), then we need to resize the element.
Then we wrap it all up in a function, and that's all there is to it:
function initDraw(canvas) {
var mouse = {
x: 0,
y: 0,
startX: 0,
startY: 0
};
function setMousePosition(e) {
var ev = e || window.event; //Moz || IE
if (ev.pageX) { //Moz
mouse.x = ev.pageX + window.pageXOffset;
mouse.y = ev.pageY + window.pageYOffset;
} else if (ev.clientX) { //IE
mouse.x = ev.clientX + document.body.scrollLeft;
mouse.y = ev.clientY + document.body.scrollTop;
}
};
var element = null;
canvas.onmousemove = function (e) {
setMousePosition(e);
if (element !== null) {
element.style.width = Math.abs(mouse.x - mouse.startX) + 'px';
element.style.height = Math.abs(mouse.y - mouse.startY) + 'px';
element.style.left = (mouse.x - mouse.startX < 0) ? mouse.x + 'px' : mouse.startX + 'px';
element.style.top = (mouse.y - mouse.startY < 0) ? mouse.y + 'px' : mouse.startY + 'px';
}
}
canvas.onclick = function (e) {
if (element !== null) {
element = null;
canvas.style.cursor = "default";
console.log("finsihed.");
} else {
console.log("begun.");
mouse.startX = mouse.x;
mouse.startY = mouse.y;
element = document.createElement('div');
element.className = 'rectangle'
element.style.left = mouse.x + 'px';
element.style.top = mouse.y + 'px';
canvas.appendChild(element)
canvas.style.cursor = "crosshair";
}
}
}
Usage: Pass the block-level element that you would like to make a rectangle canvas.
Example:
<!doctype html>
<html>
<head>
<style>
#canvas {
width:2000px;
height:2000px;
border: 10px solid transparent;
}
.rectangle {
border: 1px solid #FF0000;
position: absolute;
}
</style>
</head>
<body>
<div id="canvas"></div>
<script src="js/initDraw.js"></script>
<script>
initDraw(document.getElementById('canvas'));
</script>
</body>
</html>
Here's how to click-move-click to create a rectangle
Create these variables:
var isDrawing=false;
var startX;
var startY;
In your mousedown event handler:
If this is the starting click, set the isDrawing flag and set the startX/Y.
If this is the ending click, clear the isDrawing flage and draw the rectangle.
You might also want to change the mouse cursor so the user knows they are drawing.
if(isDrawing){
isDrawing=false;
ctx.beginPath();
ctx.rect(startX,startY,mouseX-startX,mouseY-startY);
ctx.fill();
canvas.style.cursor="default";
}else{
isDrawing=true;
startX=mouseX;
startY=mouseY;
canvas.style.cursor="crosshair";
}
Here is a Fiddle: http://jsfiddle.net/m1erickson/7uNfW/
Instead of click-move-click, how about using drag to create a rectangle?
Create these variables:
var mouseIsDown=false;
var startX;
var startY;
In your mousedown event handler, set the mouseIsDown flag and set the startX/Y.
Optionally, change the cursor so the user knows their dragging a rectangle.
mouseIsDown=true;
startX=mouseX;
startY=mouseY;
canvas.style.cursor="crosshair";
In your mouseup event handler, clear the mouseIsDown flag and draw the rect
If you changed the cursor, change it back.
mouseIsDown=false;
ctx.beginPath();
ctx.rect(startX,startY,mouseX-startX,mouseY-startY);
ctx.fill();
canvas.style.cursor="default";
For those who encountered the scrolling problem, I've found a fix.
You need to get the offset (using window.pageYOffset) and reduce it from the mouse position in any of the recommended snippets given. You should take it off from the height as well.
i was also working on a project, so here's my code
enjoy.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Selection</title>
<script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
<style>
body {
margin: 0px;
background-color: #f1f1f1;
}
canvas {
border: none;
}
</style>
</head>
<body>
<canvas id="canvas" width="800" height="500"></canvas>
<div id="output"></div>
<script>
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var canvasx = $(canvas).offset().left;
var canvasy = $(canvas).offset().top;
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
//Mousedown
$(canvas).on('mousedown', function(e) {
last_mousex = parseInt(e.clientX-canvasx);
last_mousey = parseInt(e.clientY-canvasy);
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
mousedown = false;
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
//Mousemove
$(canvas).on('mousemove', function(e) {
mousex = parseInt(e.clientX-canvasx);
mousey = parseInt(e.clientY-canvasy);
if(mousedown) {
ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
ctx.beginPath();
var width = mousex-last_mousex;
var height = mousey-last_mousey;
ctx.rect(last_mousex,last_mousey,width,height);
//ctx.fillStyle = "#8ED6FF";
ctx.fillStyle = 'rgba(164, 221, 249, 0.3)'
ctx.fill();
ctx.strokeStyle = '#1B9AFF';
ctx.lineWidth = 1;
ctx.fillRect(last_mousex, last_mousey, width, height)
ctx.stroke();
}
//Output
$('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});
</script>
</body>
</html>
Below is the solution I created in React. There might be some corner cases but it is working as per my knowledge.
Solution approach.
You must have start (x,y position) and the end (x,y) position
Once the user clicks on the cell capture cell number and column number start (x,y), this will happen on the mouseDown event
Then the user starts moving the mouse, in that case capture the cell number and the row number end (x,y) respectively.
Now the div draw logic comes where the condition would highlight the cell if the below condition is true.
i = cellNumber
i >= Math.min(start,end) && i <= Math.max(start,end) && i%4 <= Math.max(startY, endY)
https://codesandbox.io/s/still-field-0q760y?file=/src/App.js

Get Element by Position determined in Z-Index - Javascript

I am using the following sentence to get the element in some position, but he takes the first ...
$(this.cTaskItem[0]).mouseup(function(event){
var posX = event.clientX, posY = event.clientY;
var overElem = document.elementFromPoint(posX, posY);
overElem.style.border = "3px solid red";
});
I wonder how do I get the element at a given position and Z-Index.
Thank You
If the first element (the one that's selected by document.elementFromPoint(posX, posY)) is not supposed to be clickable you can set the css prepoerty pointer-events: none; to it and it will not be selected anymore
As #t.niese suggested above you could do this:
$(this.cTaskItem[0]).mouseup(function(event)
{
var posX = event.clientX, posY = event.clientY;
var elements = [];
var elm = document.elementFromPoint(posX, posY);
while(elm.tagName != "HTML")
{
elements.push(elm);
elm.style.display = "none";
elm = document.elementFromPoint(posX, posY);
}
});
Then all you would need to do is go through your elements array and select the one you need.

Categories

Resources