How to add Phylotree.js to nuxt? - vue.js

I installed phylotreejs using the following command:
npm install --save phylotree
When I try to import this into a page like this:
import * as d3 from 'd3';
import phylotree from 'phylotree/build/phylotree';
I get the following error:
Cannot read property 'phylotree' of undefined
It would be really helpful if I can understand what's going on here.
I read and tried the following things by reading nuxt documentation [https://nuxtjs.org/faq/]
import phylotree from '~/node_modules/phylotree/build/phylotree.js'
export default {
head () {
return {
script: [
{ src: '~/node_modules/phylotree/build/phylotree.js' }
],
}
},
}
but nothing seems to work
Following is the Vue page, I'm trying to create:
<template>
<div>
<section class="section">
<div class="container">
<div id="phylotree"></div>
</div>
</section>
</div>
</template>
<script>
import * as d3 from 'd3';
import phylotree from 'phylotree';
import _ from 'lodash';
export default {
data:() => ({
example_tree : "(((EELA:0.150276,CONGERA:0.213019):0.230956,(EELB:0.263487,CONGERB:0.202633):0.246917):0.094785,((CAVEFISH:0.451027,(GOLDFISH:0.340495,ZEBRAFISH:0.390163):0.220565):0.067778,((((((NSAM:0.008113,NARG:0.014065):0.052991,SPUN:0.061003,(SMIC:0.027806,SDIA:0.015298,SXAN:0.046873):0.046977):0.009822,(NAUR:0.081298,(SSPI:0.023876,STIE:0.013652):0.058179):0.091775):0.073346,(MVIO:0.012271,MBER:0.039798):0.178835):0.147992,((BFNKILLIFISH:0.317455,(ONIL:0.029217,XCAU:0.084388):0.201166):0.055908,THORNYHEAD:0.252481):0.061905):0.157214,LAMPFISH:0.717196,((SCABBARDA:0.189684,SCABBARDB:0.362015):0.282263,((VIPERFISH:0.318217,BLACKDRAGON:0.109912):0.123642,LOOSEJAW:0.397100):0.287152):0.140663):0.206729):0.222485,(COELACANTH:0.558103,((CLAWEDFROG:0.441842,SALAMANDER:0.299607):0.135307,((CHAMELEON:0.771665,((PIGEON:0.150909,CHICKEN:0.172733):0.082163,ZEBRAFINCH:0.099172):0.272338):0.014055,((BOVINE:0.167569,DOLPHIN:0.157450):0.104783,ELEPHANT:0.166557):0.367205):0.050892):0.114731):0.295021)",
}),
mounted (){
// const phylotree = require('phylotree');
var tree = d3.layout.phylotree()
.svg(d3.select("#phylotree"));
tree(example_tree).layout();
}
};
</script>
<style scoped>
#spaced {
letter-spacing: 3px;
}
.section {
padding: 1.5rem 1.5rem;
}
</style>

I was able to figure out what was going on. The d3 version for phylotree.js is v3 while I was using v5. But even then it didn't work. So, I tried it in a simple html file and found out the requirements as in this page Link.
Then tried the following script, it worked. But is there a better way to do this. Can anyone help me figure this out!
<template>
<section class="section">
<div class="container">
<svg id="tree_display" />
</div>
</section>
</template>
<script>
export default {
head () {
return {
script: [
{ src: 'https://d3js.org/d3.v3.min.js' },
{ src: 'https://veg.github.io/phylotree.js/phylotree.js' },
{ src: 'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js' },
],
}
},
mounted (){
var example_tree = "(((EELA:0.150276,CONGERA:0.213019):0.230956,(EELB:0.263487,CONGERB:0.202633):0.246917):0.094785,((CAVEFISH:0.451027,(GOLDFISH:0.340495,ZEBRAFISH:0.390163):0.220565):0.067778,((((((NSAM:0.008113,NARG:0.014065):0.052991,SPUN:0.061003,(SMIC:0.027806,SDIA:0.015298,SXAN:0.046873):0.046977):0.009822,(NAUR:0.081298,(SSPI:0.023876,STIE:0.013652):0.058179):0.091775):0.073346,(MVIO:0.012271,MBER:0.039798):0.178835):0.147992,((BFNKILLIFISH:0.317455,(ONIL:0.029217,XCAU:0.084388):0.201166):0.055908,THORNYHEAD:0.252481):0.061905):0.157214,LAMPFISH:0.717196,((SCABBARDA:0.189684,SCABBARDB:0.362015):0.282263,((VIPERFISH:0.318217,BLACKDRAGON:0.109912):0.123642,LOOSEJAW:0.397100):0.287152):0.140663):0.206729):0.222485,(COELACANTH:0.558103,((CLAWEDFROG:0.441842,SALAMANDER:0.299607):0.135307,((CHAMELEON:0.771665,((PIGEON:0.150909,CHICKEN:0.172733):0.082163,ZEBRAFINCH:0.099172):0.272338):0.014055,((BOVINE:0.167569,DOLPHIN:0.157450):0.104783,ELEPHANT:0.166557):0.367205):0.050892):0.114731):0.295021)";
var tree = d3.layout.phylotree()
.svg(d3.select("#tree_display"));
tree(example_tree).layout();
}
};
</script>
<style scoped>
#spaced {
letter-spacing: 3px;
}
.section {
padding: 1.5rem 1.5rem;
}
</style>

