农作物管理系统(openlayers、python、django)

2024-01-28 15:58

本文主要是介绍农作物管理系统(openlayers、python、django),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

农作物管理系统(openlayers、python、django)

    • 客户需求
    • 原始数据
    • 软件安装
    • 服务发布
    • 源码
    • 功能界面

客户需求

项目名称是:农作物长势遥感监测信息发布平台

  1. 农作物长势分析:做成下拉菜单,下拉菜单里面是月份。点击地块之后可以出现每个月份的长势图(是曲线图)
  2. 农作物分类:农作物共分了6类,也可以做成下拉菜单,点击菜单出现棉花,玉米等类,在点击下拉菜单的时候可以在图中显示对应的种类。
  3. 农作物面积:也是下拉菜单,也主要是棉花,玉米,小麦等5类作物面积。在点击下拉菜单时出现地块和面积统计数据。(要是地块数据不好显示可以只做显示面积数据)
  4. 用户在点击每个地块数据时可以给用户显示地块的种植类和面积已经属于那个乡镇
  5. 定位用户的地理位置,可以显示该位置的地块信息(如果是耕地就显示,不是耕地就不用显示了)
  6. 地图常用的放大缩小功能,和搜索查询功能

以上是原始需求,实现上做了一些改动

原始数据

原始数据,点我

软件安装

  1. 用于发布地图服务java环境:Tomcat + geoserver + jdk
  2. 用于后端python
  3. 用于前端nodejs
  4. 开发工具visual studio code、pycharm等

服务发布

简单发布shp 和 tif影像数据wms服务即可
在这里插入图片描述

源码

前端主要是react+dva+umi+antdesign框架

前端 核心源码 pages/openlayers_nongye/index.js

