openlayer3 vector layer text display repeated - openlayers-3

This is a picture which shows the number of my shops at this place, but why on my map the number 90 is repeated?. I am using a styleFunc to determine the color, the cold is something like:
function styleFunction(feature) {
var destCount = feature.get("destCount");
var originCount = feature.get("originCount");
if (typeof originCount === "undefined") {
originCount = 0;
}
if (typeof destCount === "undefined") {
destCount = 0;
}
totalPointsCount = destCount + originCount;
totalPointsCount = totalPointsCount.toString();
return getStyle(feature.getProperties().type);
}
function styleFunction(feature) {
var destCount = feature.get("destCount");
var originCount = feature.get("originCount");
if (typeof originCount === "undefined") {
originCount = 0;
}
if (typeof destCount === "undefined") {
destCount = 0;
}
totalPointsCount = destCount + originCount;
totalPointsCount = totalPointsCount.toString();
return getStyle(feature.getProperties().type);
}
Code for creating the baseLayer is:
fetch('data/xml/service-meta-data.xml').then(function (response) {
return response.text();
}).then(function (text) {
var result = parser.read(text);
var options = ol.source.WMTS.optionsFromCapabilities(result, {
layer: 'China',
matrixSet: 'EPSG:3857'
});
var baseLayer = new ol.layer.Tile({
opacity: 1,
source: new ol.source.WMTS(options)
});
var map = new ol.Map({
layers: [
baseLayer,
vectorLayer
],
overlays: [infoOverlay],
target: 'map',
view: view
});
})
You can ignore all the data processing, and focus on the stylefunc, can anyone tell me why the number is repeated? Many thxs

Have a look this link Openlayers3 Vector labels.
Tile layers create duplicate labels when you start zooming in. So create it has ImageWMS layer.
var baseLayer = new ol.layer.Image({
opacity: 1,
source: new ol.source.ImageWMS(options)
});

Related

forEachFeatureAtPixel does not work properly

