主頁 > 企業開發 > 500行JavaScript代碼在前端根據資料生成CAD工程剖面圖

500行JavaScript代碼在前端根據資料生成CAD工程剖面圖

2023-03-06 07:58:06 企業開發

前言

用資料生成CAD圖,一般采用的ObjectArx對CAD二次開發完成,ObjectARX是AutoDesk公司針對AutoCAD平臺上的二次開發而推出的一個開發軟體包,它提供了以C++為基礎的面向物件的開發環境及應用程式介面,能訪問和創建AutoCAD圖形資料庫,而由于現在懂C++的人少,很多人對C++有點望而生畏,則JavaScript 是互聯網上最流行的腳本語言,用戶群體很大,那有沒有可能利用JavaScript來進行資料成圖?

今天和大家聊聊,怎么用500行JavaScript代碼,根據資料在前端創建一個Dwg格式的工程剖面圖,

效果

先上效果圖 image-20230303195106114

datatodwg.gif

它支持哪些功能?

  • 支持CAD的27種物體型別的創建,如線、文字、填充等

  • 支持對DWG圖中物體進行修改、克隆、洗掉等操作

  • 支持創建CAD圖層、線型、塊定義、文字樣式

  • 支持從外部圖形中拷貝物體到當前創建的CAD圖中

  • 支持塊屬性文字的創建和設定

  • 對創建好的CAD圖形資料能以GeoJson的格式在前端直接展示,同時能選中移動等操作

  • 對創建好的CAD圖形能在前端展示,同時能點擊彈出物體型別等屬性

  • 能匯出成DWG圖形

實作原理

image-20230303202058333

(1) 對剖面圖中不變的元素如圖例做成模板,創建圖時直接拷貝這些物體即可,對于圖簽可以外部圖形插入,同時圖簽中需要修改的文字內容如制圖人或日期等欄位,可以塊屬性文字的方式在創建時以屬性賦值的方式來進行創建,如上面生成的剖面圖的模板來源于下面這兩個模板圖形, 剖面圖模板:image-20230303202523238

圖簽模板:(其中單位和日期是塊屬性文字,支持插入的時候輸入屬性值進行修改)

image-20230303202615419

(2) 獲取要創建的繪圖資料,示例中對資料進行了模擬生成,

(3) 根據唯杰地圖https://vjmap.com/ SDK中提供創建CAD物體型別的方法創建相關物體, 唯杰地圖SDK支持的物體型別有DbLine直線、DbCurve曲線、Db2dPolyline二維折線、Db3dPolyline三維多段線、DbPolyline多段線、BlockReference塊參照、DbArc圓弧、DbCircle圓、DbEllipse橢圓、DbHatch填充、Text單行文本、DbMText多行文本、RasterImage柵格圖片、DbShape型物體、Spline樣條曲線、Wipeout遮罩物體、Dimension標注、Db2LineAngularDimension角度標注[兩條線]、Db3PointAngularDimension角度標注[三點]、DbAlignedDimension對齊標注、DbArcDimension圓弧標注、DbDiametricDimension直徑標注、DbOrdinateDimension坐標標注、DbRadialDimension半徑標注、DbRadialDimensionLarge半徑折線標注、DbRotatedDimension轉角標注、AcDbAttributeDefinition屬性注記、AcDbAttribute塊屬性、DbLayer圖層、DbTextStyle文字樣式、DbDimStyle標注樣式、DbLinetypeStyle線型樣式、DbBlock塊定義、DbDocument資料庫檔案,

如何減少代碼量可以用如下方法:

  • 技巧一:可以直接拷貝模板中的物體,對物體的屬性進行修改,這樣能少賦值引數,減少代碼量,

  • 技巧二:對于重復的物件,可以創建塊,變化的文字,以塊屬性文字定義,再重復創建塊參照,修改屬性文字,

(4) 把創建的資料生成一個JSON物件,呼叫唯杰地圖服務,后臺創建DWG圖形,

(5) 把后臺創建的DWG圖形資料以GeoJson資料或GIS瓦片的格式回傳給前端進行展示,對于圖不大的情況,可用GeoJson資料進行展示,如果圖大時,GeoJson資料量大,資料回傳慢,渲染也會受影響,這時建議用GIS柵格瓦片或矢量瓦片的時候進行繪制,

在線體驗地址

https://vjmap.com/demo/#/demo/map/comprehensive/03datatodwgmap

應用場景