Related

TypeError: this.$store is undefined

I'm following a Vue 2 tutorial but got stuck by this error. I've checked multiple questions before posting this one because I'm still unsure of what did I do wrong. Any input will be appreciated!
App.vue code:
<template>
<div id="app">
<!-- <img alt="Vue logo" src="./assets/logo.png"> -->
<!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
<TodoApp />
</div>
</template>
<script>
// import HelloWorld from './components/HelloWorld.vue'
import TodoApp from './components/TodoApp.vue';
export default {
name: 'App',
components: {
// HelloWorld,
TodoApp
}
}
</script>
body {
font-family: "Franklin Gothic Medium", "Arial Narrow", Arial, sans-serif;
line-height: 1.6;
background: #e8f7f0;
}
.container {
max-width: 1100px;
margin: auto;
overflow: auto;
padding: 0 2rem;
}
<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>
Store (index.js) code:
import Vuex from 'vuex';
import Vue from 'vue';
import TodoModule from './modules/TodoModule.js';
// Load vuex
Vue.use(Vuex);
// Create store
export default new Vuex.Store({
modules: {
TodoModule
}
});
Main.js code:
import Vue from 'vue'
import App from './App.vue'
import store from './store'
Vue.config.productionTip = false
new Vue({
store,
render: h => h(App),
}).$mount('#app')
TodoApp.vue code:
<template>
<div>
<h3>Vuex Todo App</h3>
<div class="todos">
<div class="todo" v-for="todo in allTodos" :key="todo.id">
{{ todo.title }}
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
name: "TodoApp",
computed: mapGetters(['allTodos'])
};
</script>
<style>
</style>
TodoModule.js code:
// import axios from "axios";
const state = {
todos: [
{
id: 1,
title: "first todo"
},
{
id: 2,
title: "second todo"
},
{
id: 3,
title: "third todo"
}
]
};
const getters = {
allTodos: state => state.todos
};
const actions = {};
const mutations = {};
export default {
state,
getters,
actions,
mutations
}
No Error on Compiler:
Error on Browser Console:
=== UPDATE ===
I still haven't fix this issue and I have tried restarting the localhost server, even my own laptop to check if it'll fix it.. no luck there.
From what I've read from answers, is it possible that this error happen because of my vue installation? Or perhaps I forgot to install something else when starting the development?
=== UPDATE 2 ===
Found the culprit, apparently my vue and vuex npm package either got corrupted or has a conflict, changing the version of vue to 2.7.8 and vuex to 3.0.1 then rerun npm i (after deleting the node_modules and package-lock.json) has fixed the issue!
Thanks for all the help!
I got the same problem while using Vue 2.
npm uninstall vuex
then
npm i vuex#3.0.1
npm install vuex by default npm installs version 4 which is not supported by Vue 2
https://github.com/vuejs/vuex/releases
Your code seems ok.
I could reproduce with no erros using TodoModule below.
const TodoModule = {
state: {
todos: [{ title: "1" }, { title: "2" }, { title: "3" }, { title: "4" }]
},
getters: {
allTodos: (state) => state.todos
}
};
export default TodoModule;
If error continues, you could check the naming on your files.
The store index.js as you said should be named as store.js.
Or perhaps restart server.
I think I might have actually done the same youtube tutorial on vuex state management but I didn't use the mapGetter helper function, instead, I used the vanilla functions of vuex for getting and setting global variables.
main.js
store: new vuex.Store({
state: {
user: {}
},
mutations: {
setUser(state, payload){
state.user = payload;
}
},
getters: {
getUser: state => state.user,
}})
any-component.js
this.user = this.$store.getters.getUser; //get
this.$store.commit("setUser", this.user); //set
I think you should change getter inTo
export default {
name: "TodoApp",
computed: mapGetters(['allTodos'])
};
===>
export default {
name: "TodoApp",
computed: {
...mapGetters(['allTodos'])
}
};

