Can a Chartist line graph be animated left to right? - chartist.js

I see animations for Chartist line graphs (http://gionkunz.github.io/chartist-js/examples.html#example-line-path-animation), but none where the line literally draws itself out from left to right. Is that possible?

Not my solution, but it seems to do what you want.
HTML
<div class="ct-chart ct-golden-section"></div>
CSS
$color1: #ada8b6; //rgba(173, 168, 182, 100)
$color2: #ffeedb; //rgba(255, 238, 219, 100)
$color3: #4c3b4d; //rgba(76, 59, 77, 100)
$color4: #a53860; //rgba(165, 56, 96, 100)
$color5: #61c9a8; //rgba(97, 201, 168, 100)
body {
width: 100vw;
height: 100vh;
background: #111;
}
.ct-chart {
width: 90vw;
max-width: 1100px;
height: 375px;
margin: 5vh 6.5vw;
svg {
width: 100%;
}
}
.ct-grids line {
stroke: $color3;
opacity: 0.4;
}
.ct-labels span {
color: $color3;
}
#mixin pathseries($length, $delay, $strokecolor) {
stroke-dasharray: $length;
stroke-dashoffset: $length;
animation: draw 1s $delay ease both;
fill: none;
stroke: $strokecolor;
opacity: 0.8;
}
.ct-series-a {
#include pathseries(1093, 0s, $color1);
}
.ct-series-b {
#include pathseries(1665, 0.25s, $color5);
}
.ct-series-c {
#include pathseries(1644, 0.5s, $color2);
}
.ct-series-d {
#include pathseries(1540, 0.75s, $color4);
}
#keyframes draw {
to {
stroke-dashoffset: 0;
}
}
JS
new Chartist.Line('.ct-chart', {
labels: [1, 2, 3, 4, 5, 6, 7, 8],
series: [
[11, 12, 13, 11, 12, 10, 11, 10],
[12, 11, 17, -1, 0, 18, -2, 8],
[0, 8, 12, 1, 15, 3, 18, 1],
[3, 2, 12, 15, 16, 3, 18, -3]
]
}, {
high: 20,
low: -3,
fullWidth: true,
// As this is axis specific we need to tell Chartist to use whole numbers only on the concerned axis
axisY: {
onlyInteger: true,
offset: 20
}
});
setTimeout (
function() {
var path = document.querySelector('.ct-series-a path');
var length = path.getTotalLength();
console.log(length);
},
3000);

Related

Is there a way to display a node label at the top inside the node?

I am creating a graph using cytoscape.js and I have compounded nodes which are inside the parent node. I would like to have the title of the main/parent node at the top of the node but inside the node. Is that possible in cytoscape?
I have tried using using halign and valign. Whenever I use top value, it shows outside the box.
Is there a extension or a plugin that lets us do it?
Example with child node: https://stackblitz.com/edit/cytoscape-call-method-child-efmbaj?file=src%2Fapp%2FstylesheetObject.ts
As you can read here, you can only place labels inside a node with the center option, a good configuration (label inside at the top) requires a margin to be added to your label:
.selector(':parent')
.css({
'text-valign': 'center',
// the next line moves the parents label up to the top of the node and 5px down to create a padding
'text-margin-y': function (node) { return -node.height() + 5 }
})
Here is a working example:
var cy = cytoscape({
container: document.getElementById('cy'),
style: cytoscape.stylesheet()
.selector(':parent')
.css({
'text-valign': 'center',
'text-margin-y': function(node) {
return -node.height() + 5
}
})
.selector('node')
.css({
'height': 'data(size)',
'width': 'data(size)',
'border-color': '#000',
'border-width': '1',
'content': 'data(name)'
})
.selector('edge')
.css({
'width': 'data(strength)'
})
.selector('#1')
.css({
'background-color': 'red'
})
.selector('#4')
.css({
'background-color': 'green'
}),
elements: {
nodes: [{
data: {
id: '1',
size: 50,
name: 'a'
}
},
{
data: {
id: '2',
size: 20,
name: 'b',
parent: '1'
}
},
{
data: {
id: '3',
size: 40,
name: 'c',
parent: '1'
}
},
{
data: {
id: '4',
size: 50,
name: 'd'
}
},
{
data: {
id: '5',
size: 20,
name: 'e',
parent: '4'
}
},
{
data: {
id: '6',
size: 40,
name: 'f',
parent: '4'
}
}
],
},
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 75%;
position: absolute;
left: 0;
top: 0;
float: left;
}
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.17/cytoscape.min.js"></script>
<script src="https://unpkg.com/jquery#3.3.1/dist/jquery.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>
What I understand is that you want to put the parent label inside the box above child? apologies if I'm wrong
If so, My solution will be to add a padding and then apply margin for alignment.
Modified your example
Styles updated:
'padding-top':60
selector: 'node',
css: {
content: 'data(label)',
'text-valign': 'center',
'text-halign': 'center',
'font-size': 28,
'padding-top':60
}
'text-valign': 'top', and 'text-margin-y': function(node) {
return node.height() - 10;
}
selector: 'node[type="parent"]',
style: {
shape: 'rectangle',
'background-color': 'grey',
width: 300,
height: 100,
'font-size': 25.5,
'font-family': 'Lato, Helvetica Neue, Helvetica, Arial, sans-serif',
color: 'black',
'text-valign': 'top',
'text-halign': 'center',
'text-margin-y': function(node) {
return node.height() - 10;
}
}

Detect if a user has created a 4x4 line in a 4x4 grid of divs

So I am building my own custom bingo table that is 4x4 with vue. I have everything down except how to detect wether a user has formed a 4x4 line that is horizontal, diagonal, or vertical
Inside my data function I have an array that represents the 4x4
[9, 13, 28, 24],
[11, 22, 15, 43],
[54, 5, 37, 4],
[27, 40, 12, 36]
My question is how can I check to see if a user has clicked a 4x4 line? No code is needed as an answer I just want to know how I can approach this problem.
Given an n x n matrix
Horizontal:
Are there n selected elements that have the same rowIndex?
Vertical:
Are there n selected elements that have the same columnIndex?
Diagonal (Top Left to Bottom Right)
Are there n elements that have the same rowIndex as their columnIndex?
Diagonal (Top Right to Bottom Left)
Are there n elements that satisfy (length(row) - 1) - rowIndex == columnIndex?
const Card = Vue.component('card', {
template: '#card',
props: {
playerCard: Array
},
data() {
return {
selectedVals: [],
rowCounts: {},
colCounts: {}
}
},
computed: {
horizontalNumberToWin() {
return this.playerCard[0].length;
},
verticalNumberToWin() {
return this.playerCard.length;
},
diagonalNumberToWin() {
return this.playerCard.length;
},
isDiagonal() {
if (this.selectedVals.length < this.diagonalNumberToWin) return false;
// top left to bottom right
// [0, 0] [1, 1], [2, 2], [3, 3], etc..
const isTLtoBR = this.selectedVals.filter(val => val[0] === val[1]);
if (isTLtoBR.length >= this.diagonalNumberToWin) return true;
// top right to bottom left
// [0, 3], [1, 2], [2, 1], [3, 0], etc..
const rowLen = this.playerCard[0].length;
const isTRtoBL = this.selectedVals.filter(val => {
return (rowLen -1) - val[0] === val[1];
});
if (isTRtoBL.length >= this.diagonalNumberToWin) return true;
return false;
},
isHorizontal() {
if (this.selectedVals.length < this.horizontalNumberToWin) return false;
return Object.values(this.rowCounts).some(row => row >= this.horizontalNumberToWin);
},
isVertical() {
if (this.selectedVals.length < this.verticalNumberToWin) return false;
return Object.values(this.colCounts).some(col => col >= this.verticalNumberToWin);
},
},
methods: {
onCardClicked(coord) {
this.selectedVals.push(coord);
this.updateCounts(coord);
},
cardDisabled(coord) {
return this.selectedVals.some(vals => vals[0] === coord[0] && vals[1] === coord[1]);
},
updateCounts(coord) {
const rowIndex = coord[0];
const colIndex = coord[1];
this.rowCounts[rowIndex] = this.rowCounts[rowIndex] ? this.rowCounts[rowIndex] + 1 : 1;
this.colCounts[colIndex] = this.colCounts[colIndex] ? this.colCounts[colIndex] + 1 : 1;
}
}
});
new Vue({
el: '#app',
components: {
Card,
},
data: {
playerCard: [
[9, 13, 28, 24],
[11, 22, 15, 43],
[54, 5, 37, 4],
[27, 40, 12, 36]
],
},
})
#app {
display: flex;
flex-direction: row;
justify-content: center;
}
.board {
max-width: 500px;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<card :player-card="playerCard" />
</div>
<template id="card">
<div>
<p>Horizontal: {{ isHorizontal }}</p>
<p>Vertical: {{ isVertical }}</p>
<p>Diagonal: {{ isDiagonal }}</p>
<div class="board">
<template v-for="(row, rowIndex) in playerCard">
<button
v-for="(col, colIndex) in row"
:key="col"
:disabled="cardDisabled([rowIndex, colIndex])"
#click="onCardClicked([rowIndex, colIndex])">
{{ col }}
</button>
</template>
</div>
</div>
</template>
First, I think you should add isClick to check whether the user has clicked the card or not.
[
[
{ Number: 9 , isClick: false },
{ Number: 13 , isClick: false },
{ Number: 28 , isClick: false },
{ Number: 24 , isClick: false }
],
// other array ...
]
Second, bind your data into html (Maybe you should used twice v-for to achieve it). When user click the card, set isClick = true.
Third, write your own logic to check if a user has clicked a 4x4 line.

Sass refactoring variable as selector

I'd like to refactor this code if possible, I didn't find something to figure it out :
$javascript: rgb(238, 218, 103);
$php: rgb(119,125,176);
$ruby: rgb(197, 25, 17);
.isjavascript {
color: $javascript;
}
.isphp {
color: $php;
}
.isruby {
color: $ruby;
}
Well, you could use a map.
$languages-color: (
'javascript': rgb(238, 218, 103),
'php': rgb(119,125,176),
'ruby': rgb(197, 25, 17)
);
#each $label, $color in $languages-color {
.is#{$label} {
color: $color;
}
}