I have the following code,
basically I have two layers one osm laryer, one vector layers, first I add two feature nodes with id 1 and id 2 into the vector layer by single click at two random locations on the map using ol.interaction.draw, then switch to interaction drag by select 'Drag Point' (top left corner), the idea is when drag either one of the two nodes over the other node, the node being dragged shall turn into green node, I can do this by dragging node id 1 to to node id 2 easily, but when i try to drag node id 2 to node id 1, it demands much higher accuracy than vice versa. The only difference between two nodes is node id 1 is created before node id 2.
The problem I see here is in forEachFeatureAtPixel, it rarely detects(or the call back rarely return node id 1) feature node id 1 when dragging node id 2 over node id 1.
I have spent quite a while on this issue. Still cannot figure out why. Really appreciated any help.
Thanks
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Draw and Modify Features</title>
<link rel="stylesheet" href="https://openlayers.org/en/v3.20.1/css/ol.css" type="text/css">
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://openlayers.org/en/v3.20.1/build/ol-debug.js"></script>
</head>
<body>
<form class="form-inline">
<select id="type">
<option value="DrawPoint">Draw Point</option>
<option value="DragPoint">Drag Point</option>
</select>
</form>
<div id="map" class="map"></div>
<script>
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var map = new ol.Map({
layers: [raster],
target: 'map',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 4
})
});
var circle_style = new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({
color: 'rgba(255, 0, 0, 2)'
})
})
});
var overlap_style = new ol.style.Style({
image: new ol.style.Circle({
radius: 8,
fill: new ol.style.Fill({
color: 'rgba(0, 255, 0, 2)'
})
})
});
var features = new ol.Collection();
var featureOverlay = new ol.layer.Vector({
source: new ol.source.Vector({
features: features
}),
style: circle_style
});
featureOverlay.setMap(map);
window.app = {};
var app = window.app;
/**
* #constructor
* #extends {ol.interaction.Pointer}
*/
app.Drag = function () {
ol.interaction.Pointer.call(this, {
handleDownEvent: app.Drag.prototype.handleDownEvent,
handleDragEvent: app.Drag.prototype.handleDragEvent,
handleMoveEvent: app.Drag.prototype.handleMoveEvent,
handleUpEvent: app.Drag.prototype.handleUpEvent
});
this.coordinate12_ = null;
this.cursor_ = 'pointer';
this.feature_ = null;
this.previousCursor_ = undefined;
};
ol.inherits(app.Drag, ol.interaction.Pointer);
app.Drag.prototype.handleDownEvent = function (evt) {
var map = evt.map;
var feature = map.forEachFeatureAtPixel(evt.pixel,
function (feature, layer) {
return feature;
});
if (feature) {
console.log("down: node_id: " + feature.getProperties()['id']);
this.coordinate12_ = evt.coordinate;
this.feature_ = feature;
}
return !!feature;
};
app.Drag.prototype.handleDragEvent = function (evt) {
var map = evt.map;
fs = featureOverlay.getSource().getFeatures();
var feature = map.forEachFeatureAtPixel(evt.pixel,
function (feature, layer) {
return feature;
});
if (!(feature === undefined)) {
console.log("drag: node_id: " + feature.getProperties()['id']);
// console.log("this:" + this.feature_.getId()+ " o: " + feature.getId());
if (this.feature_.getProperties()['id'] != feature.getProperties()['id']) {
console.log("green: node_id: " + feature.getProperties()['id']);
this.feature_.setStyle(overlap_style);
} else {
this.feature_.setStyle(circle_style);
}
}
var deltaX = evt.coordinate[0] - this.coordinate12_[0];
var deltaY = evt.coordinate[1] - this.coordinate12_[1];
var geometry = /** #type {ol.geom.SimpleGeometry} */
(this.feature_.getGeometry());
geometry.translate(deltaX, deltaY);
this.coordinate12_[0] = evt.coordinate[0];
this.coordinate12_[1] = evt.coordinate[1];
};
app.Drag.prototype.handleMoveEvent = function (evt) {
if (this.cursor_) {
var map = evt.map;
var feature = map.forEachFeatureAtPixel(evt.pixel,
function (feature, layer) {
if (this.feature_ != null)
{
console.log("move forEachFeatureAtPixel: node_id: " + feature.getProperties()['id']);
}
return feature;
});
var element = evt.map.getTargetElement();
if (feature) {
if (this.feature_ != null)
{
console.log("move forEachFeatureAtPixel: node_id: " + feature.getProperties()['id']);
}
if (element.style.cursor != this.cursor_) {
this.previousCursor_ = element.style.cursor;
element.style.cursor = this.cursor_;
}
} else if (this.previousCursor_ !== undefined) {
element.style.cursor = this.previousCursor_;
this.previousCursor_ = undefined;
}
}
};
/**
* #param {ol.MapBrowserEvent} evt Map browser event.
* #return {boolean} `false` to stop the drag sequence.
*/
app.Drag.prototype.handleUpEvent = function (evt) {
this.coordinate12_ = null;
this.feature_ = null;
return false;
};
var draw = new ol.interaction.Draw({
features: features,
type: ('Point')
});
var drag = new app.Drag();
var id_count = 0;
draw.on('drawend', function(e) {
e.feature.setProperties({
'id': ++id_count
})
console.log(e.feature, e.feature.getProperties());
});
map.addInteraction(draw);
var typeSelect = document.getElementById('type');
typeSelect.value = 'DrawPoint';
typeSelect.onchange = function () {
if (typeSelect.value == 'DrawPoint')
{
map.removeInteraction(drag);
map.addInteraction(draw);
}else
{
map.removeInteraction(draw);
map.addInteraction(drag);
}
};
</script>
</body>
</html>
Prevent the feature(be it 1st or 2nd) which is being moved to get returned from map.forEachFeatureAtPixel method.
See the below working code snippet.
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Draw and Modify Features</title>
<link rel="stylesheet" href="https://openlayers.org/en/v3.20.1/css/ol.css" type="text/css">
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://openlayers.org/en/v3.20.1/build/ol-debug.js"></script>
</head>
<body>
<form class="form-inline">
<select id="type">
<option value="DrawPoint">Draw Point</option>
<option value="DragPoint">Drag Point</option>
</select>
</form>
<div id="map" class="map"></div>
<script>
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var map = new ol.Map({
layers: [raster],
target: 'map',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 4
})
});
var circle_style = new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({
color: 'rgba(255, 0, 0, 2)'
})
})
});
var overlap_style = new ol.style.Style({
image: new ol.style.Circle({
radius: 8,
fill: new ol.style.Fill({
color: 'rgba(0, 255, 0, 2)'
})
})
});
var features = new ol.Collection();
var featureOverlay = new ol.layer.Vector({
source: new ol.source.Vector({
features: features
}),
style: circle_style
});
featureOverlay.setMap(map);
window.app = {};
var app = window.app;
/**
* #constructor
* #extends {ol.interaction.Pointer}
*/
var dragFeature;
app.Drag = function () {
ol.interaction.Pointer.call(this, {
handleDownEvent: app.Drag.prototype.handleDownEvent,
handleDragEvent: app.Drag.prototype.handleDragEvent,
handleMoveEvent: app.Drag.prototype.handleMoveEvent,
handleUpEvent: app.Drag.prototype.handleUpEvent
});
this.coordinate12_ = null;
this.cursor_ = 'pointer';
this.previousCursor_ = undefined;
};
ol.inherits(app.Drag, ol.interaction.Pointer);
app.Drag.prototype.handleDownEvent = function (evt) {
var map = evt.map;
var feature = map.forEachFeatureAtPixel(evt.pixel,
function (feature, layer) {
return feature;
});
if (feature) {
//console.log("down: node_id: " + feature.getProperties()['id']);
this.coordinate12_ = evt.coordinate;
//this.feature_ = feature;
dragFeature = feature;
}
return !!feature;
};
app.Drag.prototype.handleDragEvent = function (evt) {
var map = evt.map;
fs = featureOverlay.getSource().getFeatures();
// Filter the feature
var feature = map.forEachFeatureAtPixel(evt.pixel,
function (feature, layer) {
if ( feature.getProperties()['id'] != dragFeature.getProperties()['id'] ) {
return feature;
}
});
if (!(feature === undefined)) {
console.log("------------------- drag: node_id: " + feature.getProperties()['id']);
// console.log("this:" + this.feature_.getId()+ " o: " + feature.getId());
if (dragFeature.getProperties()['id'] != feature.getProperties()['id']) {
console.log("green: node_id: " + feature.getProperties()['id']);
dragFeature.setStyle(overlap_style);
}
}
else {
dragFeature.setStyle(circle_style);
}
var deltaX = evt.coordinate[0] - this.coordinate12_[0];
var deltaY = evt.coordinate[1] - this.coordinate12_[1];
var geometry = /** #type {ol.geom.SimpleGeometry} */
(dragFeature.getGeometry());
geometry.translate(deltaX, deltaY);
this.coordinate12_[0] = evt.coordinate[0];
this.coordinate12_[1] = evt.coordinate[1];
};
app.Drag.prototype.handleMoveEvent = function (evt) {
if (this.cursor_) {
var map = evt.map;
var feature = map.forEachFeatureAtPixel(evt.pixel,
function (feature, layer) {
if (dragFeature != null)
{
//console.log("move forEachFeatureAtPixel: node_id: " + feature.getProperties()['id']);
}
return feature;
});
var element = evt.map.getTargetElement();
if (feature) {
if (dragFeature != null)
{
//console.log("move forEachFeatureAtPixel: node_id: " + feature.getProperties()['id']);
}
if (element.style.cursor != this.cursor_) {
this.previousCursor_ = element.style.cursor;
element.style.cursor = this.cursor_;
}
} else if (this.previousCursor_ !== undefined) {
element.style.cursor = this.previousCursor_;
this.previousCursor_ = undefined;
}
}
};
/**
* #param {ol.MapBrowserEvent} evt Map browser event.
* #return {boolean} `false` to stop the drag sequence.
*/
app.Drag.prototype.handleUpEvent = function (evt) {
this.coordinate12_ = null;
//this.feature_ = null;
dragFeature = null;
return false;
};
var draw = new ol.interaction.Draw({
features: features,
type: ('Point')
});
var drag = new app.Drag();
var id_count = 0;
draw.on('drawend', function(e) {
e.feature.setProperties({
'id': ++id_count
})
//console.log(e.feature, e.feature.getProperties());
});
map.addInteraction(draw);
var typeSelect = document.getElementById('type');
typeSelect.value = 'DrawPoint';
typeSelect.onchange = function () {
if (typeSelect.value == 'DrawPoint')
{
map.removeInteraction(drag);
map.addInteraction(draw);
}else
{
map.removeInteraction(draw);
map.addInteraction(drag);
}
};
</script>
</body>
</html>

