Instead of creating custom object shape, I already have it as a Vue component. Here is what I have tried:
<template>
<div>
<canvas ref="canvas"></canvas>
<button type="button" #click="addVueComponent()">Add to canvas</button>
</div>
</template>
<script>
import { fabric } from 'fabric';
import CustomComponent from "CustomComponent.vue";
export default {
mounted() {
this.canvas = new fabric.Canvas(this.$refs.canvas);
},
methods:
{
addVueComponent() {
var vueComponent = new Vue({
template: '<custom-component ref="customComp"></custom-component>',
components: { 'custom-component': CustomComponent},
});
vueComponent.$mount();
var customObj = new fabric.Rect({
width: 100,
height: 100,
left: 50,
top: 50,
});
customComponent._element = vueComponent.$refs.customComponent.$el;
this.canvas.add(customComponent);
}
}
}
but instead of a rendered component I am just getting black rectangle as a result.
Is it even possible to add Vue component to canvas and what is the way to do it?
Related
I'm trying to implement a simple world map in a Vue application. I have created a MapContainer component that is then imported into my main app. Below is the code for MapContainer.vue:
<template>
<div
ref="map-root"
style="width: 100%, height: 100%">
</div>
</template>
<script>
import View from 'ol/View';
import Map from 'ol/Map';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
import 'ol/ol.css';
export default {
name: 'MapContainer',
components: {},
props: {},
mounted() {
new Map({
target: this.$refs['map-root'],
layers: [
new TileLayer({
source: new OSM()
})
],
view: new View({
zoom: 0,
center: [0, 0],
constrainResolution: true
})
});
}
}
</script>
<style>
</style>
I am registering the MapContainer component and then simply placing it inside a div in the parent component. When I import this component and try to use it, I get an empty div in place of the map. Does anyone know what I'm doing wrong?
Here is the parent component's code:
<template>
<div>
<map-container></map-container>
</div>
</template>
<script>
import MapContainer from '../mapping/MapContainter.vue';
export default {
components: {
'map-container': MapContainer
}
}
</script>
I fixed this by adding the following class to the div with the ref:
.map {
width: 100% !important;
height: 600px !important;
}
(The !important's might not be strictly necessary).
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<MglMap :accessToken="accessToken" :mapStyle="mapStyle" />
</template>
<script>
import Mapbox from "mapbox-gl";
import { MglMap } from "vue-mapbox";
export default {
components: {
MglMap
},
data() {
return {
accessToken: "pk.eyJ1IjoiYWlzaHdlcnlhIiwiYSI6ImNrYzVyYXBlNzBrZGgzMG8wc3FtZjU5NDAifQ.u4azaXjkh41xSMC1NJLhTw", // your access token. Needed if you using Mapbox maps
mapStyle: "mapbox://styles/aishwerya/ckc5ufmlw0nu11ip289o79bkl" // your map style
};
},
created() {
// We need to set mapbox-gl library here in order to use it in template
this.mapbox = Mapbox;
}
};
</script>
I created the mapbox-gl map but it showing blank screen
I have tried with this link but it didnt worked
I dont what Im missing it clearly shows me blank screen
Here is a simple way to integrate the mapbox application using Vue 2. This example doesn't require NPM or import statements. I would be careful about including your api key on public forums. I have included your api key in order for this example to work.
<script src="https://api.mapbox.com/mapbox-gl-js/v1.11.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.11.0/mapbox-gl.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<style>
#project { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
<div id="project"></div>
<script>
var mapping = new Vue({
el: '#project',
data: {
map: ''
},
mounted(){
mapboxgl.accessToken = 'pk.eyJ1IjoiYWlzaHdlcnlhIiwiYSI6ImNrYzVyYXBlNzBrZGgzMG8wc3FtZjU5NDAifQ.u4azaXjkh41xSMC1NJLhTw';
//create a new mapbox instance
this.map = new mapboxgl.Map({
container: 'project',
'style' : 'mapbox://styles/mapbox/light-v10'
});
//fit the united states to the screen
this.map.fitBounds([[-135, 47], [-60, 25]]);
}
});
</script>
I'm using vue to make an arc gis driven application, because the map's center can changed based on user location, I am setting the default location to some props then passing them into my map component to be called in the map components mounted() hook for rendering.
I think i'm pretty close to doing this correctly but when I log my props in my map component in the console it says they're undefined.
I'm not sure if my app code is at fault or my child component code?
as you can see in my app.vue I am even trying to pass in plain integers to test the values and they are still undefined.
app.vue
<template>
<div id="app">
<web-map v-bind:centerX="-118" v-bind:centerY="34" />
<div class="center">
<b-button class="btn-block" #click="getLocation" variant="primary">My Location</b-button>
</div>
</div>
</template>
<script>
import WebMap from './components/webmap.vue';
export default {
name: 'App',
components: { WebMap },
data(){
return{
lat: -118,
long: 34
}
},
};
</script>
webmap.vue
<template>
<div></div>
</template>
<script>
import { loadModules } from 'esri-loader';
export default {
name: 'web-map',
props:['centerX, centerY'],
data: function(){
return{
X: this.centerX,
Y: this.centerY
}
},
mounted() {
console.log(this.X,this.Y)
// lazy load the required ArcGIS API for JavaScript modules and CSS
loadModules(['esri/Map', 'esri/views/MapView'], { css: true })
.then(([ArcGISMap, MapView]) => {
const map = new ArcGISMap({
basemap: 'topo-vector'
});
this.view = new MapView({
container: this.$el,
map: map,
center: [this.X,this.Y], ///USE PROPS HERE FOR NEW CENTER
zoom: 8
});
});
},
beforeDestroy() {
if (this.view) {
// destroy the map view
this.view.container = null;
}
}
};
</script>
There is a typo. Change:
props:['centerX, centerY'],
to:
props:['centerX', 'centerY'],
new to Vue - learning as I go about exploring.
I'm trying to use a custom object as data source for a v-for situation. So far, not working - I admit I'm not sure how to access data by name in a Vue component.
main.js
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import VueKonva from "vue-konva";
Vue.use(VueKonva);
import RoomBuilder from "#/model/RoomBuilder";
Vue.config.productionTip = false;
new Vue({
router,
store,
render: h => h(App),
data: () => ({
roomBuilder: new RoomBuilder()
})
}).$mount("#app");
The custom object, which may not be wired right into the data provider, is roomBuilder.
Then, in the component where I want to reference this object, I have this code:
<template>
<v-stage ref="stage" :config="stageSize">
<v-layer>
<v-rect ref="background" :config="backgroundConfig"></v-rect>
<v-rect
v-for="room in roomBuilder.getRooms()"
:key="room.id"
:config="room.config"
></v-rect>
</v-layer>
</v-stage>
</template>
<script>
export default {
name: "RoomGrid",
data() {
return {
stageSize: {
width: 1000,
height: 1000
},
backgroundConfig: {
width: 50,
height: 50,
fill: "#2B2B2B"
}
};
},
mounted() {
this.$nextTick(function() {
window.addEventListener("resize", this.fitStageIntoParentContainer);
this.fitStageIntoParentContainer();
});
},
methods: {
fitStageIntoParentContainer() {
const parentElement = this.$parent.$el;
const background = this.$refs.background.getNode();
background
.setAttr("width", parentElement.clientWidth)
.setAttr("height", parentElement.clientHeight);
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss"></style>
The two POJOs are:
RoomBuilder.js
import Room from "#/model/Room";
class RoomBuilder {
construct() {
this.rooms = [new Room(1)];
}
drawOnto(konvaStage) {
console.log(konvaStage);
}
getRooms() {
return this.rooms;
}
}
export default RoomBuilder;
and
Room.js
class Room {
construct(id) {
this.id = id;
this.config = {
x: 10,
y: 10,
fill: "white",
width: 10,
height: 10
};
}
}
export default Room;
Thanks, and go easy on me. I'm typically a server-side guy! I clearly have wired something wrong... have tried
v-for="room in this.$data.roomBuilder.getRooms()"
v-for="room in roomBuilder.getRooms()"
etc.
Clearly there's some magic afoot I don't understand!
Thank you!
When using Konva without vue, I can access and modify stage width like this:
var stage = new Konva.Stage({
container: 'container',
width: stageWidth,
height: stageHeight
});
stage.width(100); //good
I do not how to access stage object and by extension set its width using vuejs:
<template>
<v-stage :config="configKonva">
<v-layer>
<v-circle :config="configCircle"></v-circle>
</v-layer>
</v-stage>
</template>
<script>
export default {
methods: {
setWidth(width) {
//here I want to access stage and set it's width
}
}
}
</script>
You need to add "ref" for v-stage. After that you'll get direct access to the v-stage component instance. So after that you can call its method getStage().
<v-stage :config="configKonva" ref="konva">
...
export default {
methods: {
setWidth(width) {
this.$refs.konva.getStage().width(640);
}
}