Converting Vue Component to Vuetify Component - vue.js

I am using Vue+Vuetify. Never learnt Vue standlone went straight into the duo
I am trying to re-create a sparkline metric - Can be seen in this codepen "PageViews" (Source starts at line 30 in JS)
The issue: Vue standalone has a different method of registering components. I have attempted to re-jig the code and register the component according to Vuetify's rules. Normally a sparkline in Vuetify is simply called with <v-sparkline/>.
Despite my efforts I am stuck with the error: TypeError: "this.Chart is not a function".
What am I doing wrong?
My attempt: metric.vue
<template>
<div class="br2">
<div class="pa3 flex-auto bb b--white-10">
<h3 class="mt0 mb1 f6 ttu white o-70">{{ title }}</h3>
<h2 class="mv0 f2 fw5 white">{{ value }}</h2>
</div>
<div class="pt2">
<canvas></canvas>
</div>
</div>
</template>
<script>
export default {
props: ["title", "value"],
data () {
return {
ctx: null,
}
},
mounted () {
this.ctx = this.$el.querySelector("canvas").getContext("2d");
let sparklineGradient = this.ctx.createLinearGradient(0, 0, 0, 135);
sparklineGradient.addColorStop(0, "rgba(255,255,255,0.35)");
sparklineGradient.addColorStop(1, "rgba(255,255,255,0)");
let data = {
labels: ["A", "B", "C", "D", "E", "F"],
datasets: [{
backgroundColor: sparklineGradient,
borderColor: "#FFFFFF",
data: [2, 4, 6, 4, 8, 10]
}]
};
this.Chart(this.ctx, {
data: data,
options: {
elements: {
point: {
radius: 0
}
},
scales: {
xAxes: [{
display: false
}],
yAxes: [{
display: false
}]
}
}
});
}
}
</script>

you did not import Chart from chart.js
<template>
<div id="app">
<div class="br2">
<div class="pt2">
<canvas></canvas>
</div>
</div>
</div>
</template>
<script>
import Chart from 'chart.js'
export default {
name: "App",
data(){
return{
ctx: null
}
},
created: function() {
Chart.defaults.global.legend.display = false;
},
mounted: function() {
this.ctx = this.$el.querySelector("canvas").getContext("2d");
let sparklineGradient = this.ctx.createLinearGradient(0, 0, 0, 135);
sparklineGradient.addColorStop(0, "rgba(255,255,255,0.35)");
sparklineGradient.addColorStop(1, "rgba(255,255,255,0)");
let data = {
labels: ["A", "B", "C", "D", "E", "F"],
datasets: [{
backgroundColor: 'red',
borderColor: "#FFFFFF",
data: [2, 4, 6, 4, 8, 10]
}]
};
Chart.Line(this.ctx, {
data: data,
options: {
elements: {
point: {
radius: 0
}
},
scales: {
xAxes: [{
display: false
}],
yAxes: [{
display: false
}]
}
}
});
}
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

Related

ECharts failed in rendering the candlesticks in quasar app

I use echarts for vue library from here and getting both sample setup and data from here.
So my codes are like these:
app.js
import { Quasar } from 'quasar'
import { markRaw } from 'vue'
import RootComponent from 'app/src/App.vue'
import createStore from 'app/src/stores/index'
import createRouter from 'app/src/router/index'
import ECharts from 'vue-echarts'
import { use } from "echarts/core"
import { CanvasRenderer } from 'echarts/renderers'
import { CandlestickChart } from 'echarts/charts'
import {
GridComponent,
TooltipComponent,
TitleComponent,
LegendComponent,
DataZoomComponent,
} from 'echarts/components'
use([
CanvasRenderer,
CandlestickChart,
GridComponent,
TooltipComponent,
TitleComponent,
LegendComponent,
DataZoomComponent,
])
... more ..
MyChart.vue
<template>
<q-item>
<div style="width: 100%; margin: 0;" class="bg-white">
<table style="width: 100%; height: 360px">
<tr>
<td style="width: 45%">Info</td>
<td style="width: 55%">
<chart class="candle-chart" :option="option"></chart>
</td>
</tr>
</table>
</div>
</q-item>
</template>
<script>
/* eslint-disable */
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "MyChart",
props: {
id: Number,
event: Object,
prices: Array
},
setup(props) {
const priceData = splitData(props.prices);
const optionObj = ref({
title: {
text: props.event.pair,
left: 0
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
legend: {
data: ['日K']
},
grid: {
left: '10%',
right: '5%',
bottom: '15%'
},
xAxis: {
type: 'category',
data: priceData.categoryData,
boundaryGap: false,
axisLine: { onZero: false },
splitLine: { show: false },
min: 'dataMin',
max: 'dataMax'
},
yAxis: {
scale: true,
splitArea: {
show: true
}
},
series: [
{
name: '日K',
type: 'candlestick',
data: priceData.values,
itemStyle: {
color: '#FD1050',
color0: '#0CF49B',
borderColor: '#FD1050',
borderColor0: '#0CF49B'
},
}
]
});
function splitData(rawData) {
const categoryData = [];
const values = [];
for (var i = 0; i < rawData.length; i++) {
categoryData.push(rawData[i].splice(0, 1)[0]);
values.push(rawData[i]);
}
return {
categoryData: categoryData,
values: values
};
}
return {
option: optionObj
}
}
});
</script>
<style scoped>
.candle-chart {
width: 100%;
border: 1px;
border-style: solid;
border-radius: 4px;
border-color: #b0a9a9;
}
</style>
I load data from json file, but to be simple.. the structure of the data is like below:
"prices": [
[ "2013/1/24", 2320.26, 2320.26, 2287.3, 2362.94 ],
[ "2013/1/25", 2300, 2291.3, 2288.26, 2308.38 ],
... more data ... ]
There is no error after running it, I can see the chart area and all the lines, the legends, the grid, the tooltip and so on... but not a single candle rendered (see below screemshot)
Can anybody from ECharts or Vue-echarts or anybody who ever work on this tell me what is wrong with my code?