Bug when converting "synthetic points" example from Openlayers 3.5 to 3.16

Trying to update the example at http://ol3.qtibia.ro/build/examples/synthetic-points.html
to the latest version of Openlayers. Getting a bug I can't figure out; triggered by the pointermove event, as a consequence of the displaySnap function. Play around with the JS fiddle below.
http://jsfiddle.net/1vzp3mwd/7/
var point = null;
var line = null;
var displaySnap = function(coordinate) {
var closestFeature = vectorSource.getClosestFeatureToCoordinate(coordinate);
if (closestFeature === null) {
point = null;
line = null;
} else {
var geometry = closestFeature.getGeometry();
var closestPoint = geometry.getClosestPoint(coordinate);
if (point === null) {
point = new ol.geom.Point(closestPoint);
} else {
point.setCoordinates(closestPoint);
}
if (line === null) {
line = new ol.geom.LineString([coordinate, closestPoint]);
} else {
line.setCoordinates([coordinate, closestPoint]);
}
}
map.render();
};
map.on('pointermove', function(evt) {
if (evt.dragging) {
return;
}
var coordinate = evt.coordinate;
displaySnap(coordinate);
});
map.on('click', function(evt) {
displaySnap(evt.coordinate);
});
var imageStyle = new ol.style.Circle({
radius: 10,
fill: null,
stroke: new ol.style.Stroke({
color: 'rgba(255,255,0,0.9)',
width: 3
})
});
var strokeStyle = new ol.style.Stroke({
color: 'rgba(255,255,0,0.9)',
width: 3
});
map.on('postcompose', function(evt) {
var vectorContext = evt.vectorContext;
if (point !== null) {
vectorContext.setStyle(imageStyle);
vectorContext.drawGeometry(point);
}
if (line !== null) {
vectorContext.setStyle(null, strokeStyle);
vectorContext.drawGeometry(line);
}
});
Here is an updated, working example: http://jsfiddle.net/1vzp3mwd/8/
Here's what I did:
I loaded the "debug" version of the full library to make for nicer stack traces and easier debugging. (Note that you would never want to use this in production.)
I changed your vectorContext.setStyle() calls so that they were called with an ol.style.Style object. See the API docs for more detail.
Here is the relevant part of the updated example:
var stroke = new ol.style.Stroke({
color: 'rgba(255,255,0,0.9)',
width: 3
});
var style = new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: null,
stroke: stroke
}),
stroke: stroke
});
map.on('postcompose', function(evt) {
var vectorContext = evt.vectorContext;
vectorContext.setStyle(style);
if (point !== null) {
vectorContext.drawGeometry(point);
}
if (line !== null) {
vectorContext.drawGeometry(line);
}
});
Make sure to use http://openlayers.org/en/latest/examples/ when looking for examples (this will give you examples for the latest release). You can always get to that from http://openlayers.org/. The Synthetic Points example you are trying to reproduce is located here: http://openlayers.org/en/latest/examples/synthetic-points.html.