Set element height based on parent height in vue js on page load

I want to set the height of a vue component (to be specific it is this -> https://github.com/jbaysolutions/vue-grid-layout).
The height of which (in vue-grid-layout -> grid-item) should be same as of its parent.
And this also should be only in page load time. So how this can be achieved in vue js?
I don't want to do this using CSS. I need height in pixels. as to vue-grid-layout -> item height needs in pixel initially. as it is resizable, it can be changed afterwards.
it would be easier to provide an accurate answer with some example html (your actual code), but the following should work in general.
export default {
...
data() {
return {
parentHeight: 0
}
},
mounted() {
this.parentHeight = this.$parent.$el.offsetHeight;
}
...
}
So in the mounted lifecycle hook you can read the height of the parent and then set it where ever you need it.
No need for advanced javascript to calculate the height, just use styling:
height: 100%;
Demo:
.parent {
resize: both;
overflow: auto;
height: 100px;
display: block;
width: 100px;
border: 1px solid black;
}
.child {
height: 100%;
background: pink;
}
<div class="parent">
</div>
<div class="parent">
<div class="child">
I'm a child!
</div>
</div>
I found a solution to fix the grid-layout height depending on available space. For that I have used folowing props: max-rows, row-height, margins, autoSize=false
And ResizeObserver which will adjust grid-layout row-height according to available height after window resize. Also be aware that I used some Bootstrap classes for styling
<template>
<div class="flex-grow-1 w-100">
<grid-layout
:layout="layout"
:col-num="colCount"
:maxRows="rowCount"
:row-height="rowHeight"
:autoSize="false"
:is-draggable="true"
:is-resizable="true"
:is-mirrored="false"
:preventCollision="true"
:vertical-compact="false"
:margin="margin"
:use-css-transforms="true"
>
<grid-item
v-for="item in layout"
class="bg-primary"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:key="item.i"
>
<span class="remove" #click="removeItem(item.i)">x</span>
</grid-item>
</grid-layout>
</div>
</template>
<script lang="ts">
import { defineComponent } from '#vue/runtime-core';
interface GridItem {
x: number;
y: number;
w: number;
h: number;
i: string;
}
interface State {
layout: GridItem[];
index: number;
colCount: number;
rowCount: number;
rowHeight: number;
observer: null | ResizeObserver;
margin: number[];
}
export default defineComponent({
name: 'VideoWall',
data(): State {
return {
layout: [
{ x: 0, y: 0, w: 2, h: 2, i: '0' },
{ x: 2, y: 0, w: 2, h: 4, i: '1' },
{ x: 4, y: 0, w: 2, h: 5, i: '2' },
{ x: 6, y: 0, w: 2, h: 3, i: '3' },
{ x: 8, y: 0, w: 2, h: 3, i: '4' },
],
index: 0,
colCount: 36,
rowCount: 36,
rowHeight: 40,
margin: [5, 5],
observer: null,
};
},
mounted() {
this.observer = new ResizeObserver(this.onResize);
if (this.$el instanceof Element) {
this.observer.observe(this.$el);
} else {
console.log('VideoWall: Failed to bind observer');
}
},
unmounted() {
if (this.observer) {
this.observer.disconnect();
}
},
methods: {
onResize(entries: ResizeObserverEntry[]): void {
this.rowHeight =
Math.floor(entries[0].contentRect.height / this.rowCount) -
this.margin[1];
},
},
});
</script>

sencha Touch chart: Applying gradient color to line fill

I am working on a mobile application that contains different line charts . I have been trying to apply gradient colors to a line (single) chart fill color. But unfortunately I could not.
Is it possible to apply color gradients to a line fill color? Please help.
Check out this article: http://www.sencha.com/learn/learning-sencha-touch-charts/
sample styling with SASS:
chart {
colors: linear-gradient(45, rgb(212, 40, 40), rgb(117, 14, 14))
linear-gradient(45, rgb(180, 216, 42), rgb(94, 114, 13))
linear-gradient(45, rgb(43, 221, 115), rgb(14, 117, 56))
linear-gradient(45, rgb(45, 117, 226), rgb(14, 56, 117))
linear-gradient(45, rgb(187, 45, 222), rgb(85, 10, 103));
background: linear-gradient(45, #444, #111);
series {
stroke-width: 2;
&:nth-child(1) {
fill: linear-gradient(0, rgb(212, 40, 40), rgb(117, 14, 14));
}
&:nth-child(2) {
fill: linear-gradient(0, rgb(180, 216, 42), rgb(94, 114, 13));
}
&:nth-child(3) {
fill: linear-gradient(0, rgb(43, 221, 115), rgb(14, 117, 56));
}
&:nth-child(4) {
fill: linear-gradient(0, rgb(45, 117, 226), rgb(14, 56, 117));
}
&:nth-child(5) {
fill: linear-gradient(0, rgb(187, 45, 222), rgb(85, 10, 103));
}
}
axis {
stroke: #555;
fill: #555;
label {
fill: #eee;
}
title {
fill: #eee;
}
}
}
Also note this earlies post: Sencha Touch Charts style