Recursive component view does not display after data change

A common need for data binding is manipulating an element's class list and inline styles. Since class and style are both attributes, we can use v-bind to assign them a string value dynamically, much like with other attributes.
I want to have 2d array with turned on and off dates checked in component by v-if
interesting variable is dir.
<html>
<body>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<div class="container">
<h4>
Vue.js Expandable Tree Menu<br />
<small>(Recursive Components)</small>
</h4>
<div id="app">
<tree-menu :nodes="tree.nodes" :depth="0" :label="tree.label" :dir="dir"></tree-menu>
</div>
</div>
<script>
let tree = {
label: "root",
nodes: [
{
label: "item1",
nodes: [
{
label: "item1.1",
},
{
label: "item1.2",
nodes: [
{
label: "item1.2.1",
},
],
},
],
},
{
label: "item2",
},
],
};
Vue.component("tree-menu", {
props: ["nodes", "label", "depth", "dir"],
template: `
<div >
<div class="label-wrapper" #click="toggleChildren">
<div :style="indent" :class="labelClasses">
<i v-if="nodes" class="fa" :class="iconClasses"></i>
{{ label }}
</div>
</div>
<tree-menu
v-if="dir[0][0]"
v-for="node in nodes"
:nodes="node.nodes"
:label="node.label"
:depth="depth + 1"
:dir="dir"
>
</tree-menu>
</div>`,
data() {
return {
showChildren: false,
};
},
computed: {
iconClasses() {
return {
"fa-plus-square-o": !this.showChildren,
"fa-minus-square-o": this.showChildren,
};
},
labelClasses() {
return { "has-children": this.nodes };
},
indent() {
return { transform: `translate(${this.depth * 50}px)` };
},
},
methods: {
toggleChildren() {
this.dir[0][0] = !this.dir[0][0];
alert(this.dir[0][0]);
},
},
});
new Vue({
el: "#app",
data: {
tree,
dir: [
[1, 1, 1, 1, 1],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
],
},
});
</script>
<style>
body {
font-family: "Open Sans", sans-serif;
font-size: 18px;
font-weight: 300;
line-height: 1em;
}
.container {
width: 300px;
margin: 0 auto;
}
.tree-menu {
.label-wrapper {
padding-bottom: 10px;
margin-bottom: 10px;
border-bottom: 1px solid #ccc;
.has-children {
cursor: pointer;
}
}
}
</style>
</body>
</html>
I want to have 2d array with turned on and off dates that are checked by v-if.

