OpenLayers cluster get incorrect style - vuejs3

I want to paint several clusters red, but when zoom the red flags disappear. I code on vue3 optionAPI.
script.js
import View from 'ol/View'
import Map from 'ol/Map'
import TileLayer from 'ol/layer/Tile'
import OSM from 'ol/source/OSM'
import VectorLayer from 'ol/layer/Vector'
import Point from 'ol/geom/Point';
import LineString from 'ol/geom/LineString';
import VectorSource from 'ol/source/Vector';
import Feature from 'ol/Feature'
import {
Circle as CircleStyle,
Fill,
Stroke,
Style,
Text,
} from 'ol/style';
import Overlay from 'ol/Overlay';
import Cluster from "ol/source/Cluster"
import { useGeographic } from 'ol/proj';
import 'ol/ol.css'
import './style.css'
import axios from 'axios'
export default {
name: 'MapContainer',
components: {},`your text`
props: {},
data() {
return {
place: [43.984506, 56.305298],
data: [],
featuresPoints: [],
featuresLines: [],
}
},
methods: {
async getData() {
axios("https://someRestApiLink.com").then(res => {
this.data = res.data;
this.createFeachers();
this.renderMap();
});
},
setCircleStyle(feature) {
const size = feature.get('features').length;
let style = styleCache[size];
if (!style) {
style = new Style({
image: new CircleStyle({
radius: 10,
stroke: new Stroke({
color: '#fff',
}),
fill: new Fill({
color: '#3399CC',
}),
}),
text: new Text({
text: size.toString(),
fill: new Fill({
color: '#fff',
}),
}),
});
styleCache[size] = style;
}
return style;
},
createFeachers() {
for (let item of this.data) {
let coords = JSON.parse(item.coords);
if (coords.length === 1) {
let feature = new Feature(new Point(coords[0].reverse()));
feature.mydata = item;
this.featuresPoints.push(feature);
} else {
let rightCoords = coords.map(el => el.reverse());
let isValidFeacture = true;
for (let i = 0; i < rightCoords.length - 1; i++) {
if (Math.abs(rightCoords[i][0] - rightCoords[i + 1][0]) > .01) {
isValidFeacture = false;
break
}
}
if (!isValidFeacture) continue;
let feature = new Feature({
geometry: new LineString(rightCoords)
});
feature.setStyle(new Style({
stroke: new Stroke({
color: '#0000ff',
width: 3
})
}))
feature.mydata = item
this.featuresLines.push(feature);
}
}
},
createMap() {
return new Map({
target: this.$refs['map-root'],
view: new View({
zoom: 12,
center: this.place
}),
layers: [
new TileLayer({
source: new OSM()
}),
this.createLineLayer(),
this.createPointLayer(),
],
});
},
createPointLayer() {
const styleCache = {};
let cluster = new Cluster({
distance: 15,
minDistance: 6,
source: new VectorSource({
features: this.featuresPoints,
})
});
const mainCluster = new VectorLayer({
source: cluster,
style: function (feature) {
function calculateFired(cluster, length) {
let pointList = cluster.values_.features;
let countFired = 0;
for (let point of pointList) {
if (point.mydata.status === "Просрочен") {
countFired++;
}
}
return countFired === length ? "full" : countFired > 0 ? "several" : "none";
}
const size = feature.get('features').length;
let style = styleCache[size];
if (!style) {
let hasFired = calculateFired(feature, size);
style = new Style({
image: new CircleStyle({
radius: 10,
stroke: new Stroke({
color: hasFired === "none" ? '#fff' : "#f00",
// color: '#fff',
}),
fill: new Fill({
color: hasFired === "full" ? "#f00" : '#3399CC',
// color: '#3399CC',
}),
}),
text: new Text({
text: size.toString(),
fill: new Fill({
color: '#fff',
}),
}),
});
styleCache[size] = style;
// console.log(style);
}
return style;
},
});
mainCluster.mydata = this.featuresPoints.map(el => el.mydata);
return mainCluster
},
createLineLayer() {
return new VectorLayer({
source: new VectorSource({
features: this.featuresLines,
}),
})
},
renderMap() {
useGeographic();
const createPopUp = this.createPopUp;
var container = document.getElementById("popup");
var content = document.getElementById("popup-content");
const map = this.createMap();
const overlay = new Overlay({
element: container,
autoPan: true
});
map.on('click', function (e) {
let pixel = map.getEventPixel(e.originalEvent);
if (document.getElementsByClassName('popup-content').length != 0) {
document.getElementsByClassName('popup-content')[0].style.display = 'none'
}
map.forEachFeatureAtPixel(pixel, function (feature) {
let data = feature.mydata ?? feature.values_.features.map(el => el.mydata);
let coodinate = e.coordinate;
content.innerHTML = createPopUp(data);
overlay.setPosition(coodinate);
map.addOverlay(overlay);
});
});
},
createPopUp(data) {
let content = "";
if (data.length) {
let sortedData = data.sort((a, b)=> {
if (a.time.split(".").reverse().join("-") > b.time.split(".").reverse().join("-")) return 1;
if (a.time.split(".").reverse().join("-") < b.time.split(".").reverse().join("-")) return -1;
return 0;
});
for (let el of sortedData) {
content += `
<div class="popup-content__valueBlock">
<div class="popup-content__valueBlock__organization">
${el.organization}:
</div>
<div class="popup-content__valueBlock__aimOfWorks">
Тип: ${el.aim_of_works}
</div>
<div class="popup-content__valueBlock__stripSurface">
Работы ведутся над: ${el.strip_surface}
</div>
<div class="popup-content__valueBlock__status">
${el.status} - ${el.finish_date}
</div>
</div>
`;
}
} else {
content = `
<div class="popup-content__valueBlock">
<div class="popup-content__valueBlock__organization">
${data.organization}:
</div>
<div class="popup-content__valueBlock__aimOfWorks">
Тип: ${data.aim_of_works}
</div>
<div class="popup-content__valueBlock__stripSurface">
Работы ведутся над: ${data.strip_surface}
</div>
<div class="popup-content__valueBlock__status">
${data.status} - ${data.time}
</div>
</div>
`;
}
return `
<div class="popup-content">
<span class="close" onclick="closePopup()">x</span>
<span class="count">Количество выбранных ордеров: ${data.length ?? 1}</span>
${content}
</div>
`;
},
},
mounted() {
this.getData();
},
}
I checked ol_uid of cluster when I rezoomed, and I was so surprised by changed this property at the same cluster. Also I tried to rerender map at every time when I changed zoom, but this not work too.
I think that I mb do something wrong on creating or rendering map or clusters.