能在前端通過JavaScript創建CAD格式的DWG圖形,極大的降低了資料生成CAD圖的門檻,具有很廣泛的應用場景,例如,在建筑和工程領域,DWG檔案是廣泛使用的標準檔案格式,如工程中常用的一些等值線圖、剖面圖、水位圖等;建筑、交通等不同行業中的相關圖紙都可以用這個來生成DWG圖形,偷個懶,讓目前很火的ChatGPT來總結下吧:

image-20230303213354454

全部實作代碼

// --資料自動生成CAD工程剖面圖--根據資料在前端創建生成CAD格式的工程剖面圖形
// 剖面圖模板來源地圖id和版本
let templateSectId = "template_sect";
let templateSecVersion = "v1";
// 圖框模板來源id和版本
const templateTkMapId = "template_tk";
const templateTkVersion = "v1";
// 注:以下所的有objectid來源方法為:
// 在唯杰云端管理平臺 https://vjmap.com/app/cloud 里面以記憶體方式打開模板圖,然后點擊相應物體,在屬性面板中獲取object值
// 或者以幾何渲染方式打開模板圖,點擊相應物體,在屬性面板中獲取object值,如果是塊物體(objectid中有多個_),取第一個_前面的字串
let svc = new vjmap.Service(env.serviceUrl, env.accessToken);
// 獲取模板資訊
let tplInfo;
// 獲取模板中的資訊
const getTemplateInfo = async (templateSectId, version) => {
    let features = await getTemplateData(templateSectId, version);
    // 獲取所有填充符號,先獲取 填充符號 圖層中的所有文字,文字上面的hatch就是填充符號
    let hatchInfos = features.filter(f => f.layername == "填充符號" && f.name == "AcDbMText").map(t => {
        let hatch = features.filter(f => f.layername == "填充符號" && f.name == "AcDbHatch").find(h =>
            // 填充垂直方向位于文字上方,并且距離不能超過文字高度兩倍,水平方向包含文字中心點水平方向
            h.envelop.min.y > t.envelop.max.y &&
            h.envelop.min.y - t.envelop.max.y < t.envelop.height() * 2 &&
            h.envelop.min.x <= t.envelop.center().x &&
            h.envelop.max.x >= t.envelop.center().x
        )
        if (!hatch) return;
        return {
            name: t.text,
            hatchObjectId: hatch.objectid
        }
    })
    // 獲取繪制開始的位置線
    let lineInfo = features.filter(f => f.layername == "線" && f.name == "AcDbLine");
    let startLine;
    if (lineInfo.length > 0) {
        startLine = {
            objectId: lineInfo[0].objectid,
            positon: [lineInfo[0].envelop.min.x, lineInfo[0].envelop.min.y]
        }
    }
    return {
        startLine,
        hatchInfos
    }
}
?
// 模擬資料
const mockData = https://www.cnblogs.com/vjmap/archive/2023/03/05/(hatchNames, minCount) => {
    // 對填充符號次序先隨機排序下,這樣每次生成次序就不一樣了
    hatchNames.sort(() => Math.random() - 0.5);
    let data = [];
    // 孔口個數
    let kongCount = vjmap.randInt(minCount, minCount * 2);
    for(let i = 0; i < kongCount; i++) {
        let item = {
            name:'孔' + (i + 1),
            x: 15 * (i + 1) + vjmap.randInt(0, 10) + 1000, // 孔口坐標x 生成亂數x
            y: vjmap.randInt(100, 105), // 孔口坐標y 生成亂數y
            stratums: [] // 分層資料
        }
        // 生成每層的資訊
        let stratumCount = vjmap.randInt(5, hatchNames.length - 1);
        let stratumAllThickness = 0;
        for(let k = 0; k < stratumCount; k++) {
            const thickness = vjmap.randInt(2, 6) // 隨機生成一個厚度
            item.stratums.push({
                hatch: hatchNames[k],
                thickness: thickness
            })
            stratumAllThickness += thickness;
        }
        item.stratumsThickness = stratumAllThickness; // 所有的厚度
        data.push(item);
    }
    return data;
}
// 創建剖面圖
const createSectDoc = async (sectData) => {
    // 獲取要繪制的資料
    let drawData = https://www.cnblogs.com/vjmap/archive/2023/03/05/sectData;
    // 獲取最大和最小值
    let minX = Math.min(...drawData.map(d => d.x));
    let maxX = Math.max(...drawData.map(d => d.x));
    let minY = Math.min(...drawData.map(d => d.y));
    let maxY = Math.max(...drawData.map(d => d.y + d.stratumsThickness));
    minY = Math.floor(minY / 10) * 10; // 往10取整,刻度以10為單位
    maxY = Math.ceil(maxY / 10) * 10 + 10; // 往10取整,刻度以10為單位,稍長點
    let posMaxX = maxX - minX + 20; //x繪制位置,相對距離從標尺偏移十個像素
    let posMinX = 10;//x繪制位置,相對距離從標尺偏移十個像素
?
    const startPoint = tplInfo.startLine.positon;
?
    let doc = new vjmap.DbDocument();
    // 資料來源
    doc.from = `${templateSectId}/${templateSecVersion}`;
?
    // 把來源圖的資料最后都清空,(這里的模板不需要清空,直接用了)
    // doc.isClearFromDb = true;
    let entitys = [];
?
    // 左邊刻度
    entitys.push(new vjmap.DbLine({
        objectid:"169A2",
        start: startPoint,
        end: [startPoint[0], startPoint[1] + (maxY - minY)]
    }))
    for(let y = minY; y < maxY; y += 10) {
        let pt = [startPoint[0], startPoint[1] + maxY - y];
        entitys.push(new vjmap.DbLine({
            start: pt,
            end: [pt[0] - 2, pt[1]]
        }))
        // 刻度值
?
        entitys.push(new vjmap.DbText({
            cloneObjectId: '168C8',
            position: [pt[0] - 1, pt[1] + 0.2],
            text: y + ''
        }))
    }
    // 右邊刻度
    entitys.push(new vjmap.DbLine({
        cloneObjectId: "169A2", // 不是修改了,是克隆左邊的刻度線
        start: [startPoint[0] + posMaxX, startPoint[1]],
        end: [startPoint[0] + posMaxX, startPoint[1] + (maxY - minY)]
    }))
    for(let y = minY; y < maxY; y += 10) {
        let pt = [startPoint[0], startPoint[1] + maxY - y];
        entitys.push(new vjmap.DbLine({
            start: [pt[0] + posMaxX , pt[1]],
            end: [pt[0]  + posMaxX + 2, pt[1]]
        }))
        // 刻度值
        entitys.push(new vjmap.DbText({
            cloneObjectId: '168C8',
            position: [pt[0] + posMaxX + 1, pt[1] + 0.2],
            text: y + ''
        }))
    }
?
    // 修改線坐標
    entitys.push(new vjmap.DbLine({
        cloneObjectId:  tplInfo.startLine.objectId,
        start: [startPoint[0], startPoint[1]],
        end: [startPoint[0] + posMaxX, startPoint[1]]
    }))
?
?
    // 演示下塊及屬性欄位的使用,這里用塊創建一個孔口名稱和x坐標,中間用橫線隔開
    const blockName = "nameAndx";
    let block = new vjmap.DbBlock();
    block.name = blockName;
    block.origin = [0, 0]
    block.entitys = [
        new vjmap.DbAttributeDefinition({
            position: [0, 0.2],
            contents: "名稱",
            tag: "NAME",
            colorIndex: 7, // 自動反色
            horizontalMode: vjmap.DbTextHorzMode.kTextCenter,
            verticalMode: vjmap.DbTextVertMode.kTextBottom, // kTextBottom,
            height: 0.5,
        }),
        new vjmap.DbLine({
            start: [-2, 0],
            end: [2, 0]
        }),
        new vjmap.DbAttributeDefinition({
            position: [0, -0.2],
            contents: "X坐標",
            tag: "POSX",
            colorIndex: 7, // 自動反色
            horizontalMode: vjmap.DbTextHorzMode.kTextCenter,
            verticalMode: vjmap.DbTextVertMode.kTextTop, // kTextBottom,
            height: 0.5,
        })
    ];
    doc.appendBlock(block);
    // 繪制每一個孔
    for(let i = 0; i < drawData.length; i++) {
        // 開始繪制的位置點
        let x = posMinX + drawData[i].x - minX;
        let y = startPoint[1] + maxY - drawData[i].y;
        // 名稱和x,用上面的塊創建塊參照
        let blockRef = new vjmap.DbBlockReference();
        blockRef.blockname = blockName;
        blockRef.position =  [x + 1.5,  y + 3];
        // 修改屬性定義值
        blockRef.attribute = {
            NAME: drawData[i].name,
            POSX: drawData[i].x
        }
        entitys.push(blockRef);
?
        // 一層一層繪制
        for(let k = 0; k < drawData[i].stratums.length; k++) {
            let y2 = y - drawData[i].stratums[k].thickness;
            let bounds = vjmap.GeoBounds.fromArray([x, y, x + 3, y2]);
            let points = bounds.toPointArray(); // 轉成點坐標格式
            // 閉合
            points.push(points[0]);
            // 填充
            entitys.push(new vjmap.DbHatch({
                cloneObjectId: drawData[i].stratums[k].hatch.hatchObjectId,
                points: points,
                patternScale: 1.5
            }))
            // 邊框
            entitys.push(new vjmap.Db2dPolyline({
                points: points
            }))
?
            // 繪制連接下一個孔的線
            if (i != drawData.length - 1) {
                const nextKongStratums = drawData[i + 1].stratums;
                let nextX = posMinX + drawData[i + 1].x - minX;
                let nextY = startPoint[1] + maxY - drawData[i + 1].y;
                if (k < nextKongStratums.length) {
                    for(let n = 0; n <= k; n++) {
                        nextY = nextY - drawData[i + 1].stratums[n].thickness;
                    }
                    entitys.push(new vjmap.DbLine({
                        start: [x + 3, y2],
                        end: [nextX, nextY]
                    }))
                }
                // 水平間距
                entitys.push(new vjmap.DbLine({
                    start: [x, startPoint[1]],
                    end: [x, startPoint[1] - 2]
                }))
                entitys.push(new vjmap.DbLine({
                    start: [nextX, startPoint[1]],
                    end: [nextX, startPoint[1] - 2]
                }))
                entitys.push(new vjmap.DbLine({
                    start: [x, startPoint[1] - 2],
                    end: [nextX, startPoint[1] - 2]
                }))
                // 間距值
                entitys.push(new vjmap.DbText({
                    cloneObjectId: '168C8',
                    position: [(x + nextX) / 2, startPoint[1] - 1],
                    text: nextX - x,
                    horizontalMode: vjmap.DbTextHorzMode.kTextCenter, // kTextCenter
                    verticalMode: vjmap.DbTextVertMode.kTextVertMid // kTextVertMid,
                }))
            }
            y = y2;
        }
        // 最下面寫上累計厚度值
        entitys.push(new vjmap.DbText({
            cloneObjectId: '168C8',
            position: [x + 1.5, y - 0.2],
            text: drawData[i].stratumsThickness,
            horizontalMode: vjmap.DbTextHorzMode.kTextCenter, // kTextCenter
            verticalMode: vjmap.DbTextVertMode.kTextTop // kTextTop,
        }))
?
?
    }
?
    entitys.push(new vjmap.DbText({
        objectid: '1687C',
        position: [(posMinX + posMaxX) / 2.0, startPoint[1] + maxY - minY + 10],
        /* 如果是相對位置,可以利用矩陣
        matrix: [
            {
                op: "translation",
                vector: [相對偏移x, 相對偏移y]
            }
        ],*/
        text: `剖面圖${Date.now()}`
    }))
?
    // 繪制圖框
    let bounds = vjmap.GeoBounds.fromArray([posMinX - 20, startPoint[1] + maxY - minY + 15, posMaxX + 10, startPoint[1] - 20]);
    let labelPos = [bounds.max.x, bounds.min.y];
    let points = bounds.toPointArray(); // 轉成點坐標格式
    // 閉合
    points.push(points[0]);
    // 邊框
    entitys.push(new vjmap.Db2dPolyline({
        points: points
    }))
    bounds = bounds.scale(1.02);
    points = bounds.toPointArray(); // 轉成點坐標格式
    // 閉合
    points.push(points[0]);
    // 邊框
    entitys.push(new vjmap.Db2dPolyline({
        points: points,
        lineWidth: 30 // mm
    }))
?
    let date = new Date();
    // 圖框從其他模板插入,并修改塊屬性文字
    entitys.push(new vjmap.DbBlockReference({
        cloneObjectId: '6A1',
        cloneFromDb: `${templateTkMapId}/${templateTkVersion}`,
        position: labelPos,
        attribute: {
            // 修改塊中的屬性欄位
            DATETIME: `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`,
            COMPANY: {
                text: "唯杰地圖VJMAP",
                color: 0x00FFFF
            }
        }
    }))
?
    entitys.push(new vjmap.DbLine({
        objectid: "168C8", // 這個模板文字不用了,直接洗掉了
        delete: true
    }))
    doc.entitys = entitys;
    return doc;
}
?
?
// 先得設定一個要圖形的所有范圍,這個范圍是隨便都沒有有關系的,最后匯出dwg時,會根據物體的所有坐標去自動計算真實的范圍,
let mapBounds = '[-10000,-10000,10000,10000]'
let mapExtent = vjmap.GeoBounds.fromString(mapBounds);
mapExtent = mapExtent.square(); // 要轉成正方形
?
svc.setCurrentMapParam({
    darkMode: true, // 由于沒有打開過圖,所以主動設定黑色模式
    bounds: mapExtent.toString()
})
// 建立坐標系
let prj = new vjmap.GeoProjection(mapExtent);
?
// 新建地圖物件
let map = new vjmap.Map({
    container: 'map', // container ID
    style: {
        version: svc.styleVersion(),
        glyphs: svc.glyphsUrl(),
        sources: {},
        layers: []
    },// 矢量瓦片樣式
    center: [0,0], // 中心點
    zoom: 2,
    renderWorldCopies: false
});
// 地圖關聯服務物件和坐標系
map.attach(svc, prj);
?
// 使地圖全部可見
map.fitMapBounds();
await map.onLoad();
?
?
// 創建一個幾何物件
const createGeomData = https://www.cnblogs.com/vjmap/archive/2023/03/05/async (map, doc) => {
    let svc = map.getService();
    let res = await svc.cmdCreateEntitiesGeomData({
        filedoc: doc.toDoc()
    });
    if (res.error) {
        message.error(res.error);
        return {
            type:"FeatureCollection",
            features: []
        };
    }
    if (res.metadata && res.metadata.mapBounds) {
        // 如果回傳的元資料里面有當前地圖的范圍,則更新當前地圖的坐標范圍
        map.updateMapExtent(res.metadata.mapBounds);
    }