NuxtJS: styles of inline SVG not exported to resulting CSS

I want to style inline SVG, but NuxtJS (or better say WebPack) doesn't include this styling into output CSS:
<template>
<header>
<NuxtLink to="/" v-html="logoIco" class="logo"></NuxtLink>
</header>
</template>
<script>
export default {
name: 'HeaderComponent',
computed: {
logoIco() {
return require(`assets/images/logo.svg?raw`);
},
},
};
</script>
<style scoped lang="scss">
header {
.logo {
background: red; // this style included in result CSS
svg {
background: yellow; // and this NOT
}
}
}
</style>
WebPack doesn't see any SVG during build and doesn't include header .logo svg rule in resulting CSS.
How this can be done?
I've found an idea here: https://github.com/nuxt-community/svg-module/issues/72
This code works as expected:
<template>
<header>
<NuxtLink to="/" v-html="logoIco" class="logo">
<component :is="require(`assets/images/logo.svg?inline`)"></component>
</NuxtLink>
</header>
</template>
<script>
export default {
name: 'HeaderComponent',
};
</script>
<style scoped lang="scss">
header {
.logo {
background: red; // this style included in result CSS
svg {
background: yellow; // and this now also included
}
}
}
</style>

[Vue warn]: Failed to resolve component, possible import error

