Change url on image click - javascript

I insert an array of images using js, added same class to all images. Now I want to change url when click on image but I cant differentiate between the images can someone please help? For example when click on image1 it takes to a diff link, click on image2 takes to a different link.
here's the code below:
infoArray = [
{
"image": "001.jpg",
"title": "Jordan",
"text": ["Web Development"],
},
{
"image": "tri.jpg",
"title": "Last Night",
"text": ["Web Development"],
},
{
"image": "001.jpg",
"title": "Chatter",
"text": ["Web Development", "Web Design"],
},
]
function insertDiv(array, container) {
array.forEach(function (e, index) {
let div = document.createElement("div");
div.classList.add("box");
container.appendChild(div);
insertImages(array, div, index)
});
}
function insertImages(array, container, index) {
let img = new Image();
img.src = array[index]["image"];
img.classList.add("image");
container.appendChild(img);
insertTitle(array, container, index);
}
function insertTitle(array, container, index) {
let titleContainer = document.createElement("p");
titleContainer.classList.add("title");
let title = document.createTextNode(array[index]["title"]);
titleContainer.appendChild(title);
container.appendChild(titleContainer);
insertText(array, container, index);
}
function insertText(array, container, index) {
let textContainer = document.createElement("div");
textContainer.classList.add("textContainer");
array[index]["text"].forEach(function (e, i) {
let text = document.createElement("p");
let innerText = document.createTextNode(array[index]["text"][i]);
text.appendChild(innerText);
textContainer.appendChild(text);
})
container.appendChild(textContainer);
}
function FadeIn(img){
var ourScene = new ScrollMagic.Scene({
triggerElement: img,
triggerHook: 0.7,
reverse: true,
duration: "100%",
})
.on('start', function(){
TweenMax.to(img, 1, {opacity: 1, y:10})
})
.on('end', function(){
controllerInfo = controller.info("scrollDirection");
TweenMax.to(img, 1, {opacity: 0});
if ( controllerInfo == 'REVERSE'){
TweenMax.to(img, 1, {opacity: 1});
}
})
.addIndicators()
.addTo(controller);
}
function checkHovering(images){ //looks if hovering on img
images.forEach(function(image, index){
document.addEventListener("mousemove", function(e){
if(e.x>image.getBoundingClientRect().x
&& e.x<document.documentElement.clientWidth - image.getBoundingClientRect().x
&& e.y>image.getBoundingClientRect().y
&& e.y<image.getBoundingClientRect().y + image.getBoundingClientRect().height){
TweenMax.to(image, 1, {css: {scale: 1.02}});
appearTitle(index);
} else {
TweenMax.to(image, 0.5, {css: {scale: 1}});
disappearTitle(index);
}
})
})
}
function appearTitle(index){
currentTitles[index].style.opacity = 1;
currentText[index].style.opacity = 1;
}
function disappearTitle(index){
currentTitles[index].style.opacity = 0;
currentText[index].style.opacity = 0;
}
function clickImg(images){
images.forEach(function(image){
})
}
let container = document.querySelector(".container");
let controller = new ScrollMagic.Controller();
insertDiv(infoArray, container);
let currentTitles = document.querySelectorAll(".title");
let currentImages = document.querySelectorAll(".image");
let currentText = document.querySelectorAll(".textContainer");
currentImages.forEach(function(element){
FadeIn(element);
})
checkHovering(currentImages);

Related

Custom range slider does not work on mobile phone

