I have seen similar questions on StackOverflow, but none of the answers have helped me so far.
I am using chart.js in my web project, but now, when I want to show 2 line graphs in the same container they do weird stuff, even if I adjust the parent container or try to wrap the canvas with a div.
here is some of the code:
[...]
<!--the big white container-->
<div class="Card Fill" id="5da78c0de214b0020e86f53a">
<div class="Details">
<span>entradas:30</span>
<span>duracion: 0:02</span>
</div>
<div class="ChartContainer">
<div class="ChartWraper">
<canvas id="tempGraph"></canvas>
</div>
<div class="ChartWraper">
<canvas id="ppmGraph"></canvas>
</div>
</div>
</div>
[...]
function drawChart(canvas, datasetLabel, data, labels) {
window[datasetLabel] = new Chart(
document.getElementById(canvas),
{
type: 'line',
data: {
datasets: [
{
lineTension: 0.1,
label: datasetLabel,
fill: true,
data: data
}
],
labels: labels
},
options: {
scales: {
xAxes: [{
display: true
}]
}
}
}
);
}
//ask api for data array
window.onload = function () {
let droneId = document.getElementsByClassName("Card")[0].id;
axios.get(`/api/vuelos/data/${droneId}`)
.then((response) => {
responseData = response.data;
let factorized = refractor(response.data); //separate the data from the drone into arrays
drawChart("tempGraph", "temperatura", factorized.temp, factorized.labels);
drawChart("ppmGraph", "particulas por millon", factorized.ppm, factorized.labels);
})
.catch((error) => {
alert(error.message);
console.log(error);
});
}
.Card {
position: relative; /* soo that i can relocate the options inside*/
background: var(--background);
padding: 30px;
border-radius: 15px;
margin: 10px;
box-shadow: var(--ui-shawdow);
}
.Fill{
width: 100%;
height: 100%;
}
.Card > .Details {
padding: 10px;
display: flex;
flex-direction: column;
align-content: space-around;
}
.ChartContainer{
display: flex;
flex-direction: column;
align-content: space-between;
height: 50%;
}
.ChartWraper{
height: 40%;
width: 100%;
}
canvas{
height: 40%;
}
What may I be doing wrong? I have tried changing things at the CSS or the Html but does not seem to work
I want it to look moething like this, responsive withouth overflow out of the card.
Related
I'm actually coding an infinite slider in vuejs (using Nuxt 3 RC.10) and I'm facing a problem : my scrollLeft don't want to be reset.
Let me explain. I got two rows of images, and when the left side of the second row collides with the left side of the container, I want to set the scrollLeft to 0. This works perfectly on both browser with Svelte, but I did not succeed with Vuejs. For some reason the second row is glitching.
After debuging, my condition is comes true but the problem seems to come from instruction slider.value.scrollLeft = 0
Thanks in advance for your help
Here my component Slider:
(PS: the commented overflow: hidden is for test purposes.
<script setup>
const slider = ref(null)
const scrollEnabled = ref(true)
const centeredComputed = computed(() => {
return scrollEnabled.value ? "" : "justify-content: center;"
})
function scroll() {
let rows = document.getElementsByClassName('row')
slider.value.scrollLeft += 20
if (scrollEnabled.value && rows[1].getBoundingClientRect().left <= slider.value.getBoundingClientRect().left) {
slider.value.scrollLeft = 0
}
scrollEnabled.value = rows[0].clientWidth > slider.value.clientWidth
}
onMounted(() => {
slider.value.addEventListener('scroll', scroll)
window.addEventListener('load', scroll)
window.addEventListener('resize', scroll)
})
onUnmounted(() => {
window.removeEventListener('load', scroll)
window.removeEventListener('resize', scroll)
})
</script>
<template>
<div ref="slider" class="slider" :style="centeredComputed">
<div class="row">
<img v-for="id in 32" class="logo" :src="`../assets/images/partenaires/${id}.png`" :alt="'Partenaire numéro ' + id">
</div>
<div v-if="scrollEnabled" class="row">
<img v-for="id in 32" class="logo" :src="`../assets/images/partenaires/${id}.png`" :alt="'Partenaire numéro ' + id">
</div>
</div>
</template>
<style lang='scss' scoped>
.slider {
width: 100%;
height: 100%;
white-space: nowrap;
//overflow-x: hidden;
overflow: auto;
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: flex-start;
}
.row {
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: flex-start;
height: 100%;
}
.logo {
display: inline-flex;
margin: 0 2rem;
height: 100%;
}
</style>
index.html
<!--FIRST PIZZA---FIRST CHUNK OF HTML CODE-->
<div class="column-pizza-1">
<a href="">
<div class="pizza-item--img">
<img src="" id="pizza-img-1" />
</div>
<div class="pizza-item--add" id="selected-1">Add</div>
</a>
<div class="pizza-item--price" id="pizza-price-1">Rs. --</div>
<div class="pizza-item--name" id="pizza-name-1">--</div>
<div class="pizza-item--desc" id="pizza-desc-1">--</div>
</div>
<!--SECOND PIZZA---SECOND CHUNK OF HTML CODE-->
<div class="column-pizza-2">
<a href="">
<div class="pizza-item--img">
<img src="" id="pizza-img-2" />
</div>
<div class="pizza-item--add" id="selected-2">Add</div>
</a>
<div class="pizza-item--price" id="pizza-price-2">Rs. --</div>
<div class="pizza-item--name" id="pizza-name-2">--</div>
<div class="pizza-item--desc" id="pizza-desc-2">--</div>
<div class="pizza-item--sizes" id="pizza-size-2">
</div>
pizzas.json
[
{
"id": 1,
"name": "Tandoori Paneer",
"img": "/images/pizza.png",
"price": 200,
"sizes": [0, 100, 200],
"description": "Spiced paneer, Onion, Green Capsicum & Red Paprika in Tandoori Sauce",
"cheese": [0, 100, 0]
},
{
"id": 2,
"name": "Veggie Supreme",
"img": "images/pizza.png",
"price": 250,
"sizes": [0, 100, 200],
"description": "Black Olives, Green Capsicum, Mushroom, Onion, Red Paprika, Sweet Corn",
"cheese": [0, 100, 0]
}
]
index.js
//FIRST PIZZA - loading json data and showing it on index.html page
fetch("pizzas.json").then((response) =>
response.json().then((data) => {
//console.log(data[0].name);
document.querySelector("#pizza-img-1").src = data[0].img;
document.querySelector("#pizza-name-1").innerHTML = data[0].name;
document.querySelector(
"#pizza-price-1"
).innerHTML = `Rs ${data[0].price.toFixed(2)}`;
document.querySelector("#pizza-desc-1").innerHTML = data[0].description;
})
);
//SECOND PIZZA
fetch("pizzas.json").then((response) =>
response.json().then((data) => {
//console.log(data[0].name);
document.querySelector("#pizza-img-2").src = data[1].img;
document.querySelector("#pizza-name-2").innerHTML = data[1].name;
document.querySelector(
"#pizza-price-2"
).innerHTML = `Rs ${data[1].price.toFixed(2)}`;
document.querySelector("#pizza-desc-2").innerHTML = data[1].description;
})
);
MY DOUBT:
As you can see in the above code, I want to display details of two pizza items whose details are stored in json file and I'm using vanilla javascript to load data from json to HTML. And for each each of the pizzas, I have created element in index.html which is not good. Let's suppose in future I want to display details of 50 pizzas, so that would mean creating 50 chunks of code in html.
Can someone please tell me how can I use only one chunk of the HTML code and use it multiple times to create as many pizza items using vanilla javascript.
MY TAKE ON:
I was thinking to store the json data as a global variable and then use onload() and ready() to load data but I'm not sure about how to do it.
You can create an HTML template in JavaScript and use it over to generate your multiple <div> based on data in JSON file.
Using Template Literals you can easily use with the loops
fetch("https://api.jsonbin.io/b/605b2c5aaee69516ee8a8866/2").then((response) =>
response.json().then((data) => {
let jsonSize = data.length;
let htmlContent = '';
for (let i = 0; i < jsonSize; i++) {
let id = data[i].id;
let name = data[i].name;
let img = data[i].img;
let price = data[i].price;
let sizes = data[i].sizes;
let description = data[i].description;
let cheese = data[i].cheese;
htmlContent += `
<div class="column-pizza">
<a href="">
<div class="pizza-item--img">
<img src="${img}" id="pizza-img-${i}" />
</div>
<div class="pizza-item--add" id="selected-${i}">Add</div>
</a>
<div class="pizza-item--price" id="pizza-price-${i}">₹${price}</div>
<div class="pizza-item--name" id="pizza-name-${i}">${name}</div>
<div class="pizza-item--desc" id="pizza-desc-${i}">${description}</div>
</div>`;
}
document.querySelector("#root").innerHTML = htmlContent;
})
);
.column-pizza {
height: auto;
width: 50vv;
}
.pizza-item--add,
.pizza-item--price {
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
}
.pizza-item--add {
background-color: #4CAF50;
/* Green */
}
.pizza-item--price {
background-color: #333;
/* Gray */
}
<div id="root"></div>
PS- Don't have pizza image placeholder, thus using some random 🐕 and 🏞️ images.
Here is a demo
you can use async/await to fetch json
use map to transform the array to tags
use innerHTML to append a bunch of html contents
document.addEventListener('DOMContentLoaded', async ev => {
const res = await fetch('https://jsonplaceholder.typicode.com/photos')
const data = await res.json()
const photos = data.slice(0, 100)
const appEl = document.querySelector('#app')
appEl.innerHTML = photos.map((photo, index) => {
return `<div class="photo" style="transition-delay: ${index / 10}s">
<div class="image">
<img src="${photo.thumbnailUrl}" alt="thumbnailUrl" />
</div>
<div class="title">
${photo.title}
</div>
</div>`
}).join('')
setTimeout(() => {
appEl.classList.add('loaded')
}, 0)
}, false)
#app {
display: flex;
flex-flow: row wrap;
justify-content: space-evenly;
align-items: center;
position: relative;
}
.photo {
width: 200px;
height: 200px;
position: absolute;
top: 0;
left: 0;
transform: translate(-100vw, -100vh);
}
#app.loaded .photo {
position: static;
transition: all ease 1s;
transform: translate(0, 0);
}
.image {
text-align: center;
transition: transform ease 1s;
}
.image:hover {
transform: scale(1.1);
}
.title a {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
display: inline-block;
text-align: center;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
color: midnightblue;
text-decoration: none;
}
.title a:hover {
color: dodgerblue;
}
<div id="app"></div>
I want to build a state transition based on the "Animating State with Watchers" in the vue.js docs: https://v2.vuejs.org/v2/guide/transitioning-state.html#Animating-State-with-Watchers
I understand the example with primitive datatypes. In my case the data numbers, which I need to animate, are values in objects stored in an array.
Here is a simplified example of my problem:
new Vue({
el: '#animated-bar-demo',
data: {
bars: [
{
width: 30,
},
{
width: 10,
},
{
width: 70,
},
]
},
// HOW TO WATCH AND ANIMATE BARS.WIDTH FOR EACH BAR?
/* computed: {
animatedNumber: function() {
return this.tweenedNumber.toFixed(0);
}
},
watch: {
number: function(newValue) {
TweenLite.to(this.$data, 0.5, { tweenedNumber: newValue });
}
}, */
methods: {
changeData() {
let bars = this.bars;
bars.forEach(bar => {
bar.width += 10;
});
this.bars = bars;
},
},
})
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
button {
margin-bottom: 24px;
}
.bar-container {
width: 400px;
height: 32px;
border: 3px solid black;
overflow: hidden;
margin-bottom: 32px;
}
.bar {
width: 120%;
height: 100%;
background-color: #FA7268;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
<div id="animated-bar-demo">
<button v-on:click="changeData()"> add data </button>
<div class="bar-container" v-for="bar in bars">
<div class="bar"
:style="{ 'width': bar.width + '%'}">
</div>
</div>
</div>
I've commented the computed and watch logic for primitive values in my example out. How to watch and animate the width of each bar in the bars array?
I really appreciate your help and explanation for this problem.
Thanks!
I didn't found a solution to iterate an array through the tweenLite method but I got it to work.
I've created a component for the bar element and passing a single object width the width included.
Maybe someone with the same problem finds this solution helpful.
I am making a javascript form that includes a question being answered with only the number 1-6 (multiple choice) when the user finishes the form, there will be a result showing a chart (ChartJS). I've made that, but I want to show the user below the chart as following. If statement 1 is 1 and If statement 2 is 3 and If statement 3 is 4 then show .... . Here is my code:
/*-----------------------------------------------------
REQUIRE
-------------------------------------------------------*/
var yo = require('yo-yo')
var csjs = require('csjs-inject')
var minixhr = require('minixhr')
var chart = require('chart.js')
/*-----------------------------------------------------
THEME
-------------------------------------------------------*/
var font = 'Montserrat'
var yellow = 'hsla(52,35%,63%,1)'
var white = 'hsla(120,24%,96%,1)'
var violet = 'hsla(329,25%,45%,1)'
var lightBrown = 'hsla(29,21%,67%,1)'
var darkBrown = 'hsla(13,19%,45%,1)'
/*-----------------------------------------------------------------------------
LOADING FONT
-----------------------------------------------------------------------------*/
var links = ['https://fonts.googleapis.com/css?family=Montserrat']
var font = yo`<link href=${links[0]} rel='stylesheet' type='text/css'>`
document.head.appendChild(font)
/*-----------------------------------------------------------------------------
LOADING DATA
-----------------------------------------------------------------------------*/
var questions = [
`
Statement #1:
The next social network I build,
will definitely be for animals.
`,
`
Statement #2:
I really like to do my hobby
`,
`
Statement #3:
My friends say, my middle name should be "Halo".
`,
`
Statement #4:
Rhoma Irama is definitely one of my
favourite artists
`,
`
Statement #5:
I think I could spend all day just
sleeping at my couch
`,
`
Statement #6:
I have a really strong desire to succeed
`
]
var i = 0
var question = questions[i]
var results = []
var answerOptions = [1,2,3,4,5,6]
/*-----------------------------------------------------------------------------
QUIZ
-----------------------------------------------------------------------------*/
function quizComponent () {
var css = csjs`
.quiz {
background-color: ${yellow};
text-align: center;
font-family: 'Montserrat';
padding-bottom: 200px;
}
.welcome {
font-size: 4em;
padding: 50px;
color: ${darkBrown}
}
.question {
font-size: 2em;
color: ${white};
padding: 40px;
margin: 0 5%;
}
.answers {
display: flex;
justify-content: center;
flex-wrap: wrap;
margin: 0 5%;
}
.answer {
background-color: ${violet};
padding: 15px;
margin: 5px;
border: 2px solid ${white};
border-radius: 30%;
}
.answer:hover {
background-color: ${lightBrown};
cursor: pointer;
}
.instruction {
color: ${violet};
font-size: 1em;
margin: 0 15%;
padding: 20px;
}
.results {
background-color: ${white};
text-align: center;
font-family: 'Montserrat', cursive;
padding-bottom: 200px;
}
.resultTitle{
font-size: 4em;
padding: 50px;
color: ${darkBrown}
}
.back {
display: flex;
justify-content: center;
}
.backImg {
height: 30px;
padding: 5px;
}
.backText {
color: ${white};
font-size: 25px;
}
.showChart {
font-size: 2em;
color: ${violet};
margin: 35px;
}
.showChart:hover {
color: ${yellow};
cursor: pointer;
}
.myChart {
width: 300px;
height: 300px;
}
`
function template () {
return yo`
<div class="${css.quiz}">
<div class="${css.welcome}">
IQ Test
</div>
<div class="${css.question}">
${question}
</div>
<div class="${css.answers}">
${answerOptions.map(x=>yo`<div class="${css.answer}" onclick=${nextQuestion(x)}>${x}</div>`)}
</div>
<div class="${css.instruction}">
Choose how strongly do you agree with the statement<br>
(1 - don't agree at all, 6 - completely agree)
</div>
<div class="${css.back}" onclick=${back}>
<img src="http://i.imgur.com/L6kXXEi.png" class="${css.backImg}">
<div class="${css.backText}">Back</div>
</div>
</div>
`
}
var element = template()
document.body.appendChild(element)
return element
function nextQuestion(id) {
return function () {
if (i < (questions.length-1)) {
results[i] = id
i = i+1
question = questions[i]
yo.update(element, template())
} else {
results[i] = id
sendData(results)
yo.update(element, seeResults(results))
}
}
}
function seeResults(data) {
var ctx = yo`<canvas class="${css.myChart}"></canvas>`
return yo`
<div class="${css.results}">
<div class="${css.resultTitle}">
Your Result
</div>
<div class="${css.showChart}" onclick=${function(){createChart(ctx, data)}}>
Click to see the chart
</div>
${ctx}
</div>
`
}
function back() {
if (i > 0) {
i = i-1
question = questions[i]
yo.update(element, template())
}
}
function sendData(results) {
var request = {
url : 'https://cobatest-964fd.firebaseio.com/results.json',
method : 'POST',
data : JSON.stringify(results)
}
minixhr(request)
}
function createChart(ctx, myData) {
minixhr('https://cobatest-964fd.firebaseio.com/results.json', responseHandler)
function responseHandler (data, response, xhr, header) {
var data = JSON.parse(data)
var keys = Object.keys(data)
var arrayOfAnswers = keys.map(x=>data[x])
var stats = arrayOfAnswers.reduce(function(currentResult,answer,i) {
var newResult=currentResult.map((x,count)=>(x*(i+1)+answer[count])/(i+2))
return newResult
}, myData)
var data = {
labels: [
"Caring", "Eager", "Pessimist",
"Hard-headed", "Lazy", "Ambitious"
],
datasets: [
{
label: "My score",
backgroundColor: "rgba(179,181,198,0.2)",
borderColor: "rgba(179,181,198,1)",
pointBackgroundColor: "rgba(179,181,198,1)",
pointBorderColor: "#fff",
pointHoverBackgroundColor: "#fff",
pointHoverBorderColor: "rgba(179,181,198,1)",
data: myData
},
]
}
var myChart = new Chart(ctx, {
type: 'radar',
data: data,
options: {
scale: {
scale: [1,2,3,4,5,6],
ticks: {
beginAtZero: true
}
}
}
})
}
}
}
quizComponent()
Please do help! thank you
Just like onclick is an event, onsubmit is one too.
From w3schools:
in HTML: <element onsubmit="myScript">
in JS: object.onsubmit = function(){myScript};
in JS with eventListener:object.addEventListener("submit", myScript);
You can check it out on w3 schools:
onsubmit event
onsubmit attribute
more
I would like to split the active items to 50% height of their parent element. So when I open the first two items, they should split to 50% of their parent class .items (both .item have 100px). So I can see both without scrolling. Also when I open all three of them, they should get the height of 100px, which is the half of their parent. My problem is, tha the second item overlaps and I have to scroll. Whats wrong?
angular.module("myApp", []).controller("myController", function($scope) {
$scope.itemList = [{
id: 1,
name: "Item 1",
isOpen: false
}, {
id: 2,
name: "Item 2",
isOpen: false
}, {
id: 3,
name: "Item 3",
isOpen: false
}];
$scope.setHeight = function() {
if ($scope.itemList.length > 1) {
var typeHeaderHeight = $('.item-header').outerHeight();
var halfHeight = Math.round($('.items').outerHeight() / 2);
setTimeout(() => {
$('.item').css('height', typeHeaderHeight);
$('.item.active').css('height', halfHeight);
});
}
}
});
.frame {
display: flex;
flex-direction: column;
height: 200px;
}
.items {
display: flex;
flex: 1 1 auto;
flex-direction: column;
overflow: auto;
border: 1px solid black;
}
.item {
display: flex;
flex-direction: column;
flex: 0 0 auto;
margin-bottom: 5px;
background-color: rgb(150, 150, 150);
color: white;
}
.item:hover {
cursor: pointer;
}
.item-header {
position: relative;
display: flex;
}
.active {
background-color: rgb(220, 220, 220);
color: rgb(150, 150, 150);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="frame" ng-app="myApp" ng-controller="myController">
<div class="items">
<div class="item" ng-repeat="item in itemList" ng-click="item.isOpen = !item.isOpen; setHeight()" ng-class="{active: item.isOpen}">
<div class="item-header">
{{item.name}}
</div>
</div>
</div>
</div>
The issue is that you are setting the values of typeHeaderHeight and halfHeight variables outside the timeout so it always calculated before the item is actually opened so there is mistake in the calculations
try to make it like
setTimeout(() => {
var typeHeaderHeight = $('.item-header').outerHeight();
var halfHeight = Math.round($('.items').outerHeight() / 2);
$('.item').css('height', typeHeaderHeight);
$('.item.active').css('height', halfHeight);
});
},500)
One more thing .. I don't recommend to use setTimeout of vanilla JavaScript try to use $timeout instead of it