Related

MapboxglSpiderifier in NextJs (react-map-gl)

I am using Map from react-map-gl to display several markers in a map. I also use Layers and Source to have my markers in clusters. But I have a problem because I can have multiple points with the exact same coordinate and those points end up overlaying each other when zooming in (it seems that there is only one marker in the position when there are multiple).
I have installed mapboxgl-spiderifier to overcome this problem but I can't seem to get it working.
Here's some of my code:
const [spiderifier, setSpiderifier] = useState(null);
const ref = useRef();
...
const onMapLoad = React.useCallback(() => {
setSpiderifier(
new MapboxglSpiderifier(ref.current.getMap(), {
onClick: function (e, spiderLeg) {
e.stopPropagation();
console.log("Clicked on ", spiderLeg);
},
markerWidth: 100,
markerHeight: 100,
})
);
}, []);
const onClick = (event) => {
const feature = event.features[0];
if (feature.layer.id === "clusters") {
const clusterId = feature.properties.cluster_id;
const mapboxSource = ref.current.getSource("classesandtrainers");
if (location.zoom >= 12) {
mapboxSource.getClusterLeaves(
clusterId,
100,
0,
function (err, leafFeatures) {
if (err) {
return console.error("error while getting leaves of a cluster", err);
}
let markers = leafFeatures.map((leafFeature) => {
return leafFeature.properties;
});
spiderifier.spiderfy(event.lngLat, { ...geoJson, features: markers });
}
);
return;
}
mapboxSource.getClusterExpansionZoom(clusterId, (err, zoom) => {
if (err) {
return;
}
ref.current.easeTo({
center: feature.geometry.coordinates,
zoom,
duration: 500,
});
});
}
};
...
return (
<Map
ref={ref}
{...location}
onLoad={onMapLoad}
onMove={(evt) => setLocation(evt.viewState)}
onClick={onClick}
mapStyle="mapbox://styles/flxbl/cl92sjxf4001g15la7upwjij2"
mapboxAccessToken={process.env.mapbox_key}
style={{ width: "100%", height: "100%", margin: 0, padding: 0 }}
interactiveLayerIds={[clusterLayer.id, unclusteredPointLayer.id]}
>
<Source
id="classesandtrainers"
type="geojson"
data={sourceData()}
cluster={true}
clusterMaxZoom={14}
clusterRadius={50}
>
<Layer {...clusterLayer} />
<Layer {...clusterCountLayer} />
<Layer {...unclusteredPointLayer} />
</Source>
<ScaleControl position="bottom-right" />
{renderPopup()}
</Map>
Can someone please help me?

How To Crop uploaded image with react-konva

I am using react-konva and I want to crop my selected image when edit button clicked.
Can anyone please guide me how I can achieve this ?
this is the Rect I am using to crop the portion of the image.
Here in this code onShapeChange function saves the crop value of the image in
canvas editor.
{(isCropping &&
<>
{React.createElement(`Rect`, {
ref: cropRef,
key: selectedShape.id,
id: selectedShape.id,
...selectedShape.attributes,
draggable: false,
onTransformEnd: (e) => {
const node = cropRef.current;
const scaleX = node.scaleX();
const scaleY = node.scaleY();
node.scaleX(1);
node.scaleY(1);
const newShape = {
...selectedShape,
attributes:
{
...selectedShape.attributes,
crop: {
x: node.x() - selectedShape.attributes.x,
y: node.y() - selectedShape.attributes.y,
// width: this.state.rect.attrs.width,
// height: this.state.rect.attrs.height
// x: node.x(),
// y: node.y(),
width: Math.max(5, node.width() * scaleX),
height: Math.max(node.height() * scaleY),
}
}
}
console.log('newShape in cropper', newShape, 'SelectedShape', selectedShape);
onShapeChange({
id: selectedShape.id,
index: selectedReportItem.index,
reportIndex: selectedReportItem.reportIndex,
newItem: newShape,
})
setIsCropping(false);
}
}, null)}
<Transformer
ref={croptrRef}
rotateEnabled={false}
flipEnabled={false}
boundBoxFunc={(oldBox, newBox) => {
// limit resize
if (newBox.width < 5 || newBox.height < 5) {
return oldBox;
}
return newBox;
}}
/>
</>
}

Init Custom Button SwiftUI

Trying to init CustomButton(title: "Add", icon: .add, status: .enable)
My code is below. I do get the title but enums are not working.
Plus recieving error
Cannot convert value of type 'Image' to expected argument type 'String'
at Image(icon)
import SwiftUI
struct CustomButton: View {
var title: String
var icon: String
var status: Color
var body: some View {
Button(action: {
}) {
Text(title)
.foregroundColor(.white)
.background(Color(.green))
.font(Font.custom("SFCompactDisplay", size: 14))
Image(icon)
.renderingMode(.original)
.foregroundColor(.white)
}
}
enum Icon {
case add
case edit
var image: Image {
switch self {
case .add:
return Image("Add")
case .edit:
return Image("Edit")
}
}
}
enum Status {
case enable
case disable
var color : Color {
switch self {
case .enable:
return Color(.green)
case .disable:
return Color(.gray)
}
}
}
init(title: String, icon: Icon, status: Status) {
self.title = title
self.icon = icon.image
self.status = status.color
}
}
I assume you wanted this
struct CustomButton: View {
var title: String
var icon: Icon
var status: Color
var body: some View {
Button(action: {
}) {
Text(title)
.foregroundColor(.white)
.background(Color(.green))
.font(Font.custom("SFCompactDisplay", size: 14))
icon.image
.renderingMode(.original)
.foregroundColor(.white)
}
}
enum Icon {
case add
case edit
var image: Image {
switch self {
case .add:
return Image("Add")
case .edit:
return Image("Edit")
}
}
}
enum Status {
case enable
case disable
var color : Color {
switch self {
case .enable:
return Color(.green)
case .disable:
return Color(.gray)
}
}
}
init(title: String, icon: Icon, status: Status) {
self.title = title
self.icon = icon
self.status = status.color
}
}
I figured it out. It works now.
struct CustomButton: View {
let title: String
let icon : String
let status: Color
#State private var buttonDisabled = true
var body: some View {
Button(action: {
}) {
ZStack(alignment:.bottom) {
HStack {
Text(title)
.foregroundColor(.white)
.font(Font.custom("SFCompactDisplay-Bold", size: 20))
.bold()
.fontWeight(.bold)
.background(status)
Image(icon)
.renderingMode(.original)
.foregroundColor(.white)
.background(Color(.white))
}
.frame(width: 335, height: 20, alignment: .center)
.padding()
.background(status)
}
.cornerRadius(10)
}
}
enum Icon {
case add
case edit
case none
var image: String {
switch self {
case .add:
return "Add"
case .edit:
return "Edit"
case .none:
return "empty"
}
}
}
enum Status {
case enable
case disable
}
init(title: String, icon: Icon, status: Status) {
self.title = title
self.icon = icon.image
if status == .enable {
self.status = Color(#colorLiteral(red: 0, green: 0.6588235294, blue: 0.5254901961, alpha: 1))
} else {
self.status = Color(#colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1))
}
}
}
struct CustomButton_Previews: PreviewProvider {
static var previews: some View {
CustomButton(title: "Odeme Yontemi Ekle", icon: .none, status: .enable)
}
}

Change font size and font color in Chartjs Angular 5

Font color in chartjs is light gray, then when you want to print from page, it does not appear.
I change the font color of chartjs in options attribute, but it does not work.
How can I change the font color in chartjs angular
public options:any = {
legend: {
labels: {
// This more specific font property overrides the global property
fontColor: 'red',
fontSize: '30'
}
}
};
in template :
<canvas baseChart
height=100
[datasets]="barChartData"
[labels]="barChartLabels"
[options]="barChartOptions"
[legend]="barChartLegend"
[colors]="chartColors"
[chartType]="barChartType"
[options]="options"
>
</canvas>
I use chartjs like following in ts file.
This is my complete ts file:
import { Component, Input, OnInit } from '#angular/core';
import { Test } from './models/test.model';
#Component({
selector: 'app-customer-report-test',
templateUrl: './customer-report-test.component.html',
styleUrls: ['./customer-report-test.component.css']
})
export class CustomerReportTestComponent implements OnInit {
#Input('test') test: Test = new Test();
public barChartOptions:any = {
scaleShowVerticalLines: false,
responsive: true
};
public barChartLabels:string[];
public barChartType:string = 'bar';
public barChartLegend:boolean = true;
public barChartData:any[];
backgroundColorList: string[];
public chartColors: any[] = [
{
backgroundColor: this.backgroundColorList
}];
public options:any;
constructor() { }
//----------------------------------------------------------------------------
ngOnInit() {
//set Label
this.barChartLabels = [];
for(let i=1; i<= this.test.data_array.length; i++){
this.barChartLabels.push('' + i);
}
//set data chart
this.barChartData = [{data: this.test.data_array, label: this.test.test_type[1]}]
this.test.test_type[1]}, {data: [20,20, 20, 20],type: "line",label: ['0', '1', '2', '3'] ,fill:'none'}]
// set color to line according to state_array
this.backgroundColorList = [];
if(this.test.state_array.length != 0){
for(let i=0; i<this.test.data_array.length; i++){
if(this.test.state_array[i] == 0){
this.backgroundColorList.push('#069ed6');
}else if(this.test.state_array[i] == 1){
this.backgroundColorList.push('#F5482D');
}else if(this.test.state_array[i] == 2){
this.backgroundColorList.push('#CAC409');
}
}
}
else{
for(let d of this.test.data_array){
this.backgroundColorList.push('#069ed6');
}
}
this.chartColors = [
{
backgroundColor: this.backgroundColorList
}];
this.options = {
responsive: true,
title: {
display: true,
text: 'Custom Chart Title'
},
legend: {
display: true,
labels: {
fontColor: 'red'
}
}
};
}
}
for changing the color of numbers and lines in coordinate plane,we can do:
for example in xAxes:
xAxes: [{
gridLines: {
display: true,
color: "red" // this here
},
ticks: {
fontColor: "red", // this here
}
}],
and font and color of labels:
legend: {
display: true,
labels:{
fontSize: 10,
fontColor: 'red',
}
},
DEMO.
You may try to edit the source code.
1. Go to the link /node_modules/chart.js/src/core/core.js in your node modules folder.
2. edit the following code i.e the core.js file. change the
defaultFontColor: '#0000ff'
to any color you want. I have implemented this in my code for pie chart. and it worked.
`
defaults._set('global', {
responsive: true,
responsiveAnimationDuration: 0,
maintainAspectRatio: true,
events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
hover: {
onHover: null,
mode: 'nearest',
intersect: true,
animationDuration: 400
},
onClick: null,
defaultColor: 'rgba(0,0,0,0.1)',
defaultFontColor: '#0000ff',
defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
defaultFontSize: 12,
defaultFontStyle: 'normal',
showLines: true,
// Element defaults defined in element extensions
elements: {},
// Layout options such as padding
layout: {
padding: {
top: 0,
right: 0,
bottom: 0,
left: 0
}
}
});
module.exports = function() {
// Occupy the global variable of Chart, and create a simple base class
var Chart = function(item, config) {
this.construct(item, config);
return this;
};
Chart.Chart = Chart;
return Chart;
};`

Akryum: Vuex#1 for Meteor example app, addTrackers?

I don't really understand any of this from https://github.com/Akryum/meteor-vuex-example/tree/master/imports/vuex/modules: from init(data) all the way to if data in getters at the bottom references to vue instance data or state of vuex.
subModule.addTrackers({
selectedThread() {
let sub;
return {
init(data) {
data.selectedThread = null;
data.posts = [];
},
watch(state) {
// Dynamic subscription
if(sub) {
sub.stop();
}
if(state.selectedThreadId) {
sub = Meteor.subscribe('posts', state.selectedThreadId);
console.log('subscribed posts to thread ', state.selectedThreadId);
}
return {
id: state.selectedThreadId
}
},
update(data, {id}) {
data.selectedThread = Object.freeze(Threads.findOne({
_id: id
}));
data.posts = Object.freeze(Posts.find({
thread_id: id
}, {
sort: {created: -1}
}).fetch());
console.log('posts', data.posts);
},
getters: {
getSelectedThread: data => data.selectedThread,
getPosts: data => data.posts
}
}
}
})

Resources