Vue Element UI - html inside <el-select>

I would like to implement a select element with different colored-labels for each entry:
My code looks like this:
var Main = {
data() {
return {
selectedState: null,
processStates: [
{
value: 0,
label: 'New',
color: 'ffffff'
},
{
value: 1,
label: 'Ready',
color: 'ff9933'
},
{
value: 2,
label: 'Running',
color: '008000'
},
{
value: 3,
label: 'Rejected',
color: 'cc0000'
},
{
value: 4,
label: 'Terminated',
color: '2E9AFE'
}
]
}
},
methods: {}
}
var Ctor = Vue.extend(Main);
new Ctor().$mount('#app');
#import url("//unpkg.com/element-ui#2.4.4/lib/theme-chalk/index.css");
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui#2.4.11/lib/index.js"></script>
<div id="app">
<el-select v-model="selectedState" style="width:200px">
<el-option
v-for="state in processStates"
:key="state.value"
:label="state.label"
:value="state.value"
>
<span>
<el-tag :style="'background-color:#' + state.color"> </el-tag> {{ state.label }}
</span>
</el-option>
</el-select>
</div>
AS you can see, I managed to inject html into the option tag and have the desired result.
However, I would like to have the same html when one option is selected.
Desired result:
Any idea how can I achieve it?
You have to use the prefix slot for this. As done below, also I changed the selectedState to an object, but you can also still use the string value, but then you have to do a lookup to get the color
var Main = {
data() {
return {
selectedState: { color: 'ffffff'},
processStates: [
{
value: 0,
label: 'New',
color: 'ffffff'
},
{
value: 1,
label: 'Ready',
color: 'ff9933'
},
{
value: 2,
label: 'Running',
color: '008000'
},
{
value: 3,
label: 'Rejected',
color: 'cc0000'
},
{
value: 4,
label: 'Terminated',
color: '2E9AFE'
}
]
}
},
methods: {}
}
var Ctor = Vue.extend(Main);
new Ctor().$mount('#app');
#import url("//unpkg.com/element-ui#2.4.4/lib/theme-chalk/index.css");
.el-input--prefix .el-input__inner {
padding-left: 40px;
}
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui#2.4.11/lib/index.js"></script>
<div id="app">
<el-select v-model="selectedState" value-key="value" style="width:200px">
<template slot="prefix">
<el-tag class="prefix" :style="`background-color: #${selectedState.color}`"/>
</template>
<el-option
v-for="state in processStates"
:key="state.value"
:label="state.label"
:value="state"
>
<span>
<el-tag :style="'background-color:#' + state.color"> </el-tag> {{ state.label }}
</span>
</el-option>
</el-select>
</div>

How can I change my c3 chart axis color in vue environment

I want use c3.js in my vue app, it's successful to build a chart but I can't change my c3 chart axis color.
It's not just axis color, all style of c3 charts I can't change and fixed, it's upset for me.
Do you have any idea for it?
<template>
<div id="home">
<div class="block1">
<div id='lineChart'></div>
</div>
</div>
</template>
<script>
import * as d3 from "d3";
import c3 from 'c3';
export default {
mounted(){
this.loadBlock1();
},
methods:{
loadBlock1 () {
let chart = c3.generate({
bindto:'#lineChart',
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 50, 20, 10, 40, 15, 25]
],
}
});
}
}
}
</script>
<style scoped>
#import "https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.0/c3.min.css";
#lineChar .c3-line-data2 {
stroke-width: 5px;
}
#lineChart .c3-axis-x line,
#lineChart .c3-axis-x path {
stroke:blue;
}
</style>
Your code is not working because when you use <style scoped> Vue emulates shadow DOM adding a hash on the DOM elements and on the CSS selectors. The elements created by c3 do not contain the hash and the css selector do not match with them. So, add a style tag without the scoped attr for styling the chart.
<template>...</template>
<script>...</script>
<style scoped>...</style>
<style>...</style>
Also, avoid getting the DOM element using query selectors. Vue uses VDOM approach and DOM access should be done through directives and refs:
Vue.directive("c3", {
bind(el, binding, vnode) {
const chart = c3.generate({
bindto: el,
data: binding.value,
});
el.chart = chart;
},
update(el, binding, vnode) {
el.chart.resize();
},
unbind(el, binding, vnode) {
el.chart.destroy();
}
});
const home = new Vue({
el: "#home",
data() {
return {
options: {
columns: [
["data1", 30, 200, 100, 400, 150, 250],
["data2", 50, 20, 10, 40, 15, 25]
],
},
};
},
computed: {
chart() {
return this.$refs.chart.chart;
}
},
methods: {
load(data) {
this.chart.load(data);
},
unload(data) {
this.chart.load(data);
}
},
mounted() {
this.chart.resize();
}
});
setTimeout(() => {
home.load({
columns: [
['data1', 230, 190, 300, 500, 300, 400]
]
});
}, 1000);
setTimeout(function() {
home.load({
columns: [
['data3', 130, 150, 200, 300, 200, 100]
]
});
}, 1500);
setTimeout(function() {
home.unload({
ids: 'data1'
});
}, 2000);
#home .c3-line-data2 {
stroke-width: 5px;
}
#home .c3-axis-x line,
#home .c3-axis-x path {
stroke: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.0/c3.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.0/c3.min.js"></script>
<div id="home">
<div class="block1">
<div ref="chart" v-c3="options"></div>
</div>
</div>