trigger a marker click

I am using a Fusion Table and the Google Map API and would like to know if I can automatically trigger an event when a marker is placed.
Currently I can click on the map and I get a customized infowindow, but I want to do the same thing but after geocoding and placing a marker... I would like this to happen automatically.
Here is my code so far:
var FusionTableID = '<?php echo get_theme_mod( 'fusion_id' )?>';
var map = null;
var geocoder = null;
var marker = null;
function initialize() {
geocoder = new google.maps.Geocoder();
var local = new google.maps.LatLng(<?php echo get_theme_mod( 'lat-long' )?>);
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: local,
zoom: <?php echo get_theme_mod( 'zoom' )?>
});
// forces a refresh to from Fusion Tables
//var and=' geometry does not contain "'+new Date().getTime()+'"';
var layer = new google.maps.FusionTablesLayer({
//suppressInfoWindows: true,
query: {
select: "col2\x3e\x3e0",
from: FusionTableID,
where: ""
},
options: {
styleId: 2,
templateId: 2
},
map: map
});
layer.setMap(map);
google.maps.event.addListener(layer, "click", function(e) {
var point = e.latLng.toUrlValue(6);
var latlngStr = point.split(',', 2);
var lat = parseFloat(latlngStr[0]);
var lng = parseFloat(latlngStr[1]);
var latlng = new google.maps.LatLng(lat, lng);
if (marker && marker.setMap) marker.setMap(null);
marker = new google.maps.Marker({
position: latlng,
map: map
});
console.log(e.row['objectid'].value);
var tname = e.row['name'].value; // name
var targetDist = e.row['description'].value; // description
// poplulate the infowindow
e.infoWindowHtml = "<div class=\"grid-100\"><h2>"+tname+"</h2>"+targetDist+"<hr></div>";
});
}
function showAddress() {
var address = document.getElementById('address').value;
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (marker && marker.setMap) marker.setMap(null);
marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
if (results[0].geometry.viewport)
map.fitBounds(results[0].geometry.viewport);
// THIS DOESN'T WORK ****
new google.maps.event.trigger( marker, 'click' );
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
Thanks geocodezip
It isn't really possible to "trigger" a click on a FusionTablesLayer (you can, but you basically need to replicate the information in the click event, which is painful), you can query the table an create your own infowindow on the marker though

How to set responsive for google charts in mvc

<script type="text/javascript">
// Load the Visualization API and the piechart package.
google.load('visualization', '1.0', { 'packages': ['corechart'] });
// Set a callback to run when the Google Visualization API is loaded.
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
$(document).ready(function () {
google.setOnLoadCallback(drawChartCountry);
$("a[href='#tab11']").on('shown.bs.tab', function (e) {
google.load('visualization', '1', {
packages: ['corechart'],
callback: drawChartCountry
});
});
$("a[href='#tab21']").on('shown.bs.tab', function (e) {
google.load('visualization', '1', {
packages: ['corechart'],
callback: drawChartDevice
});
});
$("a[href='#tab31']").on('shown.bs.tab', function (e) {
google.load('visualization', '1', {
packages: ['corechart'],
callback: drawChartVersion
});
});
function drawChartCountry() {
$.post('/AppDashboard/GetCountryChart', {},
function (data) {
var tdata = new google.visualization.DataTable();
tdata.addColumn('string', 'Country');
tdata.addColumn('number', 'No.of Users');
for (var i = 0; i < data.length; i++) {
tdata.addRow([data[i].Name, data[i].Value]);
}
var options = {
title: "",
is3D: true,
//pieSliceText: 'label',
pieStartAngle: 100,
'width': 450,
'height': 350
};
var chart = new google.visualization.PieChart(document.getElementById('chart_country'));
chart.draw(tdata, options);
});
}
function drawChartDevice() {
$.post('/AppDashboard/GetDeviceChart', {},
function (data) {
var devicedata = new google.visualization.DataTable();
devicedata.addColumn('string', 'Device');
devicedata.addColumn('number', 'No.of Users');
for (var i = 0; i < data.length; i++) {
devicedata.addRow([data[i].Name, data[i].Value]);
}
var options = {
title: "",
is3D: true,
pieStartAngle: 100,
'width': 450,
'height': 350
};
var chart = new google.visualization.PieChart(document.getElementById('chart-device'));
chart.draw(devicedata, options);
});
}
function drawChartVersion() {
$.post('/AppDashboard/GetVersionChart', {},
function (data) {
var versiondata = new google.visualization.DataTable();
versiondata.addColumn('string', 'Version');
versiondata.addColumn('number', 'No.of Users');
for (var i = 0; i < data.length; i++) {
versiondata.addRow([data[i].Name, data[i].Value]);
}
var options = {
title: "",
is3D: true,
//pieSliceText: 'label',
pieStartAngle: 100,
'width': 450,
'height': 350
};
var chart = new google.visualization.PieChart(document.getElementById('chart-version'));
chart.draw(versiondata, options);
});
}
});
I have set google chart inside a widget but the sad part is responsive is not working.When i resize it to mobile size the chart data exceeds my widget.Kindly help me with this and if you need more info lemme know,thanks in advance :)