I have a webpage with a custom price slider. For desktop it works just fine and when I check it in google developer tools for mobile, it works too, but when I open the webpage with my phone, slider stops working properly, it does not change the plan column. How can I debug something like that?
http://sagemailer-17.eugeneskom.com/
that's the code being used for the slider
window.onload = () => {
const init = function() {
const breakpoints = [{
value: 0,
step: 12.5,
stepsSoFar: 0
},
{
value: 200,
step: 50,
stepsSoFar: 16
},
{
value: 1000,
step: 50,
stepsSoFar: 32
},
{
value: 2000,
step: 500,
stepsSoFar: 52
},
{
value: 10000,
step: 1000,
stepsSoFar: 68
},
{
value: 30000,
step: 5000,
stepsSoFar: 88
},
{
value: 100000,
step: 10000,
stepsSoFar: 102
},
{
value: 300000,
step: 50000,
stepsSoFar: 122
},
{
value: 1000000,
stepsSoFar: 136,
step: 1
}
];
const pricing = [
[200, 4, 0.2],
[500, 10, 0.01],
[1000, 15, 0.01],
[2000, 20, 0.005],
[7000, 50, 0.005],
[10000, 65, 0.0025],
[16000, 80, 0.0022],
[25000, 100, 0.006],
[30000, 130, 0.002],
[65000, 200, 0.002],
[100000, 270, 0.0015],
[200000, 420, 0.0015],
[300000, 570, 0.0006],
[600000, 750, 0.0006],
[700000, 810, 0.0006],
[800000, 870, 0.0006],
[900000, 930, 0.0006],
[1000000, 990, 0.001]
];
const planBgs = document.querySelectorAll(".StepRangeSlider__trackHeadItem");
const media = window.matchMedia("(max-width: 1024px)");
const minValue = 200;
const maxStep = breakpoints[breakpoints.length - 1].stepsSoFar;
const slider = document.getElementById("stepRangeSliderWrap");
const handle = document.getElementById("rangeSliderHandle");
const tooltip = document.getElementById("rangeSliderTooltip");
const plans = document.querySelectorAll(".plan-content .right .content");
let plansBreakPoints;
let valueBlock;
let emailsBlock;
let isHorizontal;
let value = 200;
let step = 18;
let pressed = false;
const checkRangeSliderVersion = () => {
if (media.matches) {
valueBlock = document.querySelectorAll(".display-price-mob");
emailsBlock = document.querySelectorAll(".emails-count");
isHorizontal = false;
} else {
valueBlock = document.querySelectorAll(".display-price");
emailsBlock = document.querySelectorAll(".emails-count");
isHorizontal = true;
}
plansBreakPoints = [
planBgs[1].getBoundingClientRect()[isHorizontal ? "left" : "top"],
planBgs[2].getBoundingClientRect()[isHorizontal ? "left" : "top"]
];
};
checkRangeSliderVersion();
media.addListener(checkRangeSliderVersion);
const getPriceForEmailsCount = emails => {
for (let i = pricing.length - 1; i >= 0; i--) {
if (emails === pricing[i][0]) {
return pricing[i][1];
}
if (emails > pricing[i][0]) {
return (emails - pricing[i][0]) * pricing[i + 1][2] + pricing[i][1];
}
}
return null;
};
const getValueForStep = step => {
const nearest = breakpoints.reduce((prev, curr) =>
curr.stepsSoFar < step && curr.stepsSoFar > prev.stepsSoFar ?
curr :
prev
);
const additionalValue = (step - nearest.stepsSoFar) * nearest.step;
return nearest.value + additionalValue;
};
const handleChange = () => {
const offset = (step / maxStep) * 100;
handle.style[isHorizontal ? "left" : "top"] = offset + "%";
tooltip.textContent = Math.floor(value);
valueBlock.forEach(e => {
e.textContent = getPriceForEmailsCount(value) + "$";
});
emailsBlock.forEach(e => {
e.textContent = Math.floor(value);
});
};
const handleMove = e => {
const client = isHorizontal ? e.clientX : e.clientY;
const sliderRect = slider.getBoundingClientRect();
let startPosition = isHorizontal ? sliderRect.left : sliderRect.top;
let endPosition = isHorizontal ? sliderRect.right : sliderRect.bottom;
if (client <= plansBreakPoints[0]) {
plans.forEach(e => {
e.style.display = "none";
});
plans[0].style.display = "block";
} else if (
client >= plansBreakPoints[0] &&
client <= plansBreakPoints[1]
) {
plans.forEach(e => {
e.style.display = "none";
});
plans[1].style.display = "block";
} else if (client >= plansBreakPoints[1]) {
plans.forEach(e => {
e.style.display = "none";
});
plans[2].style.display = "block";
}
if (!client) return;
let position;
if (client < startPosition) {
position = 0;
} else if (client > endPosition) {
position = endPosition - startPosition;
} else {
position = client - startPosition;
}
const currentStep = Math.round(
(position / (isHorizontal ? sliderRect.width : sliderRect.height)) *
maxStep
);
const currentStepValue = getValueForStep(currentStep);
if (
currentStepValue >= minValue &&
(currentStepValue !== value || currentStep !== step)
) {
value = currentStepValue;
step = currentStep;
handleChange();
}
};
const handleTouchMove = e => {
if (pressed) {
handleMouseMove(e.touches[0]);
}
};
const handleMouseUp = e => {
if (pressed) {
pressed = false;
}
};
const handleMouseMove = e => {
if (pressed) {
handleMove(e);
}
};
window.addEventListener("touchmove", handleTouchMove);
window.addEventListener("touchend", handleMouseUp);
window.addEventListener("mousemove", handleMouseMove);
window.addEventListener("mouseup", handleMouseUp);
slider.addEventListener("mousedown", function(e) {
e.preventDefault();
pressed = true;
handleMove(e);
});
slider.addEventListener("touchmove", e => {
e.preventDefault();
pressed = true;
handleMove(e.touches[0]);
});
handle.addEventListener("mousedown", function(e) {
e.preventDefault();
pressed = true;
handleMove(e);
});
handle.addEventListener("ontouchstart", function(e) {
e.preventDefault();
pressed = true;
handleMove(e.touches[0]);
});
};
init();
};

