I'm trying to load an image on canvas using Backbone + KineticJS. However the image doesn't seem to appear.
First I load the images using a model. (I'm loading the image locally so its already available)
var KineticModel = Backbone.Model.extend({
myImg: null,
createImg : function() {
var imageObj = new Image();
var kinImg = new Kinetic.Image()
imageObj.onload = function() {
kinImg.setAttrs({
x: 10,
y: 10,
image: imageObj,
width: 578,
height: 400
})
}
imageObj.src = 'test/img/vader.png';
return kinImg;
}
});
Then create the View
var KineticView = Backbone.View.extend({
id: 'container',
stage: null,
layer: null,
initialize: function (options) {
model: options.model;
el: options.el;
this.layer = new Kinetic.Layer();
this.stage = new Kinetic.Stage({ container: this.el, width: 600, height: 600 });
this.stage.add(this.layer);
},
render: function () {
var myImg = this.model.createImg();
this.layer.add(myImg);
this.stage.add(this.layer);
this.stage.draw();
}
});
Finally to tie it all up
var KModel= new KineticModel({});
var imgcontainer = $('#container').get();
view = new KineticView({model:KModel, el:imgcontainer});
view.render();
The page loads without any errors, but no image.
Console logs show that the Image Models have been passed to the layers.
Any help will be greatly appreciated!
Redraw layer after setting attrs:
kinImg.setAttrs({
x: 10,
y: 10,
image: imageObj,
width: 578,
height: 400
});
yourLayer.draw();
Note: you are working with view (Kinetic object) inside Backbone.Model - this is bad approach. Model should works only with data. Move createImg function to View.
Also look at this plugin: https://github.com/slash-system/backbone.kineticview
Related
I'm currently on a ReactJS+Nodejs application, trying to integrate OpenLayers. What I need is to change the GPS position of a marker, in real-time (via socket.io).
So far, I've come up with this code:
this.map = new Map({
target: "map",
layers: [
new TileLayer({
source: new XYZ({
attributions: 'Tiles © ArcGIS',
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'
})
}),
],
view: new View({
center: fromLonLat([-8.455826, 40.168307]),
rotation: 1.1344640138,
easing: 0.5
})
});
var vectorSource = new VectorSource({});
var markersLayer = new VectorLayer({
source: vectorSource,
});
this.map.addLayer(markersLayer);
var point1 = new Point(
fromLonLat([-8.455826, 40.168307])
);
var point2 = new Point(
fromLonLat([-8.456819, 40.166388])
);
var marker = new Feature({
geometry: point1,
name: "My point",
});
vectorSource.addFeature(marker);
var style = new Style({
image: new CircleStyle({
radius: 7,
fill: new Fill({color: 'black'}),
stroke: new Stroke({
color: 'white', width: 2
})
})
});
marker.setStyle(style);
setTimeout(function () {
marker.setGeometry(point2);
marker.getGeometry().translate(40, -40);
}, 3500);
The marker moves, however the transition occurs in an instant. Is there a way to make it move like a "CSS linear transition" to give it a more realistic look?
Using a timer you could split the move into steps along the line between the old and new positions, e.g. for 100 10ms steps
var line = new LineString([oldCoordinates, newCoordinates])];
var step = 0;
var key = setInterval( function() {
if (step < 100) {
step++;
marker.setGeometry(new Point(line.getCoordinateAt(step/100)));
} else {
clearInterval(key);
}
}, 10);
You might also be able to base something on the flight animation example https://openlayers.org/en/latest/examples/flight-animation.html
I'm developing an application in DevExtreme Mobile. In application, I use DXMap in this application. How can I use the marker clusterer structure in DevExtreme Mobile App?
You can use Google Maps Marker Clusterer API to create and manage per-zoom-level clusters for a large number of DevExtreme dxMap markers. Here is an example:
dxMap Marker Clusterer
This example is based on the approach described in the Google Too Many Markers! article
Here is sample code:
$("#dxMap").dxMap({
zoom: 3,
width: "100%",
height: 800,
onReady: function (s) {
var map = s.originalMap;
var markers = [];
for (var i = 0; i < 100; i++) {
var dataPhoto = data.photos[i];
var latLng = new google.maps.LatLng(dataPhoto.latitude, dataPhoto.longitude);
var marker = new google.maps.Marker({
position: latLng
});
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers);
}
});
The kry is to use the google maps api. I did it for my app, here how.
This the html, very simple:
<div data-options="dxView : { name: 'map', title: 'Punti vendita', pane: 'master', secure:true } ">
<div data-bind="dxCommand: { id: 'back', behavior: 'back', type: 'back', visible: false }"></div>
<div data-options="dxContent : { targetPlaceholder: 'content' } ">
<div style="width: 100%; height: 100%;">
<div data-bind="dxMap:options"></div> <!--this for the map-->
<div id="large-indicator" data-bind="dxLoadIndicator: {height: 60,width: 60}" style="display:inline;z-index:99;" />
<div data-bind="dxPopover: {
width: 200,
height: 'auto',
visible: visible,
}">
</div>
</div>
</div>
</div>
When the page loads, the app read the gps coordinates:
function handleViewShown() {
navigator.geolocation.getCurrentPosition(onSuccess, onError, options);
jQuery("#large-indicator").css("display", "none"); //this is just a gif to indicate the user to wait the end of the operation
}
If the gps location is correctly read, I save the coordinates (the center of the map):
function onSuccess(position) {
var lat1 = position.coords.latitude;
var lon1 = position.coords.longitude;
center([lat1, lon1]);
}
And these are the options I set to my dxMap:
options: {
showControls: true,
key: { google: "myGoogleApiKey" },
center: center,
width: "100%",
height: "100%",
zoom: zoom,
provider: "google",
mapType: "satellite",
autoAdjust: false,
onReady: function (s) {
LoadPoints();
var map = s.originalMap;
var markers = [];
for (var i = 0; i < MyPoints().length; i++) {
var data = MyPoints()[i];
var latLng = new google.maps.LatLng(data.location[0], data.location[1]);
var marker = createMarker(latLng, data.title, map, data.idimp);
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers, { imagePath: 'images/m' });
}
},
Where MyPoints is populated calling LoadPoints:
function LoadPoints() {
$.ajax({
type: "POST",
async:false,
contentType: "application/json",
dataType: "json",
url: myApiUrl,
success: function (Response) {
var tempArray = [];
for (var point in Response) {
var location = [Response[p]["latitudine"], Response[p]["longitudine"]];
var title = Response[p]["name"] + " - " + Response[p]["city"];
var temp = { title: title, location: location, tooltip: title, onClick: GoToNavigator, idpoint: Response[p]["id"] };
tempArray.push(temp);
}
MyPoints(tempArray);
},
error: function (Response) {
jQuery("#large-indicator").css("display", "none");
var mex = Response["responseText"];
DevExpress.ui.notify(mex, "error");
}
});
}
Note that in the folder Myproject.Mobile/images I included the images m1.png, m2.png, m3.png, m4.png and m5.png.
You can found them here.
I created 2 panels like that with the framework ExtJS (i know it's not the best way):
var panel = Ext.create("Ext.panel.Panel", {
title: "first panel",
width: 400,
height: 250,
renderTo: Ext.getBody(),
html: "test 1"
});
panel = Ext.create("Ext.panel.Panel", {
title: "second panel",
width: 400,
height: 250,
renderTo: Ext.getBody(),
html: "test 2"
});
Now I have 2 panels in my browser. And now if I do this:
panel.destroy();
It destroys only the last one.
So my question is : How can I destroy the first panel? Is there a method which contains all the panels in the browser? Do I store the IDs' panels each time in order to destroy them later?...
Try this:
var objArray = Ext.ComponentQuery.query("Ext.panel.Panel");
objArray contains all the panel objects.
Now run a for loop and destroy all the objects .
If you make them different variables (or an array that you manage), you can destroy them individually:
var panel1 = Ext.create("Ext.panel.Panel", {
...
});
var panel2 = Ext.create("Ext.panel.Panel", {
...
});
panel1.destroy();
panel2.destroy();
Or this:
var panels = [];
var panels[0] = Ext.create("Ext.panel.Panel", {
...
});
var panels[1] = Ext.create("Ext.panel.Panel", {
...
});
for (var i=0; i<panels.length; i++)
{
panels[i].destroy();
}
I have the following setup:
class App.Views.Maps extends Backbone.View
el: '#map'
events:
initialize: ->
#searchModel = new App.Models.Search()
#view = new App.Views.MapBox(map: this)
#render()
render: ->
#loadMap()
$("[rel=tooltip]").tooltip()
loadMap: =>
osmMapType = new google.maps.ImageMapType(
getTileUrl: (coord, zoom) ->
"http://tile.openstreetmap.org/#{zoom}/#{coord.x}/#{coord.y}.png"
tileSize: new google.maps.Size(256, 256)
isPng: true
alt: "OpenStreetMap layer"
name: "OSM"
maxZoom: 19
)
cloudMadeMapType = new google.maps.ImageMapType(
getTileUrl: (coord, zoom) ->
"http://b.tile.cloudmade.com/111/54912/256/#{zoom}/#{coord.x}/#{coord.y}.png"
tileSize: new google.maps.Size(256, 256)
isPng: true
alt: "CloudMade layer"
name: "CMade"
maxZoom: 13
)
lat = 51.503
lng = -0.113
latlng = new google.maps.LatLng(lat, lng)
options =
zoom: 10
center: latlng
mapTypeId: 'OSM'
#gMap = new google.maps.Map(document.getElementById("map"), options)
#gMap.mapTypes.set('OSM', osmMapType)
#gMap.mapTypes.set('CloudMade', cloudMadeMapType)
#gMap.setMapTypeId('CloudMade')
allowedBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(51.278, -0.536)
new google.maps.LatLng(51.701, 0.309)
)
lastValidCenter = new google.maps.LatLng(51.503,-0.113)
google.maps.event.addListener #gMap, "dragend", =>
if allowedBounds.contains(#gMap.getCenter())
lastValidCenter = #gMap.getCenter()
return
$('#myModal').modal(backdrop: true)
$('#myModal').on('hide', =>
origin = new google.maps.LatLng(51.438264485659836,-0.05715396179630261)
#gMap.setCenter(origin)
center = google.maps.LatLng(51.503,-0.113)
#gMap.panTo(origin)
)
#initLabel()
initLabel: =>
#rendered = view.render().el
#console.log rendered
#initLabel = new InfoBubble(
position: new google.maps.LatLng(51.44115356738888, 0.14849636779354114)
maxWidth: 240
maxHeight: 210
padding: 0
content: '<div class="tooltip_header"></div>'
tabPadding: 15
backgroundColor: 'black'
borderRadius: 0
arrowSize: 10
borderWidth: 0
borderColor: '#AB2424'
disableAutoPan: true
hideCloseButton: false
arrowPosition: 0.5
backgroundClassName: 'phoney'
tabClassName: 'tabClass'
activeTabClassName: 'activeTabClass'
arrowStyle: 2
)
#initLabel.open(#gMap)
This loads a map and then loads an InfoBubble ontop of the map. It loads it with the content <div class="tooltip_header"></div>
After this has loaded, if I append the loadMap and add
view = new App.Views.MapBox()
view.render().el
which attempts to load the view:
class App.Views.MapBox extends Backbone.View
el: '.tooltip_header'
events:
'click .testdrive' : 'loadTestDrive'
'click .test' : 'loadTestDrive'
template: JST["app/backbone/templates/mapbox"]
initialize: ->
#render()
render: ->
$(#el).html(#template())
this
loadTestDrive: ->
console.log #options.map
console.log "yessss"
#options.map.loadTestDrive()
Nothing happens... however if I go into console and do:
view = new App.Views.MapBox({map: this})
The content is rendered inside the Infobubble ontop of the map.
I think its because the load of InfoBubble is Asynchronous and I am calling the div to be rendered before it exists. But I have tried delay loading and it still happens.
What is the best way to get this view to render after the infobubble is loaded and the div is therefore available. This is why it works in console. but not on load.
Just use google maps events to listen to when the map is fully loaded like this
google.maps.event.addListener(map, 'tilesloaded', _.bind(function() {
this.render();
google.maps.event.clearListeners(map, 'tilesloaded');
},this));
With this you are 100% sure the map is rendered and the google.maps globals are avaliable and initialized.
I wrote this code to create chart, table and toolbar.
google.load("visualization", "1", { packages: ["corechart"] });
google.load('visualization', '1', { packages: ['table'] });
//google.setOnLoadCallback(drawChart);
function drawChart() {
$.ajax({
type: "GET",
url: '#Url.Action("GunlukOkumalar", "Enerji")',
data: "startDate=" + $('#start_date').val() + "&endDate=" + $('#end_date').val() + "&sayac_id=" + $("#sayaclar").val(), //belirli aralıklardaki veriyi cekmek için
success: function (result) {
if (result.success) {
var evalledData = eval("(" + result.chartData + ")");
var opts = { curveType: "function", width: '100%', height: 500, pointSize: 5 };
new google.visualization.LineChart($("#chart_div").get(0)).draw(new google.visualization.DataTable(evalledData, 0.5), opts);
$('#chart_div').show();
var visualization;
var data;
var options = { 'showRowNumber': true };
data = new google.visualization.DataTable(evalledData, 0.5);
// Set paging configuration options
// Note: these options are changed by the UI controls in the example.
options['page'] = 'enable';
options['pageSize'] = 10;
options['pagingSymbols'] = { prev: 'prev', next: 'next' };
options['pagingButtonsConfiguration'] = 'auto';
// Create and draw the visualization.
visualization = new google.visualization.Table(document.getElementById('table'));
visualization.draw(data, options);
var components = [
{ type: 'html', datasource: data },
{ type: 'csv', datasource: data }
];
var container = document.getElementById('toolbar_div');
google.visualization.drawToolbar(container, components);
return false;
}
else {
$('#chart_div').html('<span style="color:red;"><b>' + result.Error + '</b></span>');
$('#chart_div').show();
$('#table').html('<span style="color:red;"><b>' + result.Error + '</b></span>');
$('#table').show();
return false;
}
}
});
}
Google example
function drawToolbar() {
var components = [
{type: 'igoogle', datasource: 'https://spreadsheets.google.com/tq?key=pCQbetd-CptHnwJEfo8tALA',
gadget: 'https://www.google.com/ig/modules/pie-chart.xml',
userprefs: {'3d': 1}},
{type: 'html', datasource: 'https://spreadsheets.google.com/tq?key=pCQbetd-CptHnwJEfo8tALA'},
{type: 'csv', datasource: 'https://spreadsheets.google.com/tq?key=pCQbetd-CptHnwJEfo8tALA'},
{type: 'htmlcode', datasource: 'https://spreadsheets.google.com/tq?key=pCQbetd-CptHnwJEfo8tALA',
gadget: 'https://www.google.com/ig/modules/pie-chart.xml',
userprefs: {'3d': 1},
style: 'width: 800px; height: 700px; border: 3px solid purple;'}
];
var container = document.getElementById('toolbar_div');
google.visualization.drawToolbar(container, components);
};
Google get dataSource from url, but I get dataSource dynamicly from controller. When I try to export It forwards page to another page like this:
http://localhost:49972/Enerji/%5Bobject%20Object%5D?tqx=out%3Acsv%3B
How can I use exporting toolbar for dynamic Json data? Is there any example about this topic?
I also had this problem and after a lot of trawling I found this!
https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
I haven't implemented it yet but I reckon it's the way to go.