How to load data into Vue from an external file using Axios

how would you go about replacing the "image" data array in this example with an external JSON file? Basically I want to fetch/get this data externally with axios but something is not quite working yet in this example. Any clue very much appreciated!
I also created a CodePen for this example working without the external reference if you prefer to look at it this way. Thanks a lot!
https://codepen.io/FloydGekko/pen/eLoRBQ
This is the html, css and vue.js code:
<head>
<style>
[v-cloak] {
display: none;
}
.imageBlock{
width:100%;
margin:10px;
}
div.polaroid {
width:310px;
height:440px;
margin:10px;
background-color: white;
box-shadow: 6px 4px 8px 0 rgba(0, 0, 0, 0.2), 6px 6px 20px 0 rgba(0, 0, 0, 0.19);
margin-bottom: 25px;
border-radius: 18px
}
div.container {
text-align: center;
padding: 10px 20px;
}
</style>
</head>
<body>
<div id="vue" v-cloak>
<h2 align="center">
Show
<select v-model="currentKind" #change="onChange">
<option v-for="kind, index in kinds" :value="kind" :key="`kind_${index}`">{{kind ? kind : 'kind...'}}</option>
</select>
<select v-model="currentColor" #change="onChange">
<option v-for="color, index in colors" :value="color" :key="`kind_${index}`">{{color ? color : 'color...'}}</option>
</select>
and
<select v-model="currentShape" #change="onChange">
<option v-for="shape, index in shapes" :value="shape" :key="`kind_${index}`">{{shape ? shape : 'shape...'}}</option>
</select>
</h2>
<isotope
id="root_isotope"
ref="isotope"
:options='options'
:list="images"
align="center">
<div class="polaroid" align="center"
v-for="(image, index) in images"
class="imageBlock"
:key="image.id">
<a target="_blank" :href="image.url"><img border="0" :src="image.pic" alt=""
style="
border-radius: 20px;
display: block;
margin-left: auto;
margin-right: auto;
width: 100%;">
</a>
<div class="container">
<a target="_blank" :href="image.url">
<h3 align="center">{{image.title}}</h3>
</a>
<!--<h1>{{image.kind}}</h1>
<h1>{{image.color}}</h1>
<h1>{{image.shape}}</h1>
<h1>{{image.id}}</h1>-->
</div>
</div>
</isotope>
<h2 align="center">
<button #click="reset">Show all</button>
</h2>
</div>
<script src='https://unpkg.com/vue/dist/vue.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js'></script>
<script src='https://npmcdn.com/isotope-layout#3.0.6/dist/isotope.pkgd.min.js'></script>
<script src='https://rawgit.com/David-Desmaisons/Vue.Isotope/master/src/vue_isotope.js'></script>
<script src='https://unpkg.com/axios/dist/axios.min.js'></script>
<script>
let currentKind = null;
let currentColor = null;
let currentShape = null;
let imageSearchString = null;
var vm = new Vue({
el: '#vue',
data() {
return {
currentKind:'',
currentColor:'',
currentShape:'',
options: {
itemSelector: ".imageBlock",
getSortData: {
id: "id"
},
sortBy : "id",
getFilterData: {
Finder: function(itemElem) {
let kindSearch = currentKind ? itemElem.kind.indexOf(currentKind) !== -1 : true;
let colorSearch = currentColor ? itemElem.color.indexOf(currentColor) !== -1 : true;
let shapeSearch = currentShape ? itemElem.shape.indexOf(currentShape) !== -1 : true;
return kindSearch && colorSearch && shapeSearch
},
},
},
images: '',
};
},
computed: {
kinds(){
let allTags = _.flatten(this.images.map(image => image.kind))
return [''].concat(_.uniq(allTags))
},
colors(){
let allTags = _.flatten(this.images.map(image => image.color))
return [''].concat(_.uniq(allTags))
},
shapes(){
let allTags = _.flatten(this.images.map(image => image.shape))
return [''].concat(_.uniq(allTags))
},
},
mounted(){
setTimeout(()=>{
this.onChange()
}, 200)
},
created: function () {
this.loadImages();
},
methods: {
onChange: function() {
currentColor = this.currentColor;
currentShape = this.currentShape;
currentKind = this.currentKind;
this.$refs.isotope.filter('Finder');
this.$refs.cpt.layout('packery');
},
reset(){
currentColor = '';
currentShape = '';
currentKind = '';
this.currentColor = '';
this.currentShape = '';
this.currentKind = '';
this.onChange()
},
// THIS IS THE PART OF THE CODE IN QUESTION I THINK
loadImages: function () {
var vm = this;
axios.get('myimagedata.json')
.then(function (response) {
vm.images = response.data.images;
})
.catch(function (error) {
vm.images = 'An Error occured.' + error;
});
}
},
});
</script>
</body>
</html>
And this is the external JSON file "myimagedata.json" I try to load with axios:
{
"images": [
{
"id": 1,
"kind": ["A"],
"color": ["Green", "Blue"],
"shape": ["Square"],
"pic": "http://r.ddmcdn.com/s_f/o_1/cx_462/cy_245/cw_1349/ch_1349/w_720/APL/uploads/2015/06/caturday-shutterstock_149320799.jpg",
"url": "http://r.ddmcdn.com/s_f/o_1/cx_462/cy_245/cw_1349/ch_1349/w_720/APL/uploads/2015/06/caturday-shutterstock_149320799.jpg",
"title": "A"
},
{
"id": 2,
"kind": ["B"],
"color": ["Green", "Red"],
"shape": ["Circle"],
"pic": "https://www.kimballstock.com/pix/DOG/05/DOG-05-JE0078-01P.JPG",
"url": "https://www.kimballstock.com/pix/DOG/05/DOG-05-JE0078-01P.JPG",
"title": "B"
}
]
}
In axios you should be able to do something like is below. You may need to write a var self = this. External libs rewrite this as their own so to access the vue this variable you will need to set a variable beforehand and use the new variable to set your data. In the future please show your code in question like your loadImages() and the error if any you were getting.
var self = this
axios.get('/myimagedata.json')
.then(function (response) {
self.images = response.data.images
})
.catch(function (err) {
console.error(err)
})
With your json response here
{
"images": [{
"id": 1,
"kind": ["A"],
"color": ["Green", "Blue"],
"shape": ["Square"],
"pic": "http://r.ddmcdn.com/s_f/o_1/cx_462/cy_245/cw_1349/ch_1349/w_720/APL/uploads/2015/06/caturday-shutterstock_149320799.jpg",
"url": "http://r.ddmcdn.com/s_f/o_1/cx_462/cy_245/cw_1349/ch_1349/w_720/APL/uploads/2015/06/caturday-shutterstock_149320799.jpg",
"title": "A"
},
{
"id": 2,
"kind": ["B"],
"color": ["Green", "Red"],
"shape": ["Circle"],
"pic": "https://www.kimballstock.com/pix/DOG/05/DOG-05-JE0078-01P.JPG",
"url": "https://www.kimballstock.com/pix/DOG/05/DOG-05-JE0078-01P.JPG",
"title": "B"
}
]
}