create second thread (web-worker) to run complex function of force layout graph outside of main thread in react

Hi everyone I created a network graph using Pixi and d3 and my graph is to slow for that I have to work complex functions in the second thread
here is App.js
import './App.css';
import { ForceGraph } from './components/forceGraph';
import data from './data/data.json';
import React from 'react';
function App() {
const nodeHoverTooltip = React.useCallback((node) => {
return `<div>
<b>${node.name}</b>
</div>`;
}, []);
return (
<div className="App">
<ForceGraph
linksData={data.links}
nodesData={data.nodes}
nodeHoverTooltip={nodeHoverTooltip}
/>
</div>
);
}
export default App;
here is forceGraph.js
import React from 'react';
import { runForceGraphPixi } from './forceGraphGeneratorPixi';
import styles from './forceGraph.module.css';
export function ForceGraph({ linksData, nodesData, nodeHoverTooltip }) {
const containerRef = React.useRef(null);
React.useEffect(() => {
if (containerRef.current) {
runForceGraphPixi(
containerRef.current,
linksData,
nodesData,
nodeHoverTooltip
);
}
}, [linksData, nodesData, nodeHoverTooltip]);
return <div ref={containerRef} className={styles.container} />;
}
here is forceGraphGeneratorPixi.js
import * as d3 from 'd3';
import * as PIXI from 'pixi.js';
import { Viewport } from 'pixi-viewport';
import styles from './forceGraph.module.css';
export function runForceGraphPixi(
container,
linksData,
nodesData,
nodeHoverTooltip
) {
const links = linksData.map((d) => Object.assign({}, d));
const nodes = nodesData.map((d) => Object.assign({}, d));
const containerRect = container.getBoundingClientRect();
const height = containerRect.height;
const width = containerRect.width;
let dragged = false;
container.innerHTML = '';
const color = () => {
return '#f0f8ff';
};
// Add the tooltip element to the graph
const tooltip = document.querySelector('#graph-tooltip');
if (!tooltip) {
const tooltipDiv = document.createElement('div');
tooltipDiv.classList.add(styles.tooltip);
tooltipDiv.style.opacity = '0';
tooltipDiv.id = 'graph-tooltip';
document.body.appendChild(tooltipDiv);
}
const div = d3.select('#graph-tooltip');
const addTooltip = (hoverTooltip, d, x, y) => {
div.transition().duration(200).style('opacity', 0.9);
div
.html(hoverTooltip(d))
.style('left', `${x}px`)
.style('top', `${y - 28}px`);
};
const removeTooltip = () => {
div.transition().duration(200).style('opacity', 0);
};
const colorScale = (num) => parseInt(color().slice(1), 16);
const app = new PIXI.Application({
width,
height,
antialias: !0,
transparent: !0,
resolution: 1,
});
container.appendChild(app.view);
// create viewport
const viewport = new Viewport({
screenWidth: width,
screenHeight: height,
worldWidth: width * 4,
worldHeight: height * 4,
passiveWheel: false,
interaction: app.renderer.plugins.interaction, // the interaction module is important for wheel to work properly when renderer.view is placed or scaled
});
app.stage.addChild(viewport);
// activate plugins
viewport
.drag()
.pinch()
.wheel()
.decelerate()
.clampZoom({ minWidth: width / 4, minHeight: height / 4 });
const simulation = d3
.forceSimulation(nodes)
.force(
'link',
d3
.forceLink(links) // This force provides links between nodes
.id((d) => d.id) // This sets the node id accessor to the specified function. If not specified, will default to the index of a node.
.distance(50)
)
.force('charge', d3.forceManyBody().strength(-500)) // This adds repulsion (if it's negative) between nodes.
.force('center', d3.forceCenter(width / 2, height / 2))
.force(
'collision',
d3
.forceCollide()
.radius((d) => d.radius)
.iterations(2)
)
.velocityDecay(0.8);
/*
Implementation
*/
let visualLinks = new PIXI.Graphics();
viewport.addChild(visualLinks);
nodes.forEach((node) => {
const { name, gender } = node;
node.gfx = new PIXI.Graphics();
node.gfx.lineStyle(1, 0xd3d3d3);
node.gfx.beginFill(colorScale(node.id));
node.gfx.drawCircle(0, 0, 24);
node.gfx.endFill();
node.gfx
// events for click
.on('click', (e) => {
if (!dragged) {
e.stopPropagation();
}
dragged = false;
});
viewport.addChild(node.gfx);
node.gfx.interactive = true;
node.gfx.buttonMode = true;
// create hit area, needed for interactivity
node.gfx.hitArea = new PIXI.Circle(0, 0, 24);
// show tooltip when mouse is over node
node.gfx.on('mouseover', (mouseData) => {
addTooltip(
nodeHoverTooltip,
{ name },
mouseData.data.originalEvent.pageX,
mouseData.data.originalEvent.pageY
);
});
// make circle half-transparent when mouse leaves
node.gfx.on('mouseout', () => {
removeTooltip();
});
const text = new PIXI.Text(name, {
fontSize: 12,
fill: '#000',
});
text.anchor.set(0.5);
text.resolution = 2;
node.gfx.addChild(text);
});
const ticked = () => {
nodes.forEach((node) => {
let { x, y, gfx } = node;
gfx.position = new PIXI.Point(x, y);
});
for (let i = visualLinks.children.length - 1; i >= 0; i--) {
visualLinks.children[i].destroy();
}
visualLinks.clear();
visualLinks.removeChildren();
visualLinks.alpha = 1;
links.forEach((link) => {
let { source, target, number } = link;
visualLinks.lineStyle(2, 0xd3d3d3);
visualLinks.moveTo(source.x, source.y);
visualLinks.lineTo(target.x, target.y);
});
visualLinks.endFill();
};
// Listen for tick events to render the nodes as they update in your Canvas or SVG.
simulation.on('tick', ticked);
return {
destroy: () => {
nodes.forEach((node) => {
node.gfx.clear();
});
visualLinks.clear();
},
};
}
here is forceGraph.module.css
.container {
width: 100%;
height: 80vh;
position: relative;
background-color: white;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.6);
}
.container svg {
display: block;
width: 100%;
height: 100%;
}
.male {
fill: rgb(22, 130, 218);
}
.female {
fill: rgb(246, 0, 0);
}
.node text {
font: 12px sans-serif;
}
div.tooltip {
position: absolute;
text-align: center;
width: 110px;
padding: 10px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0;
border-radius: 8px;
pointer-events: none;
}
.contextMenu {
stroke: #00557d;
fill: #ffffff;
}
.menuEntry {
cursor: pointer;
}
.menuEntry text {
font-size: 12px;
stroke: #00557d;
}
here is my data.json
{
"nodes": [
{
"id": 1,
"name": "Andy",
"gender": "male"
},
{
"id": 2,
"name": "Betty",
"gender": "female"
},
{
"id": 3,
"name": "Cate",
"gender": "female"
},
{
"id": 4,
"name": "Dave",
"gender": "male"
},
{
"id": 5,
"name": "Ellen",
"gender": "female"
},
{
"id": 6,
"name": "Fiona",
"gender": "female"
},
{
"id": 7,
"name": "Garry",
"gender": "male"
},
{
"id": 8,
"name": "Holly",
"gender": "female"
},
{
"id": 9,
"name": "Iris",
"gender": "female"
},
{
"id": 10,
"name": "Jane",
"gender": "female"
}
],
"links": [
{
"source": 1,
"target": 2
},
{
"source": 1,
"target": 5
},
{
"source": 1,
"target": 6
},
{
"source": 2,
"target": 3
},
{
"source": 2,
"target": 7
}
,
{
"source": 3,
"target": 4
},
{
"source": 8,
"target": 3
}
,
{
"source": 4,
"target": 5
}
,
{
"source": 4,
"target": 9
},
{
"source": 5,
"target": 10
}
]
}
After this I'm getting result
After this i add worker.js,and while I'm importing any other library inside worker.js I'm getting some error but I fixed that one also and the code is below
deep-thought.js(worker)
import addition from './addition';
import * as d3 from 'd3';
/* eslint-disable no-restricted-globals */
self.onmessage = (question) => {
const reciveData = question.data;
const nodes = question.data.nodes;
const links = question.data.links;
console.log(nodes);
console.log(links);
console.log(reciveData);
const result = addition(42);
self.postMessage({
result: result,
});
};
updated forceGraphGeneratorPixi.js
import * as d3 from 'd3';
import * as PIXI from 'pixi.js';
import { Viewport } from 'pixi-viewport';
import styles from './forceGraph.module.css';
export function runForceGraphPixi(
container,
linksData,
nodesData,
nodeHoverTooltip
) {
const links = linksData.map((d) => Object.assign({}, d));
const nodes = nodesData.map((d) => Object.assign({}, d));
const containerRect = container.getBoundingClientRect();
const height = containerRect.height;
const width = containerRect.width;
let dragged = false;
container.innerHTML = '';
const color = () => {
return '#f0f8ff';
};
// Pass data to web-worker
const worker = new Worker(new URL('../deep-thought.js', import.meta.url));
worker.postMessage({
nodes: nodes,
links: links,
});
worker.onmessage = ({ data: { answer } }) => {
console.log(answer);
};
// Add the tooltip element to the graph
const tooltip = document.querySelector('#graph-tooltip');
if (!tooltip) {
const tooltipDiv = document.createElement('div');
tooltipDiv.classList.add(styles.tooltip);
tooltipDiv.style.opacity = '0';
tooltipDiv.id = 'graph-tooltip';
document.body.appendChild(tooltipDiv);
}
const div = d3.select('#graph-tooltip');
const addTooltip = (hoverTooltip, d, x, y) => {
div.transition().duration(200).style('opacity', 0.9);
div
.html(hoverTooltip(d))
.style('left', `${x}px`)
.style('top', `${y - 28}px`);
};
const removeTooltip = () => {
div.transition().duration(200).style('opacity', 0);
};
const colorScale = (num) => parseInt(color().slice(1), 16);
const app = new PIXI.Application({
width,
height,
antialias: !0,
transparent: !0,
resolution: 1,
});
container.appendChild(app.view);
// create viewport
const viewport = new Viewport({
screenWidth: width,
screenHeight: height,
worldWidth: width * 4,
worldHeight: height * 4,
passiveWheel: false,
interaction: app.renderer.plugins.interaction, // the interaction module is important for wheel to work properly when renderer.view is placed or scaled
});
app.stage.addChild(viewport);
// activate plugins
viewport
.drag()
.pinch()
.wheel()
.decelerate()
.clampZoom({ minWidth: width / 4, minHeight: height / 4 });
const simulation = d3
.forceSimulation(nodes)
.force(
'link',
d3
.forceLink(links) // This force provides links between nodes
.id((d) => d.id) // This sets the node id accessor to the specified function. If not specified, will default to the index of a node.
.distance(50)
)
.force('charge', d3.forceManyBody().strength(-500)) // This adds repulsion (if it's negative) between nodes.
.force('center', d3.forceCenter(width / 2, height / 2))
.force(
'collision',
d3
.forceCollide()
.radius((d) => d.radius)
.iterations(2)
)
.velocityDecay(0.8);
/*
Implementation
*/
let visualLinks = new PIXI.Graphics();
viewport.addChild(visualLinks);
nodes.forEach((node) => {
const { name, gender } = node;
node.gfx = new PIXI.Graphics();
node.gfx.lineStyle(1, 0xd3d3d3);
node.gfx.beginFill(colorScale(node.id));
node.gfx.drawCircle(0, 0, 24);
node.gfx.endFill();
node.gfx
// events for click
.on('click', (e) => {
if (!dragged) {
e.stopPropagation();
}
dragged = false;
});
viewport.addChild(node.gfx);
node.gfx.interactive = true;
node.gfx.buttonMode = true;
// create hit area, needed for interactivity
node.gfx.hitArea = new PIXI.Circle(0, 0, 24);
// show tooltip when mouse is over node
node.gfx.on('mouseover', (mouseData) => {
addTooltip(
nodeHoverTooltip,
{ name },
mouseData.data.originalEvent.pageX,
mouseData.data.originalEvent.pageY
);
});
// make circle half-transparent when mouse leaves
node.gfx.on('mouseout', () => {
removeTooltip();
});
const text = new PIXI.Text(name, {
fontSize: 12,
fill: '#000',
});
text.anchor.set(0.5);
text.resolution = 2;
node.gfx.addChild(text);
});
const ticked = () => {
nodes.forEach((node) => {
let { x, y, gfx } = node;
gfx.position = new PIXI.Point(x, y);
});
for (let i = visualLinks.children.length - 1; i >= 0; i--) {
visualLinks.children[i].destroy();
}
visualLinks.clear();
visualLinks.removeChildren();
visualLinks.alpha = 1;
links.forEach((link) => {
let { source, target, number } = link;
visualLinks.lineStyle(2, 0xd3d3d3);
visualLinks.moveTo(source.x, source.y);
visualLinks.lineTo(target.x, target.y);
});
visualLinks.endFill();
};
// Listen for tick events to render the nodes as they update in your Canvas or SVG.
simulation.on('tick', ticked);
return {
destroy: () => {
nodes.forEach((node) => {
node.gfx.clear();
});
visualLinks.clear();
},
};
}
addition.js(perform simple addition in web-worker)
const addition = (data) => {
const result = data + 1;
return result;
};
export default addition;
so i perform simple addition using web-worker but now i want to perform simulation and tick function in webWorker and after performing i want to use it in my code to replace complex function because i'm new to web-worker i'm not figure-out how to do that

