农作物管理系统(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常见环境管理工具的相关资料,文中通过代码介绍的非常详细,需要的朋友... 目录1. conda2. pip3. uvuv 工具自动创建和管理环境的特点4. setup.py5.

Python常用命令提示符使用方法详解

《Python常用命令提示符使用方法详解》在学习python的过程中,我们需要用到命令提示符(CMD)进行环境的配置,:本文主要介绍Python常用命令提示符使用方法的相关资料,文中通过代码介绍的... 目录一、python环境基础命令【Windows】1、检查Python是否安装2、 查看Python的安

Python UV安装、升级、卸载详细步骤记录

《PythonUV安装、升级、卸载详细步骤记录》:本文主要介绍PythonUV安装、升级、卸载的详细步骤,uv是Astral推出的下一代Python包与项目管理器,主打单一可执行文件、极致性能... 目录安装检查升级设置自动补全卸载UV 命令总结 官方文档详见:https://docs.astral.sh/

Python并行处理实战之如何使用ProcessPoolExecutor加速计算

《Python并行处理实战之如何使用ProcessPoolExecutor加速计算》Python提供了多种并行处理的方式,其中concurrent.futures模块的ProcessPoolExecu... 目录简介完整代码示例代码解释1. 导入必要的模块2. 定义处理函数3. 主函数4. 生成数字列表5.

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

Python虚拟环境与Conda使用指南分享

《Python虚拟环境与Conda使用指南分享》:本文主要介绍Python虚拟环境与Conda使用指南,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、python 虚拟环境概述1.1 什么是虚拟环境1.2 为什么需要虚拟环境二、Python 内置的虚拟环境工具

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

Python pip下载包及所有依赖到指定文件夹的步骤说明

《Pythonpip下载包及所有依赖到指定文件夹的步骤说明》为了方便开发和部署,我们常常需要将Python项目所依赖的第三方包导出到本地文件夹中,:本文主要介绍Pythonpip下载包及所有依... 目录步骤说明命令格式示例参数说明离线安装方法注意事项总结要使用pip下载包及其所有依赖到指定文件夹,请按照以

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1