when mouseover or out change icon marker

What i want is when user do mouseover (hover) then the icon change. My code is below:
handler = Gmaps.build("Google", {
markers: {
maxRandomDistance: null
}
});
handler.buildMap({
provider: {},
internal: {
id: "map-canvas"
}
}, function() {
var markers;
markers = handler.addMarkers(ar);
_.each(ar, function(json, index) {
json.marker = markers[index];
$(".location-" + json.id).on("mouseover", function() {
json.picture = {
url: "http://maps.google.com/mapfiles/ms/icons/green-dot.png",
width: 36,
height: 36
};
json.marker.setMap(handler.getMap());
json.marker.panTo();
handler.removeMarker(json.marker);
handler.addMarker(json);
}).on("mouseout", function() {
json.picture = '';
handler.removeMarker(json.marker);
handler.addMarker(json);
});
});
handler.bounds.extendWith(markers);
handler.fitMapToBounds();
});
Using this code, the color of the marker can change from red to green. However, when the user remove their mouse from the hover area, the color does not change back to the original color. Please can anyone suggest me on this issue?
Thanks
Hai thank for #apneadiving answer. I modify my code to this
hoverPicture = {
url: "http://maps.google.com/mapfiles/ms/icons/green-dot.png",
width: 33,
height: 33
};
handler = Gmaps.build("Google", {
markers: {
maxRandomDistance: null
}
});
handler.buildMap({
provider: {},
internal: {
id: "map-canvas"
}
}, function() {
var markers;
markers = handler.addMarkers(ar);
_.each(ar, function(json, index) {
var gr;
json.marker = markers[index];
gr = {};
gr.marker = void 0;
$(".location-" + json.id).on("mouseover", function() {
gr = {
lat: json.lat,
lng: json.lng,
picture: hoverPicture
};
json.marker.panTo();
handler.removeMarker(json.marker);
gr.marker = handler.addMarker(gr);
}).on("mouseout", function() {
handler.removeMarker(gr.marker);
json.marker = handler.addMarker(json);
});
});
handler.bounds.extendWith(markers);
handler.fitMapToBounds();
});
So the new icon need to insert to variable after addMarker
Try something like:
_.each(ar, function(json, index) {
var json.marker = markers[index];
var initialPicture = json.picture;
var hoverPicture = {
url: "http://maps.google.com/mapfiles/ms/icons/green-dot.png",
width: 36,
height: 36
}
$(".location-" + json.id).on("mouseover", function() {
json.picture = hoverPicture;
json.marker.setMap(handler.getMap());
json.marker.panTo();
handler.removeMarker(json.marker);
handler.addMarker(json);
}).on("mouseout", function() {
json.picture = initialPicture;
handler.removeMarker(json.marker);
var newMarker = handler.addMarker(json);
json.marker = newMarker;
});
});

Resources