Node.js Canvas image overlapping issue / canvas is creating image on top of previous image

I'm having an issue with Canvas when trying to create a generated collection of .png images.
I can create the .png files fine but the first image or the image before is not being cleared.
index.js
const fs = require("fs");
const { createCanvas, loadImage } = require("canvas");
const canvas = createCanvas(1000,1000);
const ctx = canvas.getContext("2d");
const edition = 10;
const {layers,width,height} = require("./input/config.js");
const saveLayer = (_canvas, _edition) => {
fs.writeFileSync(`./output/${_edition}.png`, _canvas.toBuffer("image/png"));
};
const drawLayer = async (_layer, _edition) => {
let element = _layer.elements[Math.floor(Math.random() * _layer.elements.length)];
const image = await loadImage(`${_layer.location}${element.fileName}`);
ctx.drawImage(
image,
_layer.position.x,
_layer.position.y,
_layer.size.width,
_layer.size.height
);
console.log(`I created the ${_layer.name} layer, and chose element ${element.name}`);
saveLayer(canvas, _edition);
};
for(let i = 0; i <= edition; i++){
layers.forEach(layer => {
drawLayer(layer, i);
});
console.log("Creating edition " + i);
};
config.js
const fs = require("fs");
const width = 1000;
const height = 1000;
const dir = __dirname;
const rarity = [
{key: "", val: "original" },
{key: "_r", val: "rare" },
{key: "_sr", val: "super rare" },
];
const addRarity = (_str) => {
let itemRarity;
rarity.forEach((r) => {
if (_str.includes(r.key)){
itemRarity = r.val;
}
});
return itemRarity;
};
const cleanName = (_str) => {
let name = _str.slice(0, -4);
return name;
};
const getElements = (path) => {
return fs
.readdirSync(path)
//.filter((item) => !/(^|\/)\.|^\/\.|/g.test(item))
.map((i,index) => {
return {
id: index,
name: cleanName(i),
fileName: i,
rarity: addRarity(i),
};
});
};
const layers = [
{
id: 1,
name: "0",
location: `${dir}/0/`,
elements: getElements(`${dir}/0/`),
position: {x:0, y:0},
size: {width: width, height: height},
},
{
id: 2,
name: "1",
location: `${dir}/1/`,
elements: getElements(`${dir}/1/`),
position: {x:0, y:0},
size: {width: width, height: height},
},
{
id: 3,
name: "2",
location: `${dir}/2/`,
elements: getElements(`${dir}/2/`),
position: {x:0, y:0},
size: {width: width, height: height},
},
{
id: 4,
name: "3",
location: `${dir}/3/`,
elements: getElements(`${dir}/3/`),
position: {x:0, y:0},
size: {width: width, height: height},
},
{
id: 5,
name: "4",
location: `${dir}/4/`,
elements: getElements(`${dir}/4/`),
position: {x:0, y:0},
size: {width: width, height: height},
},
];
//console.log(layers);
module.exports = {layers,width,height};
The code is working fine and I'm able to create 10 .png files.
From the images above you can see the blue hat from Image 1 is still showing in Image 2.
Edit: What I've tried -
ctx.beginPath();
context.clearRect(0, 0, canvas.width, canvas.height);
const createNFTs = async() =>{
for(let i = 1; i <= edition; i++){
for (const layer of layers) await drawLayer(layer, i);
console.log("Creating edition " + i);
};
};
Final Code:
for(let i = 1; i <= edition; i++){
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const layer of layers) await drawLayer(layer, i);
console.log("Creating edition " + i);
};
You have a forEach calling an async function.
forEach and async do not go together: the forEach is drawing the next image before the previous one is finished
Replace
layers.forEach(layer => {
drawLayer(layer, i);
});
with
for (const layer of layers) {
await drawLayer(layer, i);
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
(adding clear)
and put it in an async function

An array of prices that represents 3 different prices for the same product

I am trying to create an array that represents three different merchants which hold different prices for the same products(represented later in the code which ones).
My logic seems off and I would like help with one example on how this should be done correctly.
Attached is my code but please take notice only to the Merchantprices and getRecipeItems part.
JS
var main = function () {
var recipeType = {
0: {"name": "cocktail", "ingredients": ["Booz","Roofis","Green Stuff"]},
1: {"name": "appetizer", "ingredients": ["Some leaves","Some veggies", "I dunno toast","Cheese or whatever"]},
2: {"name": "main course", "ingredients": ["A dead animal","its blood", "some potatoes","love","asparagus"]} ,
3: {"name": "dessert", "ingredients": ["Dough","Some Sprinkly shit", "sugar","more sugar","cream shaboogy pop"]} ,
}
var Merchantprices = {
ampm:{"ingredientPrice":recipeType[0].ingredients = 20,"sumPrice":recipeType[0] = ingredientPrice * (recipeType[0].ingredients.length)},
haCarmel:{},
tivTaam:{},
}
function getRecipeItems() {
return recipeItems = [
{
"id": "recipe0",
"title": "Grasshopper Cocktail",
"img": "../images/grasshopper-cocktail.jpg",
"ingredients": recipeType[0].ingredients,
"instructions":"shaken not stirred",
"price": {"ampmPrice":Merchantprices[0].sumPrice,"haCarmelPrice":Merchantprices[1].sumPrice,"tivTaamPrice":Merchantprices[2].sumPrice},
"type" : recipeType[0].name,
},
{
"id": "recipe1",
"title": "Beef roast with veggies",
"img": "../images/beef-roast-with-veggies.JPG",
"ingredients": recipeType[2].ingredients,
"instructions":"stuff it good",
"price": 55,
"type" : recipeType[2].name,
},
{
"id": "recipe2",
"title": "Shrimp-Fried-Rice",
"img": "../images/Shrimp-Fried-Rice.jpg",
"ingredients": recipeType[1].ingredients,
"instructions":"extra MSG",
"price": 65,
"type" : recipeType[1].name,
},
{
"id": "recipe3",
"title": "Cupcake from hell",
"img": "../images/Cupcake-Idea-pics-200x150.png",
"ingredients": recipeType[3].ingredients,
"instructions":"death is inevitable",
"price": 15,
"type" : recipeType[3].name,
},
]
}
function createRecipeItem(recipeItem) {
var recipeElement = document.createElement('div');
recipeElement.setAttribute("id", recipeItem.id);
recipeElement.setAttribute("class", recipeItem);
recipeDetailsElement = document.createElement("div");
recipeDetailsElement.setAttribute("id", recipeItem.id+"_details");
recipeDetailsElement.appendChild(createDeleteRecipe(recipeItem));
recipeDetailsElement.appendChild(createRecipePic(recipeItem));
recipeDetailsElement.appendChild(createRecipeTitle(recipeItem));
recipePreperationElement = document.createElement("div");
recipePreperationElement.setAttribute("id", recipeItem.id+"_full_details");
recipePreperationElement.appendChild(createRecipeIngredients(recipeItem));
recipePreperationElement.appendChild(createRecipeInstructions(recipeItem));
recipePreperationElement.style.display = 'none';
recipeDetailsElement.appendChild(recipePreperationElement);
recipeElement.appendChild(createUndoDeleteRecipe(recipeItem));
recipeElement.appendChild(recipeDetailsElement);
return recipeElement;
}
function createUndoDeleteRecipe(recipeItem) {
var undoButton = document.createElement('span');
undoButton.setAttribute("id", recipeItem.id + "_undo");
undoButton.setAttribute("class", "fa fa-undo", "aria-hidden", "true");
$(undoButton).hide();
$(undoButton).click(() => {
onItemDeleteUndo(recipeItem);
});
return undoButton;
}
function createDeleteRecipe(recipeItem) {
var deleteButton = document.createElement('span');
deleteButton.setAttribute("class", "fa fa-times-circle", "aria-hidden", "true");
$(deleteButton).click(() => {
onItemDelete(recipeItem);
});
return deleteButton;
}
function onItemDelete(recipeItem) {
$('#'+recipeItem.id+'_details').hide();
$('#'+recipeItem.id+'_undo').show();
}
function onItemDeleteUndo(recipeItem) {
$('#'+recipeItem.id+'_details').show();
$('#'+recipeItem.id+'_undo').hide();
}
function createRecipeTitle(recipeItem) {
var div = document.createElement('div');
div.innerHTML = recipeItem.title;
return div;
}
function createRecipeInstructions(recipeItem) {
var div = document.createElement('div');
div.innerHTML = recipeItem.instructions;
return div;
}
function createRecipePic(recipeItem) {
var recipePic = document.createElement("img");
recipePic.setAttribute("src", recipeItem.img);
recipePic.setAttribute("class", "recipe");
$(recipePic).css('margin-top', '10px');
$(recipePic).click(() => {
$('#'+recipeItem.id+"_full_details").slideToggle();
});
return recipePic;
}
function createRecipeIngredients(recipeItem) {
var ingredients = document.createElement("ul");
ingredients.setAttribute("id", recipeItem.id + "_ingredients");
ingredients.className = "ingredientsList";
recipeItem.ingredients.forEach(ingredient => {
var li = document.createElement("li");
li.className = "ingredients";
li.setAttribute("type", "checkbox");
var checkbox = document.createElement("input");
checkbox.setAttribute("type", "checkbox");
li.appendChild(checkbox);
var ingredientElement = document.createElement("a");
ingredientElement.innerHTML = ingredient;
li.appendChild(ingredientElement);
ingredients.appendChild(li);
})
return ingredients;
}
recipeItems = getRecipeItems();
var mainContainer = document.getElementsByClassName('mainContainer');
recipeItems.forEach(recipeItem => {
mainContainer[0].appendChild(createRecipeItem(recipeItem));
});
};
var recipeItems;
var Merchantprices;
$(document).ready(main);
Ok, so I think I got want you meant to do. Here are 2 solutions :
Keep all in one place
function getRecipeItems() {
return recipeItems = [
{
"id": "recipe0",
// ...
"price": {
default: 8,
ampm: 10,
// -- haCarmel: 12, -- Let's omit this one
tivTaam: 15,
get: function( merchant ) {
return this[merchant] ? this[merchant] : default;
}
}
},
// ...
]
}
// ---------------------------------------
// Usage
// ---------------------------------------
// Result : 8 (default price, as you didn't specify the merchant).
getRecipeItems()[0].price.get();
// Result : 10.
getRecipeItems()[0].price.get("ampm");
// Result : 8 (default, as you didn't set this value).
getRecipeItems()[0].price.get("haCarmel");
Merchant's magic calculations
You could also set a default price, but send it to the merchant and alter it.
// Price
"price": {
default: 8,
get: function( merchant ) {
return Merchants[ merchant ]
? Merchants[ merchant ].getPrice( this.default )
: this.default;
}
}
// Merchants
Merchants {
ampm: {
//...
getPrice: function( price ){
return price + itemRarity - discount + etc;
}
},
// ...
};
In both cases, ...
You should create an object for the Merchant, RecipeItem and RecipeItemPrice. Your code will be more clean and you wouldn't create an instance of the get() function each time you create a price. Well, you should do that with ALL your game objects. :)
// Price
var RecipeItemPrice = function( value, ... ) {
this.default = value;
};
RecipeItemPrice.prototype.get = function() {
// For example, if you take the second choice :
return Merchants[ merchant ]
? Merchants[ merchant ].getPrice( this.default )
: this.default;
};

check for an existing product

I have an issue about checking for an existing product in knockoutjs.
The problem is: if the product exists in Cart Line, the product quantity will increase, if not, it will be added to Cart
This is code:
var CartLine = function (productid,productName, price, quantity) {
var self = this;
self.resultId = ko.observable(productid);
self.resultProduct = ko.observable(productName);
self.resultPrice = ko.observable(price);
self.resultQuantity = ko.observable(quantity || 1);
self.subtotal = ko.computed(function () {
return self.resultPrice() * self.resultQuantity();
});
};
$('#addProduct').click(function (line) {
var context = ko.contextFor(this);
var existing = self.find(line.resultId);
var lines = self.lines();
if (existing) {
existing.resultQuantity = existing.resultQuantity() + context.$data.Quantity();
}else{
existing = new CartLine(self.product().productid, self.product().name, self.product().price, context.$data.Quantity());
self.lines.push(existing);
}
return existing;
});
self.find = function (productid) {
return ko.utils.arrayFirst(self.lines(), function (line) {
return line.resultId === productid;
});
};
This is the full code: http://jsfiddle.net/pf9hd3Lg/2/
There are a number of errors with the code you have listed above. The below should work for the scenario you described. I have tried to comment my changes in the code below.
var CartLine = function (productid,productName, price, quantity) {
var self = this;
self.resultId = ko.observable(productid);
self.resultProduct = ko.observable(productName);
self.resultPrice = ko.observable(price);
self.resultQuantity = ko.observable(quantity || 1);
self.subtotal = ko.computed(function () {
return self.resultPrice() * self.resultQuantity();
});
};
var Cart = function() {
var self = this;
self.products = ko.observableArray([{
"productid": "1",
"name": "CAPUCINO ",
"price": 170
},
{
"productid": "2",
"name": "Sữa bò tươi",
"price": 140
}
,
{
"productid": "3",
"name": "Phô mai mặn",
"price": 170
}, {
"productid": "4",
"name": "Bơ đậu phộng ",
"price": 150
},
{
"productid": "5",
"name": "Bạc Hà",
"price": 160
},
{
"productid": "6",
"name": "Dâu Tây",
"price": 160
}
]);
self.product = ko.observable("");
self.Quantity = ko.observable(1).extend({ numeric: 0 });
self.price = ko.observable();
self.productid = ko.observable("");
self.lines = ko.observableArray();
self.grandTotal = ko.pureComputed(function () {
var total = 0;
$(self.lines()).each(function (index, line) { total += line.subtotal() })
return total;
});
$('#addProduct').click(function (line) {
var context = ko.contextFor(this);
var existing = self.find();
var lines = self.lines();
if (existing) {
//existing.resultQuantity is also an observable and should be set this way and not with the = operator
existing.resultQuantity(existing.resultQuantity() + context.$data.Quantity());
}else{
existing = new CartLine(self.product().productid, self.product().name, self.product().price, context.$data.Quantity());
self.lines.push(existing);
}
return existing;
});
self.removeProduct = function (line,event) {
self.lines.remove(line);
};
self.find = function () {
return ko.utils.arrayFirst(self.lines(), function (line) {
//resultId is an observable
//self.product().productid is what you are interested in, no need to pass it into the function
return line.resultId() === self.product().productid;
});
};
}
ko.applyBindings(new Cart());

Categories