I made a Vue3 project using the Vue CLI, and have a parent component('ReactionTimer') and a child component('Block') in the same folder('./components/').
I tried importing 'Block' into 'ReactionTimer', but got the following error:
[Vue warn]: Failed to resolve component: Block
at ReactionTimer
ReactionTimer.vue
<template>
<h1>Reaction Timer</h1>
<button #click="startTimer" :disabled="isTimerOn">Play</button>
<Block v-if="isTimerOn" :delay="delay" />
</template>
<script>
import Block from '../components/Block'
export default {
name: 'ReactionTimer',
components: {},
data() {
return {
isTimerOn: false,
delay: null
}
},
methods: {
startTimer() {
this.delay = 2000 + Math.random() * 5000;
this.isTimerOn = true
//console.log(this.delay)
}
}
}
</script>
Block.vue
<template>
<div class="block">
click me
</div>
</template>
<script>
export default {
props: 'delay'
}
</script>
<style>
.block {
width: 400px;
border-radius: 20px;
background: green;
color: aliceblue;
text-align: center;
padding: 100px 0;
margin: 40px auto;
}
</style>
I tried every combination of
import Block from '../components/Block'
import Block from '../components/Block.vue'
import Block from './Block'
import Block from './Block.vue'
You should add it to components option :
...
<script>
import Block from '../components/Block.vue'
export default {
name: 'ReactionTimer',
components: {Block },
...

Convert a VUE.JS component to web app with correct CSS styling

I have a vue.js component (vue polygon cropper) under src/App.vue like below:
<template>
<div id="app">
<h1 class="mb-4 mt-2 alert-success">Vue Image Cropper</h1>
<div>
<b-img :src="resultImage" alt="Responsive image" fluid v-show="showResult"></b-img>
<div v-show="showResult">
<b-link :href="resultImage" download="result.png">Download Image</b-link>
</div>
</div>
<div>
<polygonCrop :canvasClass="'some-class'"
:height="600"
:imageSource="imgSrc"
:showCanvas="show"
:showPointer="showPointer"
:width="800"
ref="canvas"
></polygonCrop>
</div>
<b-row>
<b-col>
<b-form-group>
<b-form-file
:state="Boolean(file)"
#change="setImage"
accept="image/*"
class="col-sm-6 mt-2"
drop-placeholder="Drop file here..."
placeholder="Choose a file or drop it here..."
size="lg"
v-model="file"
></b-form-file>
<div class="mt-3">Selected file: {{ file ? file.name : '' }}</div>
</b-form-group>
<b-button #click.prevent="crop" variant="success">Crop</b-button>
<b-button #click.prevent="undo" variant="warning">Undo</b-button>
<b-button #click.prevent="redo" variant="primary">Redo</b-button>
<b-button #click.prevent="reset" variant="danger">Reset</b-button>
</b-col>
</b-row>
</div>
</template>
<script>
// import polygonCrop from '../../dist/PolygonCropper.umd';
import polygonCrop from 'vue-polygon-cropper';
export default {
name: 'App',
data() {
return {
imgSrc: '/demo.png',
file: null,
show: false,
showResult: false,
showPointer: true,
resultImage: ""
};
},
components: {
polygonCrop
},
methods: {
setImage(e) {
const file = e.target.files[0];
if (!file && file.type.indexOf('image/') === -1) {
alert('Please select an image file');
return;
}
if (typeof FileReader === 'function') {
const reader = new FileReader();
reader.onload = (event) => {
this.imgSrc = event.target.result;
this.show = true;
};
reader.readAsDataURL(file);
} else {
alert('Sorry, FileReader API not supported');
}
},
crop: function () {
this.$refs.canvas.crop();
this.resultImage = this.$refs.canvas.resultImage;
this.show = false;
this.showResult = true;
},
undo: function () {
this.$refs.canvas.undo();
},
redo: function () {
this.$refs.canvas.redo();
},
reset: function () {
this.show = true;
this.showResult = false;
this.$refs.canvas.reset();
}
}
};
</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;
}
.some-class {
border: 1px solid #2c3e50;
}
</style>
My main.js under src directory is as follows:
import Vue from 'vue';
import App from './App.vue';
import {BootstrapVue, IconsPlugin} from 'bootstrap-vue';
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap-vue/dist/bootstrap-vue.css';
Vue.config.productionTip = false;
Vue.use(BootstrapVue);
Vue.use(IconsPlugin);
new Vue({
render: h => h(App),
}).$mount('#app');
I need to do to convert this to web component, so I have done some changes in vue.config.js file to use the correct CSS styling:
function enableShadowCss(config) {
const configs = [
config.module.rule('vue').use('vue-loader'),
config.module.rule('css').oneOf('vue-modules').use('vue-style-loader'),
config.module.rule('css').oneOf('vue').use('vue-style-loader'),
config.module.rule('css').oneOf('normal-modules').use('vue-style-loader'),
config.module.rule('css').oneOf('normal').use('vue-style-loader'),
config.module.rule('postcss').oneOf('vue-modules').use('vue-style-loader'),
config.module.rule('postcss').oneOf('vue').use('vue-style-loader'),
config.module.rule('postcss').oneOf('normal-modules').use('vue-style-loader'),
config.module.rule('postcss').oneOf('normal').use('vue-style-loader'),
config.module.rule('scss').oneOf('vue-modules').use('vue-style-loader'),
config.module.rule('scss').oneOf('vue').use('vue-style-loader'),
config.module.rule('scss').oneOf('normal-modules').use('vue-style-loader'),
config.module.rule('scss').oneOf('normal').use('vue-style-loader'),
config.module.rule('sass').oneOf('vue-modules').use('vue-style-loader'),
config.module.rule('sass').oneOf('vue').use('vue-style-loader'),
config.module.rule('sass').oneOf('normal-modules').use('vue-style-loader'),
config.module.rule('sass').oneOf('normal').use('vue-style-loader'),
config.module.rule('less').oneOf('vue-modules').use('vue-style-loader'),
config.module.rule('less').oneOf('normal-modules').use('vue-style-loader'),
config.module.rule('stylus').oneOf('vue').use('vue-style-loader'),
config.module.rule('stylus').oneOf('normal-modules').use('vue-style-loader'),
];
configs.forEach(c => c.tap(options => {
options.shadowMode = true;
return options;
}));
}
module.exports = {
// https://cli.vuejs.org/guide/webpack.html#chaining-advanced
chainWebpack: config => {
enableShadowCss(config);
}
}
The problem is that when I generate a web component:
npm run build -- --target wc --name app-1
And it generates the web component inside dist folder as follows, but when I go to demo.html, it doesn't render CSS correctly, and the component doesn't show up correctly:
C:\ThermoAnalyser\vue_js\project1\dist>dir
Volume in drive C is Windows-SSD
Volume Serial Number is 18EE-B4F6
Directory of C:\ThermoAnalyser\vue_js\project1\dist
27/12/2020 11:24 PM <DIR> .
27/12/2020 11:24 PM <DIR> ..
27/12/2020 11:24 PM 46,521 app-1.js
27/12/2020 11:24 PM 55,715 app-1.js.map
27/12/2020 11:24 PM 18,236 app-1.min.js
27/12/2020 11:24 PM 71,872 app-1.min.js.map
27/12/2020 11:24 PM 149 demo.html
5 File(s) 192,493 bytes
2 Dir(s) 300,479,696,896 bytes free
Also when I run:
npm run build
It is giving me this error:
- Building for production... ERROR TypeError: Cannot set property 'shadowMode' of undefined
TypeError: Cannot set property 'shadowMode' of undefined
at C:\ThermoAnalyser\vue_js\project1\vue.config.js:26:24
at Object.tap (C:\ThermoAnalyser\vue_js\project1\node_modules\webpack-chain\src\Use.js:14:20)
at C:\ThermoAnalyser\vue_js\project1\vue.config.js:25:26
at Array.forEach (<anonymous>)
at enableShadowCss (C:\ThermoAnalyser\vue_js\project1\vue.config.js:25:11)
at chainWebpack (C:\ThermoAnalyser\vue_js\project1\vue.config.js:34:5)
at C:\ThermoAnalyser\vue_js\project1\node_modules\#vue\cli-service\lib\Service.js:236:40
I would greatly appreciate if someone help to generate the web component of my codes with correct CSS styling?
The enableShadowCss() code you have in vue.config.js is only needed for development mode. shadowMode is already enabled in the production build, so that isn't going to help you in your build process, and you should remove it.
The BootstrapVue components are not initialized in your main app, so you'll see error messages in the browser console, indicating unknown components.
To enable the third party components, you can initialize BootstrapVue in your target component to be exported (src/App.vue in this case):
<script>
import {BootstrapVue, IconsPlugin} from 'bootstrap-vue';
Vue.config.productionTip = false;
Vue.use(BootstrapVue);
Vue.use(IconsPlugin);
export default {
//...
}
</script>
In addition, you'll need to import the styles in the target component's <style> block so that they're included in the component's Shadow CSS:
<style>
#import '~bootstrap/dist/css/bootstrap.css';
#import '~bootstrap-vue/dist/bootstrap-vue.css';
/*...*/
</style>
GitHub PR

Vue v-cloak directive does not work on component

I added v-cloak directive on the top div in my component and added css as in docs, set a timeout but it does not work I can see else content and the form styles.
Component code:
<div class="form-in-wrap" v-cloak>
<ul id="example-1" v-if="reports.length>0">
<report-component v-for="report in reports" :report="report" :key="report.id" :options="options">
</report-component>
</ul>
</div>
Component script:
<script>
import ReportComponent from "./ReportComponent";
export default {
components: {ReportComponent},
data: function () {
return {
reports: {
type: Array,
},
report: {
...
},
}
},
created: function () {
var self = this
setTimeout(function () {
self.loadData('/reports')
}, 2000);
},
methods: {
loadData: function() {
get method
}
}
</script>
<style scoped>
[v-cloak] {
display: none !important;
}
</style>
All example creates a Vue instance, but I am using export default in my component. Also it is not a main component, it is included with router can this be the case why it does not work?