?
    const features = [];
    if (res && res.result && res.result.length > 0) {
        for (let ent of res.result) {
            if (ent.geom && ent.geom.geometries) {
                let clr = map.entColorToHtmlColor(ent.color); // 物體顏色轉html顏色
                let featureAttr = {};
                // 因為要組合成一個組合物體,所以線和多邊形的顏色得區分
                if (ent.isPolygon) {
                    featureAttr.color = clr; // 填充色,只對多邊形有效
                    featureAttr.noneOutline = true; // 不顯示多邊形邊框,只對多邊形有效
                } else {
                    featureAttr.color = clr; // 顏色
                    featureAttr.line_width = ent.lineWidth; // 線寬
                }
                let ft = {
                    id: vjmap.RandomID(10),
                    type: "Feature",
                    properties: {
                        objectid: ent.objectid,
                        opacity: ent.alpha / 255,
                        ...featureAttr,
                    }
                }
                if (ent.geom.geometries.length == 1) {
                    features.push({
                        ...ft,
                        geometry: ent.geom.geometries[0],
                    });
                } else {
                    features.push({
                        ...ft,
                        geometry: {
                            geometries: ent.geom.geometries,
                            type: "GeometryCollection"
                        },
                    });
                }
?
            }
        }
    }
    return {
        type: "FeatureCollection",
        features: features,
    };
};
?
// 清空之前的地圖資料
const clearMapData = https://www.cnblogs.com/vjmap/archive/2023/03/05/() => {
    svc.setCurrentMapParam({
        darkMode: true, // 由于沒有打開過圖,所以主動設定黑色模式
        bounds: mapExtent.toString()
    })
    map.disableLayerClickHighlight();
    map.removeDrawLayer();
    let sources = map.getStyle().sources;
    for(let source in sources) {
        map.removeSourceEx(source);
    }
}
?
// 創建一個有資料的地圖
const createDataMap = async (doc) => {
    clearMapData();
    let geojson = await createGeomData(map, doc);
    const opts = vjmap.Draw.defaultOptions();
    // 修改默認樣式,把點的半徑改成1,沒有邊框,默認為5
    let pointIdx = opts.styles.findIndex(s => s.id ==="gl-draw-point-point-stroke-inactive");
    if (pointIdx >= 0) {
        opts.styles[pointIdx]['paint']['circle-radius'][3][3] = 0
    }
    pointIdx = opts.styles.findIndex(s => s.id === "gl-draw-point-inactive");
    if (pointIdx >= 0) {
        opts.styles[pointIdx]['paint']['circle-radius'][3][3] = 1
    }
    map.getDrawLayer(opts).set(geojson);
}
?
// 創建一個dwg的地圖
const createDwgMap = async (doc) => {
    // 先清空之前繪制的
    clearMapData();
    // js代碼
    let res = await svc.updateMap({
        // 獲取一個臨時的圖id(臨時圖形只會用臨時查看,過期會自動洗掉)
        mapid: vjmap.getTempMapId(1), // 臨時圖形不瀏覽情況下過期自動洗掉時間,單位分鐘,默認30
        filedoc: doc.toDoc(),
        mapopenway: vjmap.MapOpenWay.Memory,
        style: {
            backcolor: 0 // 如果div背景色是淺色,則設定為oxFFFFFF
        }
    })
    if (res.error) {
        message.error(res.error)
    }
    await map.switchMap(res);
}
?
?
let curDoc;
const exportDwgOpen = async () => {
    if (!curDoc) return;
    const mapid = 'exportdwgmap';
    let res = await svc.updateMap({
        mapid: mapid,
        filedoc: curDoc.toDoc(),
        mapopenway: vjmap.MapOpenWay.Memory,
        style: {
            backcolor: 0 // 如果div背景色是淺色,則設定為oxFFFFFF
        }
    })
    if (res.error) {
        message.error(res.error)
    } else{
        window.open(`https://vjmap.com/app/cloud/#/map/${res.mapid}?version=${res.version}&mapopenway=Memory&vector=false`)
    }
}
?
// 獲取模板的所有資料
const getTemplateData = https://www.cnblogs.com/vjmap/archive/2023/03/05/async (mapid, version) => {
    let res = await svc.rectQueryFeature({
        mapid,
        version,
        fields:"",
        geom: false, // 以記憶體方式打開,獲取真正的objectid
        maxGeomBytesSize: 0, // 不需要幾何坐標
        useCache: true, // 因為是以記憶體方式打開,后臺先把查詢的資料保存進快取,下次直接去快取查找,提高效率
        // x1,y1,x2,y2同時不輸的話,表示是查詢整個圖的范圍  這范圍不輸入,表示是全圖范圍
    })
    // 把物體的范圍字串轉成物件
    res.result.map(f => f.envelop = vjmap.GeoBounds.fromString(f.bounds));
    console.log(res.result)
    return res.result;
}
?
?
const creatSectDataMap = async () => {
    let sectData = https://www.cnblogs.com/vjmap/archive/2023/03/05/mockData(tplInfo.hatchInfos, 5);
    const doc = await createSectDoc(sectData);
    await createDataMap(doc);
    map.fitMapBounds();
    curDoc = doc;
}
const creatSectDwgMap = async () => {
    let sectData = mockData(tplInfo.hatchInfos, 15);
    const doc = await createSectDoc(sectData);
    await createDwgMap(doc);
    map.fitMapBounds();
    // 點擊有高亮狀態(滑鼠點擊地圖元素上時,會高亮)
    map.enableLayerClickHighlight(svc, e => {
        if (!e) return;
        let msg = {
            content: `type: ${e.name}, id: ${e.objectid}, layer: ${e.layerindex}`,
            key:"layerclick",
            duration: 5
        }
        e && message.info(msg);
    })
    curDoc = doc;
}
// 先獲取模板資訊
tplInfo = await getTemplateInfo(templateSectId, templateSecVersion);
// 隨機生成一個剖面圖
creatSectDataMap();
// UI界面
const App = () => {
    return (
        <div>
            <div className="info" style={{width: '430px'}}>
                <div className="input-item">
                    <button className="btn btn-full mr0" onClick={creatSectDataMap}>隨機生成一個剖面圖[前端直接繪制,適合于生成圖不大的情況]</button>
                    <button className="btn btn-full mr0" onClick={creatSectDwgMap}>隨機生成剖面圖[后臺生成DWG前端展示,適合于生成圖大的情況]</button>
                    <button className="btn btn-full mr0" onClick={exportDwgOpen}>匯出成DWG圖并打開</button>
                </div>
            </div>
        </div>
    );
}
ReactDOM.render(<App />, document.getElementById('ui'));
?
?
const mousePositionControl = new vjmap.MousePositionControl();
map.addControl(mousePositionControl, "bottom-left");

  


?
 

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/545886.html

標籤:其他

上一篇:可視化除錯某個js物件的屬性UI插件 class HTUI

下一篇:自己做一個ChatGPT微信小程式(代碼開源)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more