/* global mars3d Cesium*/
import React, { Component } from 'react';
import { connect } from 'dva';
import { Divider, Checkbox, Button, Row, Col, Tooltip, Modal, Select, Tree,Icon } from 'antd'
import styles from './style.less'
import echarts from 'echarts'
import Pie from './pie'
import Source from './source'const { TreeNode } = Tree;/* openlayers */
import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import Feature from 'ol/Feature';
import { OSM, XYZ } from 'ol/source';
import { LineString, Point, Polygon } from 'ol/geom';
import { defaults as defaultInteractions, Pointer as PointerInteraction } from 'ol/interaction';
import { Image as ImageLayer,Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import { ImageWMS ,TileJSON, Vector as VectorSource } from 'ol/source';
import { Fill, Stroke, Style } from 'ol/style';
import { toLonLat, fromLonLat, get } from 'ol/proj';
import { FullScreen } from 'ol/control';
import filter,{or,like,and, equalTo} from 'ol/format/filter';
import GeoJSON from 'ol/format/GeoJSON';
import { none } from 'ol/centerconstraint';const chinaJson = require('./file/wuhan.geojson')
const { Option, OptGroup } = Select;@connect(({ nongye }) => ({nongye
}))class Nongye extends Component {constructor(props) {super(props)this.state = {map: null,chart: null,//底图digitalLayer: new TileLayer({//source: new OSM()source: new XYZ({url: 'https://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'})}),imagesLayer: new TileLayer({//source: new OSM()source: new XYZ({url: 'https://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=6&x={x}&y={y}&z={z}'})}),arcgisLayer: new TileLayer({source: new XYZ({//url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'url: 'http://cache1.arcgisonline.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}'})}),//业务图层wushuImage:new ImageLayer({source: new ImageWMS({url: '/nongye/geoserver/nongye/wms',params: {'LAYERS': 'nongye:geotiff_coverage'},ratio: 1,serverType: 'geoserver',crossOrigin: 'anonymous',}),}),wushuBoundary:new ImageLayer({source: new ImageWMS({url: '/nongye/geoserver/nongye/wms',params: {'LAYERS': 'nongye:wusubound'},ratio: 1,serverType: 'geoserver',crossOrigin: 'anonymous',}),}),wushuCrops:new ImageLayer({source: new ImageWMS({url: '/nongye/geoserver/nongye/wms',params: {'LAYERS': 'nongye:wusugd',// 'CQL_FILTER': `kind='mianhua'`},ratio: 1,serverType: 'geoserver',crossOrigin: 'anonymous',}),}),wuhanGeojson: new VectorLayer({source: new VectorSource({url: chinaJson,format: new GeoJSON()}),style: new Style({stroke: new Stroke({color: '#319FD3',width: 20})})}),showChart: false,crop_prop:null,//点击地块详细信息}}componentDidMount() {this.start()this.setState({chart: this.refs.chart})}start = () => {this.initMap({}).then(() => {const {map,wushuCrops} = this.state//监听动作let that = thismap.on('singleclick', function (evt) {// document.getElementById('info').innerHTML = '';var viewResolution = /** @type {number} */ (map.getView().getResolution());var url = wushuCrops.getSource().getFeatureInfoUrl(evt.coordinate,viewResolution,'EPSG:3857',{'INFO_FORMAT': 'application/json'});if (url) {fetch(url).then(function (response) { return response.text(); }).then(function (result) {console.log(result)let json =JSON.parse(result)that.setState({showChart:false,crop_prop:json.features.length>0 ?json.features[0].properties:null})});}});map.on('pointermove', function (evt) {if (evt.dragging) {return;}var pixel = map.getEventPixel(evt.originalEvent);var hit = map.forEachLayerAtPixel(pixel, function () {return true;});map.getTargetElement().style.cursor = hit ? 'pointer' : '';});})}initMap = () => {const { wuhanGeojson, arcgisLayer, imagesLayer, digitalLayer,wushuBoundary,wushuImage,wushuCrops } = this.statearcgisLayer.set('id', 'arcgisLayer')arcgisLayer.setVisible(false)imagesLayer.set('id', 'imagesLayer')imagesLayer.setVisible(false)digitalLayer.set('id', 'digitalLayer')digitalLayer.setVisible(true)wushuImage.set("id",'wushuImage')wushuImage.setVisible(false)wushuBoundary.set("id",'wushuBoundary')wushuBoundary.setVisible(false)wushuCrops.set("id",'wushuCrops')wushuCrops.setVisible(true)return new Promise(resolve => {var fullScreenControl = new FullScreen()var map = new Map({interactions: defaultInteractions().extend([new Drag()]),view: new View({center: fromLonLat([84.41,44.60]),zoom: 9}),layers: [arcgisLayer,imagesLayer,digitalLayer,wuhanGeojson,wushuImage,wushuBoundary,wushuCrops,],target: 'map'});map.addControl(fullScreenControl)this.setState({map},()=>{resolve()})})};//定位location =()=>{const {map} = this.statelet bmap = new BMap.Map("allmap");var geolocation = new BMap.Geolocation();geolocation.getCurrentPosition(function(r){if(this.getStatus() == BMAP_STATUS_SUCCESS){// alert('您的位置:'+r.point.lng+','+r.point.lat);map.setView(new View({center: fromLonLat([r.point.lng,r.point.lat]),zoom: 10}))}else {alert('failed'+this.getStatus());}});}//影像和电子地图切换anhei = () => {const { map, arcgisLayer } = this.statevar layers = map.getLayers()for (let i = 0; i < layers.getLength(); i++) {var id = layers.item(i).get('id')if (id === 'imagesLayer' || id === 'digitalLayer') {layers.item(i).setVisible(false)}}arcgisLayer.setVisible(true)}weixing = () => {const { map, imagesLayer } = this.statevar layers = map.getLayers()for (let i = 0; i < layers.getLength(); i++) {var id = layers.item(i).get('id')if (id === 'arcgisLayer' || id === 'digitalLayer') {layers.item(i).setVisible(false)}}imagesLayer.setVisible(true)}luwang = () => {const { map, digitalLayer } = this.statevar layers = map.getLayers()for (let i = 0; i < layers.getLength(); i++) {var id = layers.item(i).get('id')if (id === 'arcgisLayer' || id === 'imagesLayer') {layers.item(i).setVisible(false)}}digitalLayer.setVisible(true)}onCheck = (checkedKeys, info) => {const {wushuCrops,wushuImage,wushuBoundary} = this.state//显示隐藏图层数据if(checkedKeys.includes("wushu")){//两者皆有wushuImage.setVisible(true)wushuBoundary.setVisible(true)}else if (checkedKeys.includes("image")) { //只有影像wushuImage.setVisible(true)wushuBoundary.setVisible(false)}else if(checkedKeys.includes("boundary")){ //只有边界wushuImage.setVisible(false)wushuBoundary.setVisible(true)}else{wushuImage.setVisible(false)wushuBoundary.setVisible(false)}//过滤crops业务图层要素数据let p = ''checkedKeys.forEach(element => {p += "'"+element+"' ,"});wushuCrops.getSource().updateParams({'CQL_FILTER': `kind in ${'('+p.substr(0,p.length-1)+')'}`})wushuCrops.getSource().refresh()};getArrDifference =(arr1, arr2)=> {return arr1.concat(arr2).filter(function(v, i, arr) {return arr.indexOf(v) === arr.lastIndexOf(v);});} tongji =()=>{const {crop_prop } = this.statethis.setState({showChart:true},()=>{getFromCache("tongjiArea").then(data=>{if(!data){this.props.dispatch({type: 'nongye/getTongjiArea',payload: {},}).then(result => {setToCache("tongjiArea",result)this.initBar(result.data)})}else{this.initBar(data.data)}})})}initBar = (data)=>{var myChart = echarts.init(document.getElementById('chart'));var option = {title: {text: '农作物面积统计(平方米)'},tooltip: {},xAxis: {type: 'category',data: ['棉花', '番茄', '蔬菜','小麦','玉米','其他']},yAxis: {type: 'value'},grid: {bottom: '10%',left: '3%',containLabel: true},series: [{data: [data['mianhua'],data['fanqie'],data['shucai'],data['xiaomai'],data['yumi'],data['qita']],type: 'bar'}]};myChart.setOption(option);}zhangshi = () =>{const {crop_prop } = this.statethis.setState({showChart:true},()=>{var myChart = echarts.init(document.getElementById('chart'));var option = {title: {text: '长势'},tooltip: {},xAxis: {type: 'category',data: ['3月', '5月', '6月','7月','8月','9月','10月']},yAxis: {type: 'value'},grid: {bottom: '10%',containLabel: true},series: [{data: [crop_prop.b1_all_tif, crop_prop.b2_all_tif,crop_prop.b3_all_tif,crop_prop.b4_all_tif,crop_prop.b5_all_tif,crop_prop.b6_all_tif,crop_prop.b7_all_tif],type: 'line'}]};myChart.setOption(option);})}NDVI = () =>{const {crop_prop } = this.statethis.setState({showChart:true},()=>{var myChart = echarts.init(document.getElementById('chart'));var option = {title: {text: 'NDVI'},tooltip: {},grid: {bottom: '10%',containLabel: true},xAxis: {type: 'category',data: ['3月12', '4月11', '5月26','6月20','7月10','8月24','9月3','10月18']},yAxis: {type: 'value'},series: [{data: [crop_prop.b1_ndvi202 ,crop_prop.b2_ndvi202	,crop_prop.b3_ndvi202	,crop_prop.b4_ndvi202	,crop_prop.b5_ndvi202	,crop_prop.b6_ndvi202	,crop_prop.b7_ndvi202	,crop_prop.b8_ndvi202],type: 'line'}]};myChart.setOption(option);})}render() {const { map, chart,crop_prop,showChart } = this.statereturn (<div style={{ width: '100%', paddingTop: '80px' }}><div className={styles.layer}><TreecheckabledefaultExpandedKeys={['wushu','crops']}defaultSelectedKeys={['crops']}defaultCheckedKeys={['crops']}// onSelect={this.onSelect}onCheck={this.onCheck}><TreeNode title="乌苏区位图" key="wushu"><TreeNode title="影像" key="image"></TreeNode><TreeNode title="边界" key="boundary"></TreeNode></TreeNode><TreeNode title="全部农作物" key="crops"><TreeNode title="番茄" key="fanqie"></TreeNode><TreeNode title="棉花" key="mianhua"></TreeNode><TreeNode title="蔬菜" key="shucai"></TreeNode><TreeNode title="小麦" key="xiaomai"></TreeNode><TreeNode title="玉米" key="yumi"></TreeNode><TreeNode title="其他" key="qita"></TreeNode></TreeNode></Tree><Divider orientation="right"><a onClick={this.tongji}>统计面积</a></Divider><div className={styles.desc}>{ crop_prop && (<>{/* <div className={styles.title}>农作物详情</div> */}<Divider orientation="left">农作物详情</Divider><div className={styles.item}><label>乡镇:</label><span>{crop_prop.xiangzhen}</span></div><div className={styles.item}><label>土地:</label><span>{crop_prop.classname}</span></div><div className={styles.item}><label>类型:</label><span>{crop_prop.kind}</span></div><div className={styles.item}><label>面积:</label><span>{crop_prop.Shape_Area}</span></div><div className={styles.item}><label>编码:</label><span>{crop_prop.code}</span></div><Divider orientation="right"><a onClick={this.zhangshi}>查看长势</a></Divider><Divider orientation="right"><a onClick={this.NDVI}>查看NDVI</a></Divider></>)}</div>{showChart && (<div className={styles.chart}><div id="chart" ref="chart" style={{ width: '100%',height:'100%' }}></div></div>)}</div><div className={styles.map} id="map"><div className={styles.toolbar}><div className={styles.bar} onClick={this.location}><div id="allmap" style={{display:none}}></div><p><Icon type="environment" /></p></div><div className={styles.bar} onClick={this.anhei}><p>暗黑</p></div><div className={styles.bar} onClick={this.luwang}><p>路网</p></div><div className={styles.bar} onClick={this.weixing}><p>卫星</p></div></div></div></div>)}
}var Drag = /*@__PURE__*/(function (PointerInteraction) {function Drag() {PointerInteraction.call(this, {handleDownEvent: handleDownEvent,handleDragEvent: handleDragEvent,handleMoveEvent: handleMoveEvent,handleUpEvent: handleUpEvent});/*** @type {import("../src/ol/coordinate.js").Coordinate}* @private*/this.coordinate_ = null;/*** @type {string|undefined}* @private*/this.cursor_ = 'pointer';/*** @type {Feature}* @private*/this.feature_ = null;/*** @type {string|undefined}* @private*/this.previousCursor_ = undefined;}if (PointerInteraction) Drag.__proto__ = PointerInteraction;Drag.prototype = Object.create(PointerInteraction && PointerInteraction.prototype);Drag.prototype.constructor = Drag;return Drag;
}(PointerInteraction));/*** @param {import("../src/ol/MapBrowserEvent.js").default} evt Map browser event.* @return {boolean} `true` to start the drag sequence.*/
function handleDownEvent(evt) {var map = evt.map;var feature = map.forEachFeatureAtPixel(evt.pixel,function (feature) {return feature;});if (feature) {this.coordinate_ = evt.coordinate;this.feature_ = feature;}return !!feature;
}/*** @param {import("../src/ol/MapBrowserEvent.js").default} evt Map browser event.*/
function handleDragEvent(evt) {var deltaX = evt.coordinate[0] - this.coordinate_[0];var deltaY = evt.coordinate[1] - this.coordinate_[1];var geometry = this.feature_.getGeometry();geometry.translate(deltaX, deltaY);this.coordinate_[0] = evt.coordinate[0];this.coordinate_[1] = evt.coordinate[1];
}/*** @param {import("../src/ol/MapBrowserEvent.js").default} evt Event.*/
function handleMoveEvent(evt) {if (this.cursor_) {var map = evt.map;var feature = map.forEachFeatureAtPixel(evt.pixel,function (feature) {return feature;});var element = evt.map.getTargetElement();if (feature) {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;}}
}/*** @return {boolean} `false` to stop the drag sequence.*/
function handleUpEvent() {this.coordinate_ = null;this.feature_ = null;return false;
}export default Nongye

后端主要采用django框架写的接口
后端 核心代码在这里插入图片描述

功能界面

在这里插入图片描述

说明:
左侧目录树对图层进行隐藏,影像/边界是单独图层,农作物整是一个图层,分了不同类别,这里有区别;
统计面积是统计上面农作物分类的面积,这里统计一次后写入indexdb,方便下次快速读取
点击地块左侧显示地块的详细信息,包括可查看长势图和nvdi图

如有兴趣, 能帮到您,联系我 qq:851356263 ,请说明来意,谢谢!

这篇关于农作物管理系统(openlayers、python、django)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/654097

相关文章

Python版本信息获取方法详解与实战

《Python版本信息获取方法详解与实战》在Python开发中,获取Python版本号是调试、兼容性检查和版本控制的重要基础操作,本文详细介绍了如何使用sys和platform模块获取Python的主... 目录1. python版本号获取基础2. 使用sys模块获取版本信息2.1 sys模块概述2.1.1

一文详解Python如何开发游戏

《一文详解Python如何开发游戏》Python是一种非常流行的编程语言,也可以用来开发游戏模组,:本文主要介绍Python如何开发游戏的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、python简介二、Python 开发 2D 游戏的优劣势优势缺点三、Python 开发 3D

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

Python版本与package版本兼容性检查方法总结

《Python版本与package版本兼容性检查方法总结》:本文主要介绍Python版本与package版本兼容性检查方法的相关资料,文中提供四种检查方法,分别是pip查询、conda管理、PyP... 目录引言为什么会出现兼容性问题方法一:用 pip 官方命令查询可用版本方法二:conda 管理包环境方法

基于Python开发Windows自动更新控制工具

《基于Python开发Windows自动更新控制工具》在当今数字化时代,操作系统更新已成为计算机维护的重要组成部分,本文介绍一款基于Python和PyQt5的Windows自动更新控制工具,有需要的可... 目录设计原理与技术实现系统架构概述数学建模工具界面完整代码实现技术深度分析多层级控制理论服务层控制注

pycharm跑python项目易出错的问题总结

《pycharm跑python项目易出错的问题总结》:本文主要介绍pycharm跑python项目易出错问题的相关资料,当你在PyCharm中运行Python程序时遇到报错,可以按照以下步骤进行排... 1. 一定不要在pycharm终端里面创建环境安装别人的项目子模块等,有可能出现的问题就是你不报错都安装

Spring Boot分层架构详解之从Controller到Service再到Mapper的完整流程(用户管理系统为例)

《SpringBoot分层架构详解之从Controller到Service再到Mapper的完整流程(用户管理系统为例)》本文将以一个实际案例(用户管理系统)为例,详细解析SpringBoot中Co... 目录引言:为什么学习Spring Boot分层架构?第一部分:Spring Boot的整体架构1.1

Python打包成exe常用的四种方法小结

《Python打包成exe常用的四种方法小结》本文主要介绍了Python打包成exe常用的四种方法,包括PyInstaller、cx_Freeze、Py2exe、Nuitka,文中通过示例代码介绍的非... 目录一.PyInstaller11.安装:2. PyInstaller常用参数下面是pyinstal

Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题

《Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题》在爬虫工程里,“HTTPS”是绕不开的话题,HTTPS为传输加密提供保护,同时也给爬虫带来证书校验、... 目录一、核心问题与优先级检查(先问三件事)二、基础示例:requests 与证书